2016-12-09 5 views
1

スタッカーの手助けをして、Webページを解析してデータフレームとして保存できました。複数のXMLファイルに対して同じ操作を繰り返し、リストをrbindしたいと思います。ここに私が試したし、正常にやったことです:私は、複数のXMLファイルの同じことを行うための関数を適用しようとすると、コードの上データフレーム内のベクトルとrbindに基づいて複数のXMLファイルを解析します

library(XML)  
xml.url <- "http://www.ebi.ac.uk/ena/data/view/ERS445758&display=xml" 
doc <- xmlParse(xml.url) 
x <- xmlToDataFrame(getNodeSet(doc,"//SAMPLE_ATTRIBUTE")) 
x$UNITS <- NULL 
x_t <- t(x) 
x_t <- as.data.frame(x_t) 
names(x_t) <- as.matrix(x_t[1, ]) 
x_t <- x_t[-1, ] 
x_t[] <- lapply(x_t, function(x) type.convert(as.character(x))) 

は今、うまく機能:

ERS_ID <- c("ERS445758","ERS445759", "ERS445760", "ERS445761", "ERS445762") 

xml_url_test = as.vector(sprintf("http://www.ebi.ac.uk/ena/data/view/ERS445758&display=xml", 
       ERS_ID)) 

XML_parser <- function(XML_url){ 
doc <- xmlParse(XML_url) 
x <- xmlToDataFrame(getNodeSet(doc,"//SAMPLE_ATTRIBUTE")) 
x$UNITS <- NULL 
x_t <- t(x) 
x_t <- as.data.frame(x_t) 
names(x_t) <- as.matrix(x_t[1, ]) 
x_t <- x_t[-1, ] 
x_t[] <- lapply(x_t, function(x) type.convert(as.character(x))) 
return(x_t) 
} 

major_test <- sapply(xml_url_test, XML_parser) 

それは動作しますが、提供します私は単一のXMLファイルのために生成した正しいデータフレーム形式ではない長いリストを私に返します。 は最後に、私はまた、機能的にx_t$ERSid <- ERS_IDようERS_IDベクトル 何かからERS番号を持って、最終的なデータフレームに列を追加したいと思います

誰かが私が任意のより良いと同様の機能で行方不明です何を指摘することができますタスクを実行する方法は?

ありがとうございます!あなたはこのような何かを行うことができますxml2tidyverseを使用して

答えて

3

後者は、リストとベクトルや行列に簡素化する以前の試みを返す場所をあなたの主な問題はlapply()sapplyを使用している:私は次のようには見えreadr::type_convert(out)

を使用することをお勧めしカラムの型を解析するために、ここでは行列です。もちろん

major_test <- lapply(xml_url_test, XML_parser) 

sapplylapplyのラッパーであり、また、リストを返すことができます。sapply(..., simplify=FALSE)

major_test <- sapply(xml_url_test, XML_parser, simplify=FALSE) 

しかし、他のいくつかの項目が思い付いた:

  1. 初めには、 ERS_IDをsprintfの%sオペレータでURLステムに連結していません。だから今、同じURLが繰り返されています。
  2. 最後に、データフレームのリストをコンパイルされた最終の単一データフレームにバインドしません。
  3. ERS_IDベクターにを渡して、新しいERS列を定義した関数内に追加します。列を作成するときには、接頭辞ERS ​​の接頭辞をgsubで削除します。

Rあなたは、URLのベクター又はmapとXMLファイルのリスト、またはネストされた要素内を反復処理できるよう

