Python Pandas read_xml()方法测试策略

Python Pandas read_xml()方法测试策略,python,xml,pandas,xslt,xpath,Python,Xml,Pandas,Xslt,Xpath,目前,未维护read\u xml()方法和\u xml()的对应。但是,可以为数据帧导入和标记格式实现树状结构 如果熊猫团队在未来的熊猫版本中考虑这样的 Read XML方法,它们将采用什么样的实现:用内置的 XML?ETRE。EeltEnguts >其迭代()/或迭代PARSER()/函数或第三方模块,lxml及其XPath1.0和XSLT1.0方法 下面是我在一个简单、简单、以元素为中心的XML输入上对四种方法类型的测试运行。所有这些都是为根的任何第二级子级的通用解析而设置的,并且每个方法都

目前,未维护
read\u xml()
方法和\u xml()的对应
。但是,可以为数据帧导入和标记格式实现树状结构

如果熊猫团队在未来的熊猫版本中考虑这样的<代码> Read XML<代码>方法,它们将采用什么样的实现:用内置的<代码> XML?ETRE。EeltEnguts<代码> >其<代码>迭代()/<代码>或<代码>迭代PARSER()/<代码>函数或第三方模块,

lxml
及其XPath1.0和XSLT1.0方法

下面是我在一个简单、简单、以元素为中心的XML输入上对四种方法类型的测试运行。所有这些都是为根的任何第二级子级的通用解析而设置的,并且每个方法都应该产生完全相同的数据帧。字典列表中除最后一次调用之外的所有调用
pd.Dataframe()
。XSLT方法将XML转换为CSV,用于
pd.read\u CSV()
中的casted
StringIO()

问题(多部分)

  • 性能:如何解释在迭代解析文件时,对于较大的文件通常建议使用较慢的
    iterparse
    ?部分原因是否是由于
    if
    逻辑检查

  • 内存:CPU内存是否与I/O调用的计时相关?XSLT和XPath 1.0往往不能很好地扩展到更大的XML文档,因为整个文件必须在内存中读取才能解析

  • 策略:字典列表是
    Dataframe()
    调用的最佳策略吗?看看这些有趣的答案:版本和版本。两个向上广播列表都指向数据帧

输入数据(包括熊猫朋友在内的堆栈溢出的当前数据)

性能:您如何解释在迭代解析文件时,对于较大的文件,通常建议使用较慢的iterparse?部分原因是由于if逻辑检查吗

我假设更多的python代码会使它变慢,因为每次都会对python代码进行求值。你试过像pypy这样的JIT编译器吗

如果我删除
I
并仅使用
first_标记
,则速度似乎要快得多,因此是的,部分原因是If逻辑检查:

def read_xml_iterparse2(路径):
数据=[]
内部={}
第一个标签=无
对于et.iterparse(路径)中的(ev,el):
如果不是第一个标签:
第一个标签=el.tag
如果el.tag==第一个标签和透镜(内部)!=0:
data.append(内部)
内部={}
如果el.text不是None且len(el.text.strip())>0:
内部[el.tag]=el.text
df=pd.DataFrame(数据)
%timeit读取\u xml\u iterparse(路径)
#10个回路,最好为5:33 ms/回路
%timeit读取\u xml\u iterparse2(路径)
#10个回路,最好为5:23毫秒/回路
我不确定我是否理解上一个
if
检查的目的,但我也不确定为什么要丢失仅包含空格的元素。删除最后一个
if
始终会节省一点时间:

def read_xml_iterparse3(路径):
数据=[]
内部={}
第一个标签=无
对于et.iterparse(路径)中的(ev,el):
如果不是第一个标签:
第一个标签=el.tag
如果el.tag==第一个标签和透镜(内部)!=0:
data.append(内部)
内部={}
内部[el.tag]=el.text
df=pd.DataFrame(数据)
%timeit读取\u xml\u iterparse(路径)
#10个回路,最佳5个:每个回路34.4毫秒
%timeit读取\u xml\u iterparse2(路径)
#10个回路,最好为5个:每个回路24.5毫秒
%timeit读取\u xml\u iterparse3(路径)
#10个回路,最好为5个:每个回路20.9毫秒
现在,无论有没有这些性能改进,您的iterparse版本似乎都会产生一个超大的数据帧。这里似乎是一个工作,快速版本:

