我正在使用R查询一长串PMID的PubMED。由于entrez_fetch一次只能执行一定数目,因此,我将2000个PMID分解为一个带有多个向量的列表(每个向量的长度约为500个)。当我查询PubMED时,我正在从每个出版物的XML文件中提取信息。我最后想要的是这样的:

    Original.PMID     Publication.type
    26956987          Journal.article
    26956987          Meta.analysis
    26956987          Multicenter.study
    26402000          Journal.article
    25404043          Journal.article
    25404043          Meta.analysis


每个出版物都有唯一的PMID,但每个PMID可能有几种出版物类型(如上所示)。我可以从XML文件中查询PMID编号,并且可以获得每个PMID的发布类型。我遇到的问题是重复PMID x次,以使每个PMID与它具有的每种发布类型相关联。如果我没有将数据包含在具有多个子列表的列表中(例如,如果我有14个批次,每个批次作为其自己的数据框),则可以通过从父PublicationType节点获取子节点的数量来执行此操作。但我似乎无法弄清楚如何在列表中执行此操作。

到目前为止,我的代码是这样的:

library(rvest)
library(tidyverse)
library(stringr)
library(regexr)
library(rentrez)
library(XML)

pubmed<-my.data.frame

into.batches<-function(x,n) split(x,cut(seq_along(x),n,labels=FALSE))
batches<-into.batches(pubmed.fwd$PMID, 14)
headings<-lapply(1:14, function(x) {paste0("Batch",x)})
names(batches)<-headings
fwd<-sapply(batches, function(x) entrez_fetch(db="pubmed", id=x, rettype="xml", parsed=TRUE))
trial1<-lapply(fwd, function(x)
  list(pub.type = xpathSApply(x, "//PublicationTypeList/PublicationType", xmlValue),
  or.pmid = xpathSApply(x, "//ArticleId[@IdType='pubmed']", xmlValue)))


trial1是我遇到的问题。这给出了一个列表,其中每个批处理中都有一个pub.type的向量和一个or.pmid的向量,但是它们的长度不同。

我试图找出每个出版物有多少个子出版物类型,所以我可以重复PMID多次。我当前正在使用下面的代码,该代码不执行我想要的操作:

trial1<-lapply(fwd, function(x)
  list(childnodes = xpathSApply(xmlRoot(x), "count(.//PublicationTypeList/PublicationType)", xmlChildren)))


不幸的是,这只是告诉我每批而不是每个出版物(或pmid)的子节点总数。

最佳答案

我将XML结果分成单独的Article节点,并应用xpath函数来获取pmid和pubtype。

pmids <- c(11677608, 22328765 ,11337471)
res <- entrez_fetch(db="pubmed", rettype="xml", id = pmids)
doc <- xmlParse(res)
x <-  getNodeSet(doc, "//PubmedArticle")
x1 <- sapply(x, xpathSApply, ".//ArticleId[@IdType='pubmed']", xmlValue)
x2 <- sapply(x, xpathSApply, ".//PublicationType", xmlValue)
data.frame( pmid= rep(x1, sapply(x2, length) ), pubtype = unlist(x2) )
      pmid                          pubtype
1 11677608                  Journal Article
2 11677608 Research Support, Non-U.S. Gov't
3 22328765                  Journal Article
4 22328765 Research Support, Non-U.S. Gov't
5 11337471                  Journal Article


另外,NCBI表示如果使用200个以上的UID,则使用HTTP POST方法。 rentrez不支持POSTing,但是您可以使用几行代码来运行它。

首先,您需要一个带有1000个Pubmed ID的载体(微生物基因组表中的6171)

library(readr)
x <- read_tsv( "ftp://ftp.ncbi.nih.gov/genomes/GENOME_REPORTS/prokaryotes.txt",
                na = "-", quote = "")
ids <- unique( x$`Pubmed ID` )
ids <- ids[ids < 1e9 & !is.na(ids)]


使用httr POST将ID发布到NCBI。

uri = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/epost.fcgi?"
response <- httr::POST(uri, body= list(id = paste(ids, collapse=","), db = "pubmed"))


按照entrez_post中的代码解析结果以获取网络历史记录。

 doc  <-   xmlParse( httr::content(response, as="text", encoding="UTF-8") )
 result <- xpathApply(doc, "/ePostResult/*", xmlValue)
 names(result) <- c("QueryKey", "WebEnv")
 class(result) <- c("web_history", "list")


最后,获取多达1万条记录(或者,如果有超过10K,则使用retstart选项循环遍历)

res <- entrez_fetch(db="pubmed", rettype="xml", web_history=result)
doc <- xmlParse(res)


这些只需一秒钟即可在我的笔记本电脑上运行。

articles <- getNodeSet(doc, "//PubmedArticle")
x1 <- sapply(articles, xpathSApply, ".//ArticleId[@IdType='pubmed']", xmlValue)
x2 <- sapply(articles, xpathSApply, ".//PublicationType", xmlValue)

data_frame( pmid= rep(x1, sapply(x2, length) ), pubtype = unlist(x2) )
# A tibble: 9,885 × 2
       pmid                                  pubtype
      <chr>                                    <chr>
 1 11677608                          Journal Article
 2 11677608         Research Support, Non-U.S. Gov't
 3 12950922                          Journal Article
 4 12950922         Research Support, Non-U.S. Gov't
 5 22328765                          Journal Article
 ...


最后一句话。如果每篇文章只需要一行,我通常会创建一个函数,将多个标签组合到一个定界列表中,并为缺失的节点添加NA。

xpath2 <-function(x, ...){
    y <- xpathSApply(x, ...)
    ifelse(length(y) == 0, NA,  paste(y, collapse="; "))
}

data_frame( pmid = sapply(articles, xpath2, ".//ArticleId[@IdType='pubmed']", xmlValue),
            journal = sapply(articles, xpath2, ".//Journal/Title", xmlValue),
           pubtypes = sapply(articles, xpath2, ".//PublicationType", xmlValue))

# A tibble: 6,172 × 3
      pmid                 journal                                          pubtypes
     <chr>                   <chr>                                             <chr>
1 11677608                  Nature Journal Article; Research Support, Non-U.S. Gov't
2 12950922  Molecular microbiology Journal Article; Research Support, Non-U.S. Gov't
3 22328765 Journal of bacteriology Journal Article; Research Support, Non-U.S. Gov't
4 11337471         Genome research                                   Journal Article
...

08-15 20:20