将数据从xml提取到数据框

时间:2016-07-25 21:49:59

标签: r xml dataframe

如果有人能告诉我如何从xml提取数据到R,我将非常感激。以下是我的xml文件中的1个化合物的示例,但真实文件包含数百个这样的化合物。 我知道有几个类似的问题发布但到目前为止我还没有能够开发出适合我要求的先前答案。例如,我可以使用

doc <- xmlParse("isotope information.xml")
xmlToDataFrame(
  getNodeSet(doc, "//isotope"),
  colClasses=c("character","numeric")
)

提取非常长的&#34; mz&#34;和&#34;丰富&#34;价值,但这些没有用,除非它们与相关化合物和样品等相关联。如果我尝试进一步推进树,这种方法似乎不起作用,我认为部分原因是由于不同类型的信息和/或名称中的空格?

任何帮助非常感谢。我是R的新手,在我开始使用此文件之前没有听说过xPath!

<?xml version="1.0" encoding="utf-8"?>
<compounds>
  <compound identifier="24.24_355.2087m/z" retentionTime="24.2409">
    <statistics>
      <anova>0.0013522641768629606</anova>
      <maxFoldChange>18.444703223432118</maxFoldChange>
      <mean lowest="Group A" highest="Group B" />
    </statistics>
    <condition name="Group A">
      <sample name="ACU_S1_D1_MSonly" normalizedAbundance="0.16176030585271">
        <adduct charge="2">
          <isotope>
            <mz>355.131459235488</mz>
            <abundance>0.115052197015018</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S4_D1_MSonly" normalizedAbundance="0.648153833258576">
        <adduct charge="2">
          <isotope>
            <mz>355.210174560547</mz>
            <abundance>0.45734640955925</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S7_D1_MSonly" normalizedAbundance="0">
        <adduct charge="2">
          <isotope>
            <mz>355.206065493636</mz>
            <abundance>0</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S9_D1_MSonly" normalizedAbundance="0">
        <adduct charge="2">
          <isotope>
            <mz>355.206065493636</mz>
            <abundance>0</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S10_D1_MSonly" normalizedAbundance="1.40543741447065">
        <adduct charge="2">
          <isotope>
            <mz>355.222929359468</mz>
            <abundance>0.998472798001696</abundance>
          </isotope>
          <isotope>
            <mz>355.785247802734</mz>
            <abundance>0.00450361325390688</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S11_D1_MSonly" normalizedAbundance="0">
        <adduct charge="2">
          <isotope>
            <mz>355.206065493636</mz>
            <abundance>0</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S14_D1_MSonly" normalizedAbundance="0">
        <adduct charge="2">
          <isotope>
            <mz>355.206065493636</mz>
            <abundance>0</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S17_D1_MSonly" normalizedAbundance="0">
        <adduct charge="2">
          <isotope>
            <mz>355.206065493636</mz>
            <abundance>0</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
    </condition>
    <condition name="Group B">
      <sample name="ACU_S2_D1_MSonly" normalizedAbundance="8.08281443709004">
        <adduct charge="2">
          <isotope>
            <mz>355.217085869147</mz>
            <abundance>6.34168970755279</abundance>
          </isotope>
          <isotope>
            <mz>355.720179758869</mz>
            <abundance>1.01208656740541</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S3_D1_MSonly" normalizedAbundance="1.74468788905785">
        <adduct charge="2">
          <isotope>
            <mz>355.236865028724</mz>
            <abundance>1.25719554540164</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S5_D1_MSonly" normalizedAbundance="1.20519908118674">
        <adduct charge="2">
          <isotope>
            <mz>355.221413778655</mz>
            <abundance>0.693123193025995</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S6_D1_MSonly" normalizedAbundance="11.8264838326202">
        <adduct charge="2">
          <isotope>
            <mz>355.208446325351</mz>
            <abundance>5.67846393951768</abundance>
          </isotope>
          <isotope>
            <mz>355.712529790798</mz>
            <abundance>0.718700468540192</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S12_D1_MSonly" normalizedAbundance="6.62039336582067">
        <adduct charge="2">
          <isotope>
            <mz>355.195225774627</mz>
            <abundance>4.80023810084345</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S13_D1_MSonly" normalizedAbundance="9.10340543014277">
        <adduct charge="2">
          <isotope>
            <mz>355.231293658837</mz>
            <abundance>8.75476514173928</abundance>
          </isotope>
          <isotope>
            <mz>355.73683673041</mz>
            <abundance>1.118534732035</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S15_D1_MSonly" normalizedAbundance="0">
        <adduct charge="2">
          <isotope>
            <mz>355.206065493636</mz>
            <abundance>0</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
      <sample name="ACU_S16_D1_MSonly" normalizedAbundance="2.27851790546988">
        <adduct charge="2">
          <isotope>
            <mz>355.242192813064</mz>
            <abundance>1.25391817825056</abundance>
          </isotope>
          <isotope>
            <mz>355.704849713088</mz>
            <abundance>0</abundance>
          </isotope>
        </adduct>
      </sample>
    </condition>
  </compound>

