【问题标题】:Extracting XML into data frame with parent attribute as column title将 XML 提取到以父属性为列标题的数据框中
【发布时间】:2013-06-04 05:00:32
【问题描述】:

我将处理数千个 XML 文件,它们具有相似的格式,但父级名称和父级数量不同。 通过书籍、谷歌、教程和尝试代码,我已经能够提取所有这些数据。例如:Parsing xml to pandas data frame throws memory errorDynamic search through xml attributes using lxml and xpath in python

但是,我意识到我提取的数据很糟糕,每个父母都重复了一个孩子“时间”。

这是我想要得到的。

Time   blah   abc
1200   100   2
1300   30    4
1400   70    2

这是我知道如何获得的。但我目前的方法很笨拙(我将在示例 XML 下方展示)

    child      Time   grandchild
0     blah     1200    100
1     blah     1300    30
...
n-2   abc      1200    2
n-1   abc      1300    4
n     abc      1400    2

示例 XML 格式

<outer>
   <inner>
      <parent name = "blah" id = "1"> 
         <child Time = "1200"> 
            <grandchild>100</grandchild>  
         </child>
         <child Time = "1300">
            <grandchild>30</grandchild>
         </child>
         <child Time = "1400">
            <grandchild>70</grandchild>
         </child>
      </parent>
      <parent name = "abc" id = "2"> 
         <child Time = "1200">   
            <grandchild>2</grandchild> 
         </child>
         <child Time = "1300">
            <grandchild>4</grandchild>
         </child>
         <child Time = "1400">
            <grandchild>2</grandchild>
         </child>
      </parent>      
      <parent name = "1234" id = "7734"> 
         <other> 12 </other>
      </parent> 
   </inner>
</outer>

这是我如何获得我的输出:

from lxml import etree, objectify
from pandas import *
dTime=[]
dparent = []
dgrandchild=[]
for df in root.xpath('/*/*/*/parent/child'):
    dparent.append(df.getparent().attrib['name'])
    ## Iterate over attributes of time for specific parent
    for attrib in df.attrib:
    dTime.append(df.attrib[attrib])
        ## grandchild is a child of time, and iterate
        subfields = df.getchildren()
        for subfield in subfields:
         dgrandchild.append(subfield.text)
df=DataFrame({'Parent': dparent,'Time':dTime,'grandchild':dgrandchld})

我可以只获取这个输出并重新塑造它,但这似乎效率低下并且是一种非常笨拙的方法。

我想我需要一些味道:

#this does not work
data = []
for elem in root.xpath('/*/*/*/parent/child'):
   elem_data = {}
   for attrib in elem.attrib:
       elem_data['Time'] = elem.attrib[attrib])
   for child in elem.getchildren():
       elem_data[getparent().attrib['name'])] = child.text
       data.append(elem_data)
ndata = DataFrame(data)

【问题讨论】:

  • 你能发布一些 valid xml 以便人们可以复制和粘贴吗?
  • 捕捉@cpcloud。我试图简化它并省略了属性上的引号。我已经编辑过了。谢谢。
  • 您的代码中有一些缩进问题...

标签: python pandas lxml


【解决方案1】:

我建议先解析为 DataFrame,类似于您已经采用的方式(请参阅下文了解我的实现),然后根据您的要求对其进行调整。

那么你正在寻找pivot

In [11]: df
Out[11]:
  child  Time  grandchild
0  blah  1200         100
1  blah  1300          30
2   abc  1200           2
3   abc  1300           4
4   abc  1400           2

In [12]: df.pivot('Time', 'child', 'grandchild')
Out[12]:
child  abc  blah
Time
1200     2   100
1300     4    30
1400     2   NaN

我建议先parse from a file,然后把你想要的东西取出到一个元组列表中:

from lxml import etree
root = etree.parse(file_name)

parents = root.getchildren()[0].getchildren()

In [21]: elems = [(p.attrib['name'], int(c.attrib['Time']), int(gc.text))
                      for p in parents
                      for c in p
                      for gc in c]

In [22]: elems
Out[22]:
[('blah', 1200, 100),
 ('blah', 1300, 30),
 ('blah', 1400, 70),
 ('abc', 1200, 2),
 ('abc', 1300, 4),
 ('abc', 1400, 2)]

对于多个文件,您可以将其添加到更长的列表理解中。 除非你有大量的 xml,否则应该不会太慢(这里 files 是 xml 的列表)......

elems = [(p.attrib['name'], int(c.attrib['Time']), int(gc.text))
            for f in files
            for p in etree.parse(f).getchildren()[0].getchildren()
            for c in p
            for gc in c]

把它们放在一个DataFrame中:

In [23]: pd.DataFrame(elems, columns=['child', 'Time', 'grandchild'])
Out[23]:
  child  Time grandchild
0  blah  1200        100
1  blah  1300         30
2  blah  1400         70
3   abc  1200          2
4   abc  1300          4
5   abc  1400          2

然后做枢轴。 :)

【讨论】:

  • 这行得通,@Andy Hayden。如果我无法获得任何关于如何以这种方式提取它的好主意,这就是我将要使用的方法。似乎它不干净,并且与 python 方法保持一致,以一种方式提取数据,然后对其进行处理以重塑,你知道吗?
  • 好吧,你可以试试聪明点,但通常将它读入 DataFrame “whatever”然后重塑会更快(也更理智)。 Atm 将您的数据放入 DataFrame 看起来很慢(for循环和追加)。
  • 酷。我以为我这样做太笨拙了。我很欣赏你的建议,即重塑还不错。那我就去吧!谢谢
  • 谢谢@Andy Hayden!我实现了它。如果我确实想到了一种更清洁的方法(一旦我有更多经验),我会在这里发布。
  • @Jessi 实际上,您可以对大量文件使用更大的列表理解。我认为它很整洁:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多