Estratégias de teste do método pandas read_xml()

| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |

Atualmente, as ferramentas de E/S do pandas não mantêm um read_xml() e a contraparte to_xml(). No entanto, read_json prova que estruturas semelhantes a árvores podem ser implementadas para importação de dataframe e read_html para formatos de marcação.

Se a equipe do pandas considerar esse método read_xml para uma versão futura do pandas, qual implementação eles considerariam buscar: analisar com xml.etree.ElementTree embutida com suas funções iterfind() ou iterparse() ou o módulo de terceiros, lxml com seus métodos XPath 1.0 e XSLT 1.0?

Abaixo estão minhas execuções de teste para quatro tipos de métodos em uma entrada XML simples, simples e centrada em elementos. Todos são configurados para análise generalizada para qualquer filho de segundo nível da raiz e cada método deve produzir exatamente o mesmo dataframe de pandas. Todos, exceto o último, chamam pd.Dataframe() na lista de dicionários. O método XSLT transforma XML em CSV para StringIO() convertido em pd.read_csv().

Pergunta (multi-part)

  • PERFORMANCE: Como você explica o iterparse mais lento, geralmente recomendado para arquivos maiores, pois o arquivo é analisado iterativamente? Isso se deve em parte às verificações da lógica if?

  • MEMÓRIA: A memória da CPU se correlaciona com os tempos nas chamadas de E/S? XSLT e XPath 1.0 tendem a não escalar bem com documentos XML maiores, pois o arquivo inteiro deve ser lido na memória para ser analisado.

  • ESTRATÉGIA: A lista de dicionários é uma estratégia ideal para Dataframe() chamada? Veja estas respostas interessantes: gerador versão e uma versão iterwalk definida pelo usuário . Ambas as listas de upcast para dataframe.

Inserir Dados (Stack Overflow"s atuais principais usuários por ano dos quais nossos amigos pandas estão incluídos)

<? xml version="1.0" encoding="utf-8"?> <stackoverflow> <topusers> <user>Gordon Linoff</user> <link>http://www.stackoverflow.com//users /1144035/gordon-linoff</link> <local>Nova York, Estados Unidos</local> <ano_rep>5.985</ano_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, Áustria</location> <year_rep>5.835</year_rep> ; <total_rep>154,4 39</total_rep> <tag1>angular2</tag1> <tag2>texto datilografado</tag2> <tag3>javascript</tag3> </topusers> <topusers> <usuário>jezrael</usuário> <link>http://www.stackoverflow.com//users/2901002/jezrael</link> <localização>Bratislava, Eslováquia</local> <ano_rep>5.740</ano_rep> <total_rep>83.237</total_rep> <tag1>pandas</tag1> <tag2>python</tag2> <tag3>quadro de dados</tag3> </topusers> <topusers> <usuário>VonC</usuário> <link>http://www.stackoverflow.com//users/6309/vonc</link> <local>França</local> <ano_rep>5.577</ano_rep> <total_rep>651.397</total_rep> <tag1>git</tag1> <tag2>github</tag2> <tag3>janela de encaixe</tag3> </topusers> <topusers> <user>Martijn Pieters</user> <link>http://www.stackoverflow.com//users/100297/martijn-pieters</link> <local>Cambridge, Reino Unido</local> <ano_rep>5.337</ano_rep> <total_rep>525.176</total_rep> <tag1>python</tag1> <tag2>python-3.x</tag2> <tag3>python-2.7</tag3> </topusers> <topusers> <usuário>TJ Crowder</user> <link>http://www.stackoverflow.com//users/157247/tj-crowder</link> <local>Reino Unido</local> <ano_rep>5.258</ano_rep> <total_rep>508.310</total_rep> <tag1>javascript</tag1> <tag2>jquery</tag2> <tag3>java</tag3> </topusers> <topusers> <usuário>akrun</usuário> <link>http://www.stackoverflow.com//users/3732271/akrun</link> <local></local> <ano_rep>5.188</ano_rep> <total_rep>229.553</total_rep> <tag1>r</tag1> <tag2>dplyr</tag2> <tag3>quadro de dados</tag3> </topusers> <topusers> <user>Wiktor Stribi?ew</user> <link>http://www.stackoverflow.com//users/3832970/wiktor-stribi%c5%bcew</link> <location>Varsóvia, Polônia</location> <ano_rep>4.948</ano_rep> <total_rep>158.134</total_rep> <tag1>regex</tag1> <tag2>javascript</tag2> <tag3>c#</tag3> </topusers> <topusers> <usuário>Darin Dimitrov</usuário> <link>http://www.stackoverflow.com//users/29407/darin-dimitrov</link> <location>Sofia, Bulgária</location> <ano_rep>4.936</ano_rep> <total_rep>709.683</total_rep> <tag1>c#</tag1> <tag2>asp.net-mvc</tag2> <tag3>asp.net-mvc-3</tag3> </topusers> <topusers> <usuário>Eric Duminil</usuário> <link>http://www.stackoverflow.com//users/6419007/eric-duminil</link> <local></local> <ano_rep>4.854</ano_rep> <total_rep>12.557</total_rep> <tag1>rubi</tag1> <tag2>rubi-em-trilhos</tag2> <tag3>matrizes</tag3> </topusers> <topusers> <usuário>alecxe</usuário> <link>http://www.stackoverflow.com//users/771848/alecxe</link> <local>Nova York, Estados Unidos</local> <ano_rep>4.723</ano_rep> <total_rep>233.368</total_rep> <tag1>python</tag1> <tag2>selênio</tag2> <tag3>transferidor</tag3> </topusers> <topusers> <user>Jean-Fran√ßois Fabre</user> <link>http://www.stackoverflow.com//users/6451573/jean-fran%c3%a7ois-fabre</link> <localização>Toulouse, França</localização> <ano_rep>4.526</ano_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> <local>Bellevue, WA, Estados Unidos</local> <ano_rep>4.482</ano_rep> <total_rep>41.183</total_rep> <tag1>pandas</tag1> <tag2>python</tag2> <tag3>quadro de dados</tag3> </topusers> <topusers> <user>CommonsWare</user> <link>http://www.stackoverflow.com//users/115145/commonsware</link> <local>Quem quer saber?</local> <ano_rep>4.475</ano_rep> <total_rep>616.135</total_rep> <tag1>android</tag1> <tag2>java</tag2> <tag3>android-intent</tag3> </topusers> <topusers> <usuário>Quentin</usuário> <link>http://www.stackoverflow.com//users/19068/quentin</link> <local>Reino Unido</local> <ano_rep>4.464</ano_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, Reino Unido</location> <ano_rep>4.348</ano_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> <local>Sunnyvale, CA</local> <ano_rep>4.324</ano_rep> <total_rep>411.535</total_rep> <tag1>javascript</tag1> <tag2>jquery</tag2> <tag3>assíncrono</tag3> </topusers> <topusers> <usuário>matt</usuário> <link>http://www.stackoverflow.com//users/341994/matt</link> <local></local> <ano_rep>4.313</ano_rep> <total_rep>220.515</total_rep> <tag1>rápido</tag1> <tag2>ios</tag2> <tag3>xcode</tag3> </topusers> <topusers> <user>Psidom</user> <link>http://www.stackoverflow.com//users/4983450/psidom</link> <local>Atlanta, GA, Estados Unidos</local> <ano_rep>4.236</ano_rep> <total_rep>36.950</total_rep> <tag1>python</tag1> <tag2>pandas</tag2> <tag3>r</tag3> </topusers> <topusers> <usuário>Martin R</usuário> <link>http://www.stackoverflow.com//users/1187415/martin-r</link> <local>Alemanha</local> <ano_rep>4.195</ano_rep> <total_rep>269.380</total_rep> <tag1>rápido</tag1> <tag2>ios</tag2> <tag3>swift3</tag3> </topusers> <topusers> <usuário>Barmar</usuário> <link>http://www.stackoverflow.com//users/1491895/barmar</link> <localização>Arlington, MA</localização> <ano_rep>4.179</ano_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> <local>??????</local> <ano_rep>4.142</ano_rep> <total_rep>31.602</total_rep> <tag1>laravel</tag1> <tag2>php</tag2> <tag3>laravel-5.3</tag3> </topusers> <topusers> <usuário>BalusC</usuário> <link>http://www.stackoverflow.com//users/157882/balusc</link> <location>Amsterdam, Holanda</location> <ano_rep>4.046</ano_rep> <total_rep>703.046</total_rep> <tag1>java</tag1> <tag2>jsf</tag2> <tag3>servlets</tag3> </topusers> <topusers> <usuário>GurV</usuário> <link>http://www.stackoverflow.com//users/6348498/gurv</link> <local></local> <ano_rep>4.016</ano_rep> <total_rep>7.932</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>servidor sql</tag3> </topusers> <topusers> <usuário>Nina Scholz</usuário> <link>http://www.stackoverflow.com//users/1447675/nina-scholz</link> <localização>Berlim, Alemanha</localização> <ano_rep>3.950</ano_rep> <total_rep>61.135</total_rep> <tag1>javascript</tag1> <tag2>matrizes</tag2> <tag3>objeto</tag3> </topusers> <topusers> <usuário>JB Nizet</usuário> <link>http://www.stackoverflow.com//users/571407/jb-nizet</link> <localização>Saint-Etienne, França</localização> <ano_rep>3.923</ano_rep> <total_rep>418.780</total_rep> <tag1>java</tag1> <tag2>hibernar</tag2> <tag3>java-8</tag3> </topusers> <topusers> <user>Frank van Puffelen</user> <link>http://www.stackoverflow.com//users/209103/frank-van-puffelen</link> <local>São Francisco, CA</local> <ano_rep>3.920</ano_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> <local>Estados Unidos</local> <ano_rep>3.886</ano_rep> <total_rep>475.813</total_rep> <tag1>c#</tag1> <tag2>java</tag2> <tag3>c++</tag3> </topusers> <topusers> <usuário>Tim Biegeleisen</usuário> <link>http://www.stackoverflow.com//users/1863229/tim-biegeleisen</link> <local>Cingapura</local> <ano_rep>3.814</ano_rep> <total_rep>77.211</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>java</tag3> </topusers> <topusers> <usuário>Greg Hewgill</usuário> <link>http://www.stackoverflow.com//users/893/greg-hewgill</link> <local>Christchurch, Nova Zelândia</local> <ano_rep>3.796</ano_rep> <total_rep>529.137</total_rep> <tag1>git</tag1> <tag2>python</tag2> <tag3>git-pull</tag3> </topusers> <topusers> <usuário>unutbu</usuário> <link>http://www.stackoverflow.com//users/190597/unutbu</link> <local></local> <ano_rep>3.735</ano_rep> <total_rep>401.595</total_rep> <tag1>python</tag1> <tag2>pandas</tag2> <tag3>numpy</tag3> </topusers> <topusers> <usuário>Hans Passant</usuário> <link>http://www.stackoverflow.com//users/17034/hans-passant</link> <localização>Madison, WI</localização> <ano_rep>3.688</ano_rep> <total_rep>672.118</total_rep> <tag1>c#</tag1> <tag2>.net</tag2> <tag3>winforms</tag3> </topusers> <topusers> <usuário>Jonathan Leffler</usuário> <link>http://www.stackoverflow.com//users/15168/jonathan-leffler</link> <local>Califórnia, EUA</local> <ano_rep>3.649</ano_rep> <total_rep>455.157</total_rep> <tag1>c</tag1> <tag2>bash</tag2> <tag3>unix</tag3> </topusers> <topusers> <usuário>paxdiablo</usuário> <link>http://www.stackoverflow.com//users/14860/paxdiablo</link> <local></local> <ano_rep>3.636</ano_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> <localização>Ramanthali, Kannur, Kerala, Índia</localização> <ano_rep>3.604</ano_rep> <total_rep>64.476</total_rep> <tag1>javascript</tag1> <tag2>jquery</tag2> <tag3>html</tag3> </topusers> <topusers> <usuário>Suragch</usuário> <link>http://www.stackoverflow.com//users/3681880/suragch</link> <local>Hohhot, China</local> <ano_rep>3.580</ano_rep> <total_rep>71.032</total_rep> <tag1>rápido</tag1> <tag2>ios</tag2> <tag3>android</tag3> </topusers> </stackoverflow> 

Python Métodos

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 = [] internal = {} i = 1 for (ev , el) em et.iterparse(path): if i <= 2: first_tag = el.tag if el.tag == first_tag e len(inner) != 0: data.append(inner) inner = {} if el.text não é Nenhum e 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> <!-- LINHAS DE DADOS (SEPARADAS POR VÍRGULA) --> <xsl:template match="/*/*" priority="2"> <xsl:for-each select=" *"> <xsl:if test="position() = 1"> <xsl:text>&quot;</xsl:text> </xsl:if> <xsl:value- de select="." /> <xsl:choose> <xsl:when test="position() != last()"> <xsl:text>&quot;,& quot;</xsl:texto> </xsl:quando> <xsl:caso contrário> <xsl:texto>&quot;&#xa;</xsl:texto> </xsl:caso contrário> </xsl:escolha> </xsl:para-cada> </xsl:modelo> </xsl:transformar> """ xsl = lxet.fromstring(xslstr) transform = lxet.XSLT(xsl) newdom = transform(xml) df = pd.read_csv(StringIO(str(newdom))) 

Tempos (com XML atual e XML com 25 vezes os filhos (ou seja, 900 registros de usuário do StackOverflow)

# SHORTER FILE python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_iterfind()" 100 loops, melhor de 3: 3,87 ms por loop python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_iterparse()" 100 loops, melhor de 3 : 5,5 ms por loop python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_lxml_xpath()" 100 loops, melhor de 3: 3,86 ms por loop python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_lxml_xsl( )" 100 loops, melhor de 3: 5,68 ms por loop # LARGER FILE python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_iterfind()" 100 loops, melhor de 3: 36 ms por loop python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_i terparse()" 100 loops, melhor de 3: 78,9 ms por loop python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_lxml_xpath()" 100 loops, melhor de 3: 32,7 ms por loop python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_lxml_xsl()" 100 loops, melhor de 3: 51,4 ms por loop