更新到原始帖子 嗨再次,非常感谢您使用XML和xml2的初步帮助我试图详细说明获得我需要的数据框的答案,但我仍然在努力,所以我要添加更多信息......

我已将xml文档的结构确定为:

# load necessary package(s)
library(XML)

# parse the xml file in to an R object call xmlfile
xmlfile = xmlTreeParse("QI isotope information.xml")


# check that the xmlfile object is recognised as an xml class
class(xmlfile) # the output should be: "XMLInternalDocument" "XMLAbstractDocument"

# find the root of the xml file
xmltop = xmlRoot(xmlfile)
class(xmltop) #  "XMLInternalElementNode" "XMLInternalNode"        "XMLAbstractNode"
xmlName(xmltop) # "compounds"
xmlSize(xmltop) # 4278

# the root of the xmlfile is "compounds" and it has 4278 children
# to view the content of the first child use:
xmltop[[1]]

# this contains all of the information from a unique compound identifier:
# <compound identifier="106.16_603.4571m/z" retentionTime="106.16268333333333">
#  <statistics>
#    <anova>1.1102230246251565E-16</anova>
#    <maxFoldChange>321.93091917042375</maxFoldChange>
#    <mean lowest="D9" highest="D1"/>
#  </statistics>
#  <condition name="D1">
#    <sample name="ACU_S1_D1_MSonly" normalizedAbundance="2016.23926856296">
#      <adduct charge="1">
#        <isotope>
#          <mz>603.509454467435</mz>
#          <abundance>1017.28655636311</abundance>
#        </isotope>
#        <isotope>
#          <mz>604.51484984744</mz>
#          <abundance>346.272257983685</abundance>
#        </isotope>
#        <isotope>
#          <mz>605.519216627667</mz>
#          <abundance>64.8701884746552</abundance>
#        </isotope>
#      </adduct>
#    </sample>
# N.B. this list is repeated for each sample name, in this case n=64 samples

xmlSize(xmltop[[1]]) # gives the number of nodes under the root, in this case n=5
xmlSApply(xmltop[[1]], xmlName) # gives the names of these 5 nodes
#  statistics    condition    condition    condition    condition 
# "statistics"  "condition"  "condition"  "condition"  "condition" 
xmlSApply(xmltop[[1]], as.list)

xmltop[[1]][[1]] # takes you to the statistics output:
# <statistics>
#  <anova>1.1102230246251565E-16</anova>
#   <maxFoldChange>321.93091917042375</maxFoldChange>
#   <mean lowest="D9" highest="D1"/>
# </statistics>

xmltop[[1]][[2]] # takes you to the "condition" level, i.e. condition name="D1"

xmltop[[1]][[2]][[1]] # takes you to the "sample" level, i.e. sample name="ACU_S1_D1_MSonly"

xmltop[[1]][[2]][[2]] # takes you to the "sample" level number 2, i.e. sample name="ACU_S2_D1_MSonly"

xmltop[[1]][[2]][[1]][[1]] # takes you to the "charge" level, i.e. adduct charge="1"

xmltop[[1]][[2]][[1]][[1]][[1]] # takes you to the "isotope" level, which includes m/z and abundance

# incrementing the last index number takes you to each isotope for that compound
# for example:

xmltop[[1]][[2]][[1]][[1]][[1]][[1]] # <mz>603.509454467435</mz> 
xmltop[[1]][[2]][[1]][[1]][[1]][[2]] # <abundance>1017.28655636311</abundance> 
xmltop[[1]][[2]][[1]][[1]][[2]][[1]] # <mz>604.51484984744</mz> 
xmltop[[1]][[2]][[1]][[1]][[2]][[2]] # <abundance>346.272257983685</abundance>
xmltop[[1]][[2]][[1]][[1]][[3]][[1]] # <mz>605.519216627667</mz>  
xmltop[[1]][[2]][[1]][[1]][[3]][[2]] # <abundance>64.8701884746552</abundance>
xmltop[[1]][[2]][[1]][[1]][[4]][[1]] # NULL
xmltop[[1]][[2]][[1]][[1]][[4]][[2]] # NULL

我对统计部分不感兴趣,但我想创建一个数据框,其中str输出类似于:

# > str(mydata) # returns a summary of the type/ format of each column
# 'data.frame': n obs. of  n variables:
# $ compound : Factor w/ n levels 
# $ retention_time :
# $ condition : Factor w/ 4 levels "D1","D3","D6","D9":
# $ sample_name  : Factor w/ 16 levels "ACU_S1_D1","ACU_S2_D1...: 
# $ isotope_mz : num
# $ isotope_abundance : num  

我的最终目标是能够为64个样本中的每一个提取每个isotope_mz的丰度。事实上,了解条件并不重要,因为这可以从sample_name确定。

N.B。我使用的xml文件是150 mb,有> 4000个化合物x 64个样本,每个化合物有1到4个同位素,我需要mz和丰度。除了&#39; R&#39;这里要求的方法我也搜索并尝试了许多xml转换器,但没有一个能够破译这个xml文件的结构。

2 个答案:

答案 0 :(得分:1)

这样的事情应该有效:

library(XML)
library(data.table)

mylist <- xmlToList("isotope information.xml")
mylist <- c(mylist, mylist, mylist)

xtract <- function(x) {
  data.table(compound_id = mylist[x]$compound$.attrs["identifier"],
             sample_id = mylist[x]$compound$condition$sample$.attrs["name"],
             mz = mylist[x]$compound$condition$sample$adduct$isotope[1],
             abundance = mylist[x]$compound$condition$sample$adduct$isotope[2])
}

rbindlist(lapply(seq_along(mylist), xtract))
#          compound_id        sample_id               mz         abundance
# 1: 24.24_355.2087m/z ACU_S1_D1_MSonly 355.131459235488 0.115052197015018
# 2: 24.24_355.2087m/z ACU_S1_D1_MSonly 355.131459235488 0.115052197015018
# 3: 24.24_355.2087m/z ACU_S1_D1_MSonly 355.131459235488 0.115052197015018

答案 1 :(得分:0)

我个人更喜欢xml2所以这是一个使用它的答案。我确信它可以改进,但它会给你一个长度等于化合物数量的列表,列表的每个元素都是化合物标识符和mz和丰度列的data.frame。

library(xml2)
x = read_xml(conn) # given in question
#html_structure(x) # If you want to look at the structure

output = list()
# Initialize list and collect all compunds first
a = xml_attrs(xml_find_all(x, "//compound"))
# Iterate over compounds - I'm sure this could be done in an lapply...
for(i in 1:length(a)){
  y = xml_child(x, i)
  # Get the child to simplify the xpath to collect all in this one node
  # Add a new element to the output list
  output[[i]] = list(
    a[[1]][1], # Extract identifier (assumed you didn't want the retention time) and then a df of mz and abundance
    data.frame(mz = xml_double(xml_find_all(y, "//isotope/mz" )), abundance = xml_double(xml_find_all(x, "//isotope/abundance") ))
               )
}

输出:

> output
[[1]]
[[1]][[1]]
         identifier 
"24.24_355.2087m/z" 

[[1]][[2]]
         mz   abundance
1  355.1315 0.115052197
2  355.7048 0.000000000
...
31 355.2422 1.253918178
32 355.7048 0.000000000