def read_xml_iterparse5(路径):
数据=[]
内部={}
对于et.iterparse(路径)中的(ev,el):
#/ending parents会触发一个新行,在本例中。文本后跟空格。将“topusers”作为.tag传递给我们的read_xml_iterparse5进行检查会更可靠
如果el.text和el.text[0]='\n':
#忽略/堆栈溢出
如果是内部的:
data.append(内部)
内部={}
其他:
内部[el.tag]=el.text
返回pd.DataFrame(数据)
打印(读取\u xml\u iterfind(path).shape)
# (900, 8)
打印(读取\u xml\u iterparse(路径).shape)
# (7050, 8)
打印(读取\u xml\u lxml\u xpath(path).shape)
# (900, 8)
打印(读取\u xml\u lxml\u xsl(path).shape)
# (900, 8)
打印(读取\u xml\u iterparse5(路径).shape)
# (900, 8)
%timeit read\u xml\u iterparse5(路径)
#10个回路,最好为5个:每个回路20.6毫秒
内存:CPU内存是否与I/O调用的计时相关?XSLT和XPath 1.0往往不能很好地扩展到更大的XML文档,因为整个文件必须在内存中读取才能解析

我不完全确定您所说的“I/O调用”是什么意思,但如果您的文档足够小,可以放入缓存,那么一切都会更快,因为它不会从缓存中逐出许多其他项

策略:字典列表是Dataframe()调用的最佳策略吗?看看这些有趣的答案:生成器版本和iterwalk用户定义版本。两个向上广播列表都指向数据帧


列表使用更少的内存,因此根据您拥有的列数,它可能会产生明显的差异。当然,这就要求XML标记的顺序保持一致,它们看起来确实如此。
DataFrame()
调用也需要做更少的工作,因为它不必在每一行上查找dict中的键,就可以找出哪个列的if值是什么值。

据我所知,github上也讨论了这一点。也许在那里有问题?谢谢你的回答。但是,您的答复似乎是针对Python的一般性答复,而不是针对Pandas提出的特定XML方法。也许一个特定的编码示例可以更好地说明JIT思想或Cython使用上述rep
<?xml version="1.0" encoding="utf-8"?>
<stackoverflow>
  <topusers>
    <user>Gordon Linoff</user>
    <link>http://www.stackoverflow.com//users/1144035/gordon-linoff</link>
    <location>New York, United States</location>
    <year_rep>5,985</year_rep>
    <total_rep>499,408</total_rep>
    <tag1>sql</tag1>
    <tag2>sql-server</tag2>
    <tag3>mysql</tag3>
  </topusers>
  <topusers>
    <user>Günter Zöchbauer</user>
    <link>http://www.stackoverflow.com//users/217408/g%c3%bcnter-z%c3%b6chbauer</link>
    <location>Linz, Austria</location>
    <year_rep>5,835</year_rep>
    <total_rep>154,439</total_rep>
    <tag1>angular2</tag1>
    <tag2>typescript</tag2>
    <tag3>javascript</tag3>
  </topusers>
  <topusers>
    <user>jezrael</user>
    <link>http://www.stackoverflow.com//users/2901002/jezrael</link>
    <location>Bratislava, Slovakia</location>
    <year_rep>5,740</year_rep>
    <total_rep>83,237</total_rep>
    <tag1>pandas</tag1>
    <tag2>python</tag2>
    <tag3>dataframe</tag3>
  </topusers>
  <topusers>
    <user>VonC</user>
    <link>http://www.stackoverflow.com//users/6309/vonc</link>
    <location>France</location>
    <year_rep>5,577</year_rep>
    <total_rep>651,397</total_rep>
    <tag1>git</tag1>
    <tag2>github</tag2>
    <tag3>docker</tag3>
  </topusers>
  <topusers>
    <user>Martijn Pieters</user>
    <link>http://www.stackoverflow.com//users/100297/martijn-pieters</link>
    <location>Cambridge, United Kingdom</location>
    <year_rep>5,337</year_rep>
    <total_rep>525,176</total_rep>
    <tag1>python</tag1>
    <tag2>python-3.x</tag2>
    <tag3>python-2.7</tag3>
  </topusers>
  <topusers>
    <user>T.J. Crowder</user>
    <link>http://www.stackoverflow.com//users/157247/t-j-crowder</link>
    <location>United Kingdom</location>
    <year_rep>5,258</year_rep>
    <total_rep>508,310</total_rep>
    <tag1>javascript</tag1>
    <tag2>jquery</tag2>
    <tag3>java</tag3>
  </topusers>
  <topusers>
    <user>akrun</user>
    <link>http://www.stackoverflow.com//users/3732271/akrun</link>
    <location></location>
    <year_rep>5,188</year_rep>
    <total_rep>229,553</total_rep>
    <tag1>r</tag1>
    <tag2>dplyr</tag2>
    <tag3>dataframe</tag3>
  </topusers>
  <topusers>
    <user>Wiktor Stribi?ew</user>
    <link>http://www.stackoverflow.com//users/3832970/wiktor-stribi%c5%bcew</link>
    <location>Warsaw, Poland</location>
    <year_rep>4,948</year_rep>
    <total_rep>158,134</total_rep>
    <tag1>regex</tag1>
    <tag2>javascript</tag2>
    <tag3>c#</tag3>
  </topusers>
  <topusers>
    <user>Darin Dimitrov</user>
    <link>http://www.stackoverflow.com//users/29407/darin-dimitrov</link>
    <location>Sofia, Bulgaria</location>
    <year_rep>4,936</year_rep>
    <total_rep>709,683</total_rep>
    <tag1>c#</tag1>
    <tag2>asp.net-mvc</tag2>
    <tag3>asp.net-mvc-3</tag3>
  </topusers>
  <topusers>
    <user>Eric Duminil</user>
    <link>http://www.stackoverflow.com//users/6419007/eric-duminil</link>
    <location></location>
    <year_rep>4,854</year_rep>
    <total_rep>12,557</total_rep>
    <tag1>ruby</tag1>
    <tag2>ruby-on-rails</tag2>
    <tag3>arrays</tag3>
  </topusers>
  <topusers>
    <user>alecxe</user>
    <link>http://www.stackoverflow.com//users/771848/alecxe</link>
    <location>New York, United States</location>
    <year_rep>4,723</year_rep>
    <total_rep>233,368</total_rep>
    <tag1>python</tag1>
    <tag2>selenium</tag2>
    <tag3>protractor</tag3>
  </topusers>
  <topusers>
    <user>Jean-François Fabre</user>
    <link>http://www.stackoverflow.com//users/6451573/jean-fran%c3%a7ois-fabre</link>
    <location>Toulouse, France</location>
    <year_rep>4,526</year_rep>
    <total_rep>30,027</total_rep>
    <tag1>python</tag1>
    <tag2>python-3.x</tag2>
    <tag3>python-2.7</tag3>
  </topusers>
  <topusers>
    <user>piRSquared</user>
    <link>http://www.stackoverflow.com//users/2336654/pirsquared</link>
    <location>Bellevue, WA, United States</location>
    <year_rep>4,482</year_rep>
    <total_rep>41,183</total_rep>
    <tag1>pandas</tag1>
    <tag2>python</tag2>
    <tag3>dataframe</tag3>
  </topusers>
  <topusers>
    <user>CommonsWare</user>
    <link>http://www.stackoverflow.com//users/115145/commonsware</link>
    <location>Who Wants to Know?</location>
    <year_rep>4,475</year_rep>
    <total_rep>616,135</total_rep>
    <tag1>android</tag1>
    <tag2>java</tag2>
    <tag3>android-intent</tag3>
  </topusers>
  <topusers>
    <user>Quentin</user>
    <link>http://www.stackoverflow.com//users/19068/quentin</link>
    <location>United Kingdom</location>
    <year_rep>4,464</year_rep>
    <total_rep>509,365</total_rep>
    <tag1>javascript</tag1>
    <tag2>html</tag2>
    <tag3>css</tag3>
  </topusers>
  <topusers>
    <user>Jon Skeet</user>
    <link>http://www.stackoverflow.com//users/22656/jon-skeet</link>
    <location>Reading, United Kingdom</location>
    <year_rep>4,348</year_rep>
    <total_rep>921,690</total_rep>
    <tag1>c#</tag1>
    <tag2>java</tag2>
    <tag3>.net</tag3>
  </topusers>
  <topusers>
    <user>Felix Kling</user>
    <link>http://www.stackoverflow.com//users/218196/felix-kling</link>
    <location>Sunnyvale, CA</location>
    <year_rep>4,324</year_rep>
    <total_rep>411,535</total_rep>
    <tag1>javascript</tag1>
    <tag2>jquery</tag2>
    <tag3>asynchronous</tag3>
  </topusers>
  <topusers>
    <user>matt</user>
    <link>http://www.stackoverflow.com//users/341994/matt</link>
    <location></location>
    <year_rep>4,313</year_rep>
    <total_rep>220,515</total_rep>
    <tag1>swift</tag1>
    <tag2>ios</tag2>
    <tag3>xcode</tag3>
  </topusers>
  <topusers>
    <user>Psidom</user>
    <link>http://www.stackoverflow.com//users/4983450/psidom</link>
    <location>Atlanta, GA, United States</location>
    <year_rep>4,236</year_rep>
    <total_rep>36,950</total_rep>
    <tag1>python</tag1>
    <tag2>pandas</tag2>
    <tag3>r</tag3>
  </topusers>
  <topusers>
    <user>Martin R</user>
    <link>http://www.stackoverflow.com//users/1187415/martin-r</link>
    <location>Germany</location>
    <year_rep>4,195</year_rep>
    <total_rep>269,380</total_rep>
    <tag1>swift</tag1>
    <tag2>ios</tag2>
    <tag3>swift3</tag3>
  </topusers>
  <topusers>
    <user>Barmar</user>
    <link>http://www.stackoverflow.com//users/1491895/barmar</link>
    <location>Arlington, MA</location>
    <year_rep>4,179</year_rep>
    <total_rep>289,989</total_rep>
    <tag1>javascript</tag1>
    <tag2>php</tag2>
    <tag3>jquery</tag3>
  </topusers>
  <topusers>
    <user>Alexey Mezenin</user>
    <link>http://www.stackoverflow.com//users/1227923/alexey-mezenin</link>
    <location>??????</location>
    <year_rep>4,142</year_rep>
    <total_rep>31,602</total_rep>
    <tag1>laravel</tag1>
    <tag2>php</tag2>
    <tag3>laravel-5.3</tag3>
  </topusers>
  <topusers>
    <user>BalusC</user>
    <link>http://www.stackoverflow.com//users/157882/balusc</link>
    <location>Amsterdam, Netherlands</location>
    <year_rep>4,046</year_rep>
    <total_rep>703,046</total_rep>
    <tag1>java</tag1>
    <tag2>jsf</tag2>
    <tag3>servlets</tag3>
  </topusers>
  <topusers>
    <user>GurV</user>
    <link>http://www.stackoverflow.com//users/6348498/gurv</link>
    <location></location>
    <year_rep>4,016</year_rep>
    <total_rep>7,932</total_rep>
    <tag1>sql</tag1>
    <tag2>mysql</tag2>
    <tag3>sql-server</tag3>
  </topusers>
  <topusers>
    <user>Nina Scholz</user>
    <link>http://www.stackoverflow.com//users/1447675/nina-scholz</link>
    <location>Berlin, Deutschland</location>
    <year_rep>3,950</year_rep>
    <total_rep>61,135</total_rep>
    <tag1>javascript</tag1>
    <tag2>arrays</tag2>
    <tag3>object</tag3>
  </topusers>
  <topusers>
    <user>JB Nizet</user>
    <link>http://www.stackoverflow.com//users/571407/jb-nizet</link>
    <location>Saint-Etienne, France</location>
    <year_rep>3,923</year_rep>
    <total_rep>418,780</total_rep>
    <tag1>java</tag1>
    <tag2>hibernate</tag2>
    <tag3>java-8</tag3>
  </topusers>
  <topusers>
    <user>Frank van Puffelen</user>
    <link>http://www.stackoverflow.com//users/209103/frank-van-puffelen</link>
    <location>San Francisco, CA</location>
    <year_rep>3,920</year_rep>
    <total_rep>86,520</total_rep>
    <tag1>firebase</tag1>
    <tag2>firebase-database</tag2>
    <tag3>android</tag3>
  </topusers>
  <topusers>
    <user>dasblinkenlight</user>
    <link>http://www.stackoverflow.com//users/335858/dasblinkenlight</link>
    <location>United States</location>
    <year_rep>3,886</year_rep>
    <total_rep>475,813</total_rep>
    <tag1>c#</tag1>
    <tag2>java</tag2>
    <tag3>c++</tag3>
  </topusers>
  <topusers>
    <user>Tim Biegeleisen</user>
    <link>http://www.stackoverflow.com//users/1863229/tim-biegeleisen</link>
    <location>Singapore</location>
    <year_rep>3,814</year_rep>
    <total_rep>77,211</total_rep>
    <tag1>sql</tag1>
    <tag2>mysql</tag2>
    <tag3>java</tag3>
  </topusers>
  <topusers>
    <user>Greg Hewgill</user>
    <link>http://www.stackoverflow.com//users/893/greg-hewgill</link>
    <location>Christchurch, New Zealand</location>
    <year_rep>3,796</year_rep>
    <total_rep>529,137</total_rep>
    <tag1>git</tag1>
    <tag2>python</tag2>
    <tag3>git-pull</tag3>
  </topusers>
  <topusers>
    <user>unutbu</user>
    <link>http://www.stackoverflow.com//users/190597/unutbu</link>
    <location></location>
    <year_rep>3,735</year_rep>
    <total_rep>401,595</total_rep>
    <tag1>python</tag1>
    <tag2>pandas</tag2>
    <tag3>numpy</tag3>
  </topusers>
  <topusers>
    <user>Hans Passant</user>
    <link>http://www.stackoverflow.com//users/17034/hans-passant</link>
    <location>Madison, WI</location>
    <year_rep>3,688</year_rep>
    <total_rep>672,118</total_rep>
    <tag1>c#</tag1>
    <tag2>.net</tag2>
    <tag3>winforms</tag3>
  </topusers>
  <topusers>
    <user>Jonathan Leffler</user>
    <link>http://www.stackoverflow.com//users/15168/jonathan-leffler</link>
    <location>California, USA</location>
    <year_rep>3,649</year_rep>
    <total_rep>455,157</total_rep>
    <tag1>c</tag1>
    <tag2>bash</tag2>
    <tag3>unix</tag3>
  </topusers>
  <topusers>
    <user>paxdiablo</user>
    <link>http://www.stackoverflow.com//users/14860/paxdiablo</link>
    <location></location>
    <year_rep>3,636</year_rep>
    <total_rep>507,043</total_rep>
    <tag1>c</tag1>
    <tag2>c++</tag2>
    <tag3>bash</tag3>
  </topusers>
  <topusers>
    <user>Pranav C Balan</user>
    <link>http://www.stackoverflow.com//users/3037257/pranav-c-balan</link>
    <location>Ramanthali, Kannur, Kerala, India</location>
    <year_rep>3,604</year_rep>
    <total_rep>64,476</total_rep>
    <tag1>javascript</tag1>
    <tag2>jquery</tag2>
    <tag3>html</tag3>
  </topusers>
  <topusers>
    <user>Suragch</user>
    <link>http://www.stackoverflow.com//users/3681880/suragch</link>
    <location>Hohhot, China</location>
    <year_rep>3,580</year_rep>
    <total_rep>71,032</total_rep>
    <tag1>swift</tag1>
    <tag2>ios</tag2>
    <tag3>android</tag3>
  </topusers>
</stackoverflow>
import xml.etree.ElementTree as et
import pandas as pd
from io import StringIO
from lxml import etree as lxet

def read_xml_iterfind():
    tree = et.parse('Input.xml')

    data = []
    inner = {}
    for el in tree.iterfind('./*'):
        for i in el.iterfind('*'):
            inner[i.tag] = i.text
        data.append(inner)
        inner = {}

    df = pd.DataFrame(data)

def read_xml_iterparse():
    data = []
    inner = {}
    i = 1
    for (ev, el) in et.iterparse(path):
        if i <= 2:
           first_tag = el.tag

        if el.tag == first_tag and len(inner) != 0:
            data.append(inner)            
            inner = {}

        if el.text is not None and len(el.text.strip()) > 0:
            inner[el.tag] = el.text
    i += 1

    df = pd.DataFrame(data)    

def read_xml_lxml_xpath():     
    tree = lxet.parse('Input.xml')

    data = []
    inner = {}
    for el in tree.xpath('/*/*'):
        for i in el:
            inner[i.tag] = i.text
        data.append(inner)
        inner = {}

    df = pd.DataFrame(data)

def read_xml_lxml_xsl():     
    xml = lxet.parse('Input.xml')

    xslstr = '''
    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:output version="1.0" encoding="UTF-8" indent="yes"  method="text"/>
        <xsl:strip-space elements="*"/>

        <!-- HEADERS -->
        <xsl:template match = "/*">
            <xsl:for-each select="*[1]/*">
              <xsl:value-of select="local-name()" />
                <xsl:choose>
                   <xsl:when test="position() != last()">
                      <xsl:text>,</xsl:text>
                   </xsl:when>
                   <xsl:otherwise>
                      <xsl:text>&#xa;</xsl:text>
                   </xsl:otherwise>                              
                </xsl:choose>   
            </xsl:for-each>
            <xsl:apply-templates/>
        </xsl:template>

        <!-- DATA ROWS (COMMA-SEPARATED) -->
        <xsl:template match="/*/*" priority="2">    
            <xsl:for-each select="*">
              <xsl:if test="position() = 1">
                   <xsl:text>&quot;</xsl:text>
              </xsl:if>
              <xsl:value-of select="." />
                <xsl:choose>
                   <xsl:when test="position() != last()">
                      <xsl:text>&quot;,&quot;</xsl:text>
                   </xsl:when>
                   <xsl:otherwise>
                      <xsl:text>&quot;&#xa;</xsl:text>
                   </xsl:otherwise>                              
                </xsl:choose>
            </xsl:for-each>
        </xsl:template>

    </xsl:transform>
    '''
    xsl = lxet.fromstring(xslstr)

    transform = lxet.XSLT(xsl)
    newdom = transform(xml)

    df = pd.read_csv(StringIO(str(newdom)))
# SHORTER FILE
python -mtimeit -s'import readxml_test_runs as test' 'test.read_xml_iterfind()'
100 loops, best of 3: 3.87 msec per loop

python -mtimeit -s'import readxml_test_runs as test' 'test.read_xml_iterparse()'
100 loops, best of 3: 5.5 msec per loop

python -mtimeit -s'import readxml_test_runs as test' 'test.read_xml_lxml_xpath()'
100 loops, best of 3: 3.86 msec per loop

python -mtimeit -s'import readxml_test_runs as test' 'test.read_xml_lxml_xsl()'
100 loops, best of 3: 5.68 msec per loop

# LARGER FILE
python -mtimeit -n'100' -s'import readxml_test_runs as test' 'test.read_xml_iterfind()'
100 loops, best of 3: 36 msec per loop

python -mtimeit -n'100' -s'import readxml_test_runs as test' 'test.read_xml_iterparse()'
100 loops, best of 3: 78.9 msec per loop

python -mtimeit -n'100' -s'import readxml_test_runs as test' 'test.read_xml_lxml_xpath()'
100 loops, best of 3: 32.7 msec per loop

python -mtimeit -n'100' -s'import readxml_test_runs as test' 'test.read_xml_lxml_xsl()'
100 loops, best of 3: 51.4 msec per loop