解析从XML到pandas的分层数据?

时间:2018-01-22 04:47:11

标签: python xml pandas

我继承了XML格式的数据,它具有多个嵌套的1:多关系。最低级别是我希望绘制的坐标数据(作为散点图和/或线)。我希望使用更高级别作为分组变量和格式。认识到效率低下,“扁平”数据组织对我来说是可以接受的。

XML的示例如下:

<?xml version="1.0"?>
-<Hilltop>
-<Section SiteName="1">
-<DataSource NumItems="1" Name="RL Section">
<DataType>RLOffsetSection</DataType>
<ItemFormat>0</ItemFormat>
</DataSource>
<SurveyTime> 1-Oct-1989 00:00:00</SurveyTime>
-<Data>
-<E><O>-687.500</O><I1>95.837</I1></E>
-<E><O>-680.100</O><I1>95.773</I1></E>
</Data>
</Section>

-<Section SiteName="1">
-<DataSource NumItems="1" Name="RL Section">
<DataType>RLOffsetSection</DataType>
<ItemFormat>0</ItemFormat>
</DataSource>
<SurveyTime>10-Feb-1993 12:00:00</SurveyTime>
-<Data>
-<E><O>0.000</O><I1>91.138</I1></E>
-<E><O>5.600</O><I1>91.206</I1></E>
-<E><O>11.900</O><I1>91.012</I1></E>
</Data>
</Section>

<Section SiteName="2">
<DataSource Name="RL Section" NumItems="1">
<DataType>RLOffsetSection</DataType><ItemFormat>0</ItemFormat>
</DataSource>
<SurveyTime> 1-Oct-1989 00:00:00</SurveyTime>
<Data>
<E><O>-99.100</O><I1>98.045</I1></E>
<E><O>-89.900</O><I1>98.334</I1></E>
<E><O>-85.900</O><I1>97.327</I1></E>
<E><O>-75.400</O><I1>94.177</I1></E>
<E><O>-53.100</O><I1>95.012</I1></E>
</Data>
</Section>

<Section SiteName="2">
<DataSource Name="RL Section" NumItems="1">
<DataType>RLOffsetSection</DataType><ItemFormat>0</ItemFormat>
</DataSource>
<SurveyTime>10-Feb-1993 12:00:00</SurveyTime>
<Data>
<E><O>0.000</O><I1>95.001</I1></E>
<E><O>4.600</O><I1>94.936</I1></E>
<E><O>14.800</O><I1>94.069</I1></E>
</Data>
</Section>
</Hilltop>

我已经改编了一些代码(借鉴了Gokhan Atil的博客)来解析大熊猫数据框:

def getvalueofnode(node):
    """ return node text or None """
    return node.text if node is not None else None

def main():
    """ main """
    parsed_xml = et.parse(###my path and file###)
    dfcols = ['Survey', 'XSnum', 'STA', 'Elev', 'CODE']
    df_xml = pd.DataFrame(columns=dfcols)

    for node in parsed_xml.getroot():
        Survey = node.attrib.get('SurveyTime')
        XSnum = node.attrib.get('Section SiteName')
        STA = node.find('O')
        ELEV = node.find('I1')
        CODE = node.find('Code')

        df_xml = df_xml.append(
            pd.Series([getvalueofnode(Survey), getvalueofnode(XSnum),
                       getvalueofnode(STA), getvalueofnode(ELEV), 
                       getvalueofnode(CODE)], index=dfcols),
            ignore_index=True)

    print(df_xml)

main()

它运行,我得到了我之后的数据帧结构,但我只得到'无'的单元格值,代码片段如下...... screen capture of present output df

我怀疑我在FOR循环中调用了错误的方法,但是已经耗尽了我(此时)有限的能力来排除代码。

以上述XML数据为例,我正在寻找以下数据: screen capture of desired output

非常感谢任何获得此分类的帮助。干杯!

##########编辑##########
好吧,我能够通过手动密集的解决方法将其关闭一段时间,但它无法扩展,所以我重新开始研究。

虽然我最终仍希望以df结束,但现在我正在逐步接近3D阵列(测量,测站,高程)。

我已重新分组,至少能够使用以下内容提取数据:

import xml.etree.ElementTree as ET
import numpy as np

path = "somepath"
file = "somefile.xml"

tree = ET.parse(path + file)
root = tree.getroot()

到目前为止,这么好。我可以获得每个离散调查的列表并转换为数组:

surveys =[]
for d in root.findall("./Section/SurveyTime"):
    date = d.text[:-9]
    surveys.append(date)
surv_arr = np.array(surveys)

下一位提取我想要最终在我的x轴上绘制的数值,但它是xml源中标记的所有值的运行列表(然后是数组)。

station = []
for s in root.findall("./Section/Data/E/O"):
    sta = float(s.text)
    station.append(sta)
sta_arr = np.array(station)

但我需要将每个调查的“sta”值分组在它们自己的数组中(例如,因此“sta_arr”是1 x n数组,其中n是调查数)。所以我尝试了一个嵌套的for循环:

station = []

for section in root.findall('./Section'):
    source_items = section.find('DataSource').attrib
    date = section.find('SurveyTime').text[:-9]
    for s in section.findall("./Section/Data/E/O"):
        sta = float(s.text)
        station.append(sta)

它产生n个数组,但它们是空的。因此,稍微调整代码以迭代日期变量(调查):

station = []

for section in root.findall('./Section'):
    source_items = section.find('DataSource').attrib
    date = section.find('SurveyTime').text[:-9]
    for d in date:
        sta = d.find('.Section/Data/E/O')
        station.append(sta)

好消息是填充了“站”不同长度的阵列阵列。虽然长度似乎在增加1.坏消息是所有值都是“-1”,并且每个调查的数组长度不等于xml文件中的观察数量(标记为'')。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

xmltodict是我所需要的。我能够使用有序词典方法对索引进行排序,这比我在使用etree和minidom时遇到的麻烦要快得多。

import xmltodict
import pandas as pd
xs, survey, station, elevation  = [], [], [], []
with open(path + file) as extract:
    orddict = xmltodict.parse(extract.read())
num_surveys = len(orddict['Hilltop']['Section'])
for i in range(0,num_surveys):
    XS_id = orddict['Hilltop']['Section'][i]['@SiteName']
    surv = orddict['Hilltop']['Section'][i]['SurveyTime'][:-9]
    sta_temp = []
    elev_temp = []
    data = orddict['Hilltop']['Section'][i]['Data']['E']
    for d in data:
        sta = float(d['O'])
        elev = float(d['I1'])
        sta_temp.append(sta)
        elev_temp.append(elev)
    xs.append(XS_id)
    survey.append(surv)
    station.append(sta_temp)
    elevation.append(elev_temp)
df = pd.DataFrame.from_dict({'xs':xs, 'survey':survey, 'station':station, 'elevation':elevation})

注意:结构化的DataFrame将坐标存储为列表,而不是像我最初的问题/请求中那样,存储在真正的“扁平”结构中。我的解决方案在保存一个分组级别的同时提供了我所需的绘图和分析性能,因此(对我而言)实际上是更可取的。

享受!!!

相关问题