XML_parser <- function(eid) { 
    XML_url <- as.vector(sprintf("http://www.ebi.ac.uk/ena/data/view/%s&display=xml", eid)) 
    doc <- xmlParse(XML_url) 
    x <- xmlToDataFrame(getNodeSet(doc,"//SAMPLE_ATTRIBUTE")) 
    x$UNITS <- NULL 
    x_t <- t(x) 
    x_t <- as.data.frame(x_t) 
    names(x_t) <- as.matrix(x_t[1, ]) 
    x_t <- x_t[-1, ] 
    x_t[] <- lapply(x_t, function(x) type.convert(as.character(x))) 
    x_t$ERSid <- gsub("ERS", "", eid)   # ADD COL, REMOVE ERS 
    x_t <- x_t[,c(ncol(x_t),2:ncol(x_t)-1)] # MOVE NEW COL TO FIRST 
    return(x_t) 
} 

major_test <- lapply(ERS_ID, XML_parser) 
# major_test <- sapply(ERS_ID, XML_parser, simplify=FALSE) 

# BIND DATA FRAMES TOGETHER 
finaldf <- do.call(rbind, major_test) 
# RESET ROW NAMES 
row.names(finaldf) <- seq(nrow(finaldf)) 
1

あなたの2x36のdata.frameを与える
require(xml2) 
require(purrr) 
require(tidyr) 
urls <- rep("http://www.ebi.ac.uk/ena/data/view/ERS445758&display=xml", 2) 
identifier <- LETTERS[seq_along(urls)] # Take a unique identifier per url here 

parse_attribute <- function(x){ 
    out <- data.frame(tag = xml_text(xml_find_all(x, "./TAG")), 
      value = xml_text(xml_find_all(x, "./VALUE")), stringsAsFactors = FALSE) 
    spread(out, tag, value) 
} 

doc <- map(urls, read_xml) 

out <- doc %>% 
    map(xml_find_all, "//SAMPLE_ATTRIBUTE") %>% 
    set_names(identifier) %>% 
    map_df(parse_attribute, .id="url") 

url age body product  body site body-mass index      chimera check collection date 
1 A 28  mucosa Sigmoid colon  16.95502 ChimeraSlayer; Usearch 4.1 database  2009-03-16 
2 B 28  mucosa Sigmoid colon  16.95502 ChimeraSlayer; Usearch 4.1 database  2009-03-16 
    disease status ENA-BASE-COUNT ENA-CHECKLIST ENA-FIRST-PUBLIC ENA-LAST-UPDATE ENA-SPOT-COUNT 
1  remission   627051  ERC000015  2014-12-31  2016-10-21   1668 
2  remission   627051  ERC000015  2014-12-31  2016-10-21   1668 
      environment (biome)  environment (feature) environment (material) experimental factor 
1 organism-associated habitat organism-associated habitat     mucus   microbiome 
2 organism-associated habitat organism-associated habitat     mucus   microbiome 
    gastrointestinal tract disorder geographic location (country and/or sea,region) geographic location (latitude) 
1    Ulcerative Colitis           India      72.82807 
2    Ulcerative Colitis           India      72.82807 
    geographic location (longitude) host subject id human gut environmental package investigation type 
1      18.94084    1      human-gut   metagenome 
2      18.94084    1      human-gut   metagenome 
          medication multiplex identifiers pcr primers phenotype project name 
1 ASA;Steroids;Probiotics;Antibiotics   TGATACGTCT 27F-338R pathological   BMRP 
2 ASA;Steroids;Probiotics;Antibiotics   TGATACGTCT 27F-338R pathological   BMRP 
    sample collection device or method sequence quality check sequencing method sequencing template sex target gene 
1        biopsy    software pyrosequencing     DNA male 16S rRNA 
2        biopsy    software pyrosequencing     DNA male 16S rRNA 
    target subfragment 
1    V1V2 
2    V1V2 
+0

こんにちは、お返事ありがとうございます!私はまだ整頓に慣れています あなたのコードを試しました、それは動作します!元の 'ERS445758' idを、対応する解析されたメタデータの列変数としてどのように追加するかを知りたかっただけです。基本的にERS列を追加して 'ERS445758'を追加してください。すべてのERS idのためにSon onなど。 –

+0

'set_names'が出現するThats。あなたはあなたの 'urls'に対応する識別子を表す' identifier'を設定します。列名は 'map_df(...、.id =" myname ")'で定義されます。したがって、上記のコードでは、識別子列 'url'に名前をつけ、例として' A'と 'B'を使用しました:' identifier < - LETTERS [seq_along(urls)] – Rentrop

1

purrrは、ここでは本当に便利です(調整)コードat_depthとし、*_dfの形式とflattenの形式で結果を単純化します。

library(tidyverse) 
library(xml2) 

# be kind, don't call this more times than you need to 
x <- c("ERS445758","ERS445759", "ERS445760", "ERS445761", "ERS445762") %>% 
    sprintf("http://www.ebi.ac.uk/ena/data/view/%s&display=xml", .) %>% 
    map(read_xml) # read each URL into a list item 

df <- x %>% map(xml_find_all, '//SAMPLE_ATTRIBUTE') %>%  # for each item select nodes 
    at_depth(2, as_list) %>%  # convert each (nested) attribute to list 
    map_df(map_df, flatten) # flatten items, collect pages to df, then all to one df 

df 
## # A tibble: 175 × 3 
##      TAG        VALUE UNITS 
##      <chr>        <chr> <chr> 
## 1  investigation type       metagenome <NA> 
## 2   project name        BMRP <NA> 
## 3  experimental factor       microbiome <NA> 
## 4    target gene       16S rRNA <NA> 
## 5  target subfragment        V1V2 <NA> 
## 6    pcr primers       27F-338R <NA> 
## 7 multiplex identifiers       TGATACGTCT <NA> 
## 8  sequencing method      pyrosequencing <NA> 
## 9 sequence quality check       software <NA> 
## 10   chimera check ChimeraSlayer; Usearch 4.1 database <NA> 
## # ... with 165 more rows 
+0

Wow、それは素晴らしい解決策です。私は 'as_list 'について知らなかった。これは私のソリューションよりはるかにエレガントです。 – Rentrop

0

することはできERS445758-ERS445762のようなカンマ区切りのリストまたは範囲を使用し、ENAに複数のクエリを避けるため、単一のRESTのURLとretrieve multiple IDs

このコードは、5つのサンプルすべてをノードセットに取得し、xpath文字列の先頭のドットを使用して関数をそのノードに相対的に適用します。

ERS_ID <- c("ERS445758","ERS445759", "ERS445760", "ERS445761", "ERS445762") 
url <- paste0("http://www.ebi.ac.uk/ena/data/view/", paste(ERS_ID, collapse=","), "&display=xml") 
doc <- xmlParse(url) 
samples <- getNodeSet(doc, "//SAMPLE") 
## check the first node 
samples[[1]] 
## get the sample attribute node set and apply xmlToDataFrame to that 
x <- lapply(lapply(samples, getNodeSet, ".//SAMPLE_ATTRIBUTE"), xmlToDataFrame) 
# labels for bind_rows 
names(x) <- sapply(samples, xpathSApply, ".//PRIMARY_ID", xmlValue) 
library(dplyr) 
y <- bind_rows(x, .id="sample") 

z <- subset(y, TAG %in% c("age","sex","body site","body-mass index") , 1:3) 
     sample    TAG   VALUE 
15 ERS445758    age   28 
16 ERS445758    sex   male 
17 ERS445758  body site Sigmoid colon 
19 ERS445758 body-mass index 16.9550173 
50 ERS445759    age   58 
51 ERS445759    sex   male 
... 

library(tidyr) 
z %>% spread(TAG, VALUE) 
    sample age  body site body-mass index sex 
1 ERS445758 28 Sigmoid colon  16.9550173 male 
2 ERS445759 58 Sigmoid colon  23.22543185 male 
3 ERS445760 26 Sigmoid colon  20.76124567 female 
4 ERS445761 30 Sigmoid colon    0 male 
5 ERS445762 36 Sigmoid colon    0 male 
関連する問題