Stratégies de test de la méthode Pandas read_xml()

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

Actuellement, les outils d'E/S pandas ne conservent pas de read_xml() et sa contrepartie to_xml(). Cependant, read_json prouve que des structures arborescentes peuvent être implémentées pour l'importation de dataframes et read_html pour les formats de balisage.

Si l'équipe pandas envisage une telle méthode read_xml pour une future version de pandas, quelle implémentation feraient-ils poursuivre : analyse avec xml.etree.ElementTree intégré avec ses fonctions iterfind() ou iterparse() ou le module tiers, lxml avec ses méthodes XPath 1.0 et XSLT 1.0 ?

Vous trouverez ci-dessous mes tests pour quatre types de méthodes sur une entrée XML simple, plate et centrée sur les éléments. Tous sont configurés pour une analyse généralisée pour tous les enfants de second niveau de la racine et chaque méthode doit produire exactement la même trame de données pandas. Tous sauf le dernier appelle pd.Dataframe() sur la liste des dictionnaires. La méthode XSLT transforme XML en CSV pour caster StringIO() dans pd.read_csv().

Question (multi-part)

  • PERFORMANCE : Comment expliquez-vous l'iterparse plus lent souvent recommandé pour les fichiers plus volumineux, car le fichier est analysé de manière itérative ? Est-ce en partie dû aux vérifications logiques if ?

  • MÉMOIRE : la mémoire du processeur est-elle en corrélation avec les délais dans les appels d'E/S ? XSLT et XPath 1.0 ont tendance à ne pas s'adapter aux documents XML plus volumineux, car le fichier entier doit être lu en mémoire pour être analysé.

  • STRATÉGIE : la liste des dictionnaires est-elle une stratégie optimale pour Dataframe() ? Voir ces réponses intéressantes : générateur version et une version iterwalk définie par l'utilisateur . Les deux listes upcast en dataframe.

Données d'entrée (Stack Overflow"s current meilleurs utilisateurs par année dont nos amis pandas sont inclus)

< ? 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, États-Unis</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, Autriche</location> <year_rep>5,835</year_rep> <total_rep>154,4 39</total_rep> <tag1>angular2</tag1> <tag2>dactylographie</tag2> <tag3>javascript</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>jezrael</utilisateur> <lien>http://www.stackoverflow.com//users/2901002/jezrael</link> <emplacement>Bratislava, Slovaquie</emplacement> <année_rep>5 740</année_rep> <total_rep>83 237</total_rep> <tag1>pandas</tag1> <tag2>python</tag2> <tag3>dataframe</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>VonC</utilisateur> <lien>http://www.stackoverflow.com//users/6309/vonc</link> <localisation>France</localisation> <année_rep>5 577</année_rep> <total_rep>651 397</total_rep> <tag1>git</tag1> <tag2>github</tag2> <tag3>menu fixe</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Martijn Pieters</utilisateur> <lien>http://www.stackoverflow.com//users/100297/martijn-pieters</link> <emplacement>Cambridge, Royaume-Uni</emplacement> <année_rep>5 337</année_rep> <total_rep>525 176</total_rep> <tag1>python</tag1> <tag2>python-3.x</tag2> <tag3>python-2.7</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>TJ Crowder</utilisateur> <lien>http://www.stackoverflow.com//users/157247/tj-crowder</link> <emplacement>Royaume-Uni</emplacement> <année_rep>5 258</année_rep> <total_rep>508 310</total_rep> <tag1>javascript</tag1> <tag2>jquery</tag2> <tag3>java</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>akrun</utilisateur> <lien>http://www.stackoverflow.com//users/3732271/akrun</link> <emplacement></emplacement> <année_rep>5 188</année_rep> <total_rep>229 553</total_rep> <tag1>r</tag1> <tag2>dplyr</tag2> <tag3>dataframe</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Wiktor Stribi?ew</utilisateur> <lien>http://www.stackoverflow.com//users/3832970/wiktor-stribi%c5%bcew</link> <emplacement>Varsovie, Pologne</emplacement> <année_rep>4 948</année_rep> <total_rep>158 134</total_rep> <tag1>regex</tag1> <tag2>javascript</tag2> <tag3>c#</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Darin Dimitrov</utilisateur> <lien>http://www.stackoverflow.com//users/29407/darin-dimitrov</link> <emplacement>Sofia, Bulgarie</emplacement> <année_rep>4 936</année_rep> <total_rep>709 683</total_rep> <tag1>c#</tag1> <tag2>asp.net-mvc</tag2> <tag3>asp.net-mvc-3</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Eric Duminil</utilisateur> <lien>http://www.stackoverflow.com//users/6419007/eric-duminil</link> <emplacement></emplacement> <année_rep>4 854</année_rep> <total_rep>12 557</total_rep> <tag1>rubis</tag1> <tag2>rubis sur rails</tag2> <tag3>tableaux</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>alecxe</utilisateur> <lien>http://www.stackoverflow.com//users/771848/alecxe</link> <lieu>New York, États-Unis</lieu> <année_rep>4 723</année_rep> <total_rep>233 368</total_rep> <tag1>python</tag1> <tag2>sélénium</tag2> <tag3>rapporteur</tag3> </topusers> <les meilleurs utilisateurs> <user>Jean-François Fabre</user> <lien>http://www.stackoverflow.com//users/6451573/jean-fran%c3%a7ois-fabre</lien> <lieu>Toulouse, France</lieu> <année_rep>4 526</année_rep> <total_rep>30 027</total_rep> <tag1>python</tag1> <tag2>python-3.x</tag2> <tag3>python-2.7</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>piRSquared</utilisateur> <lien>http://www.stackoverflow.com//users/2336654/pirsquared</link> <emplacement>Bellevue, WA, États-Unis</emplacement> <année_rep>4 482</année_rep> <total_rep>41 183</total_rep> <tag1>pandas</tag1> <tag2>python</tag2> <tag3>dataframe</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>CommonsWare</utilisateur> <lien>http://www.stackoverflow.com//users/115145/commonsware</link> <emplacement>Qui veut savoir ?</emplacement> <année_rep>4 475</année_rep> <total_rep>616 135</total_rep> <tag1>Android</tag1> <tag2>java</tag2> <tag3>intention Android</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Quentin</utilisateur> <lien>http://www.stackoverflow.com//users/19068/quentin</link> <emplacement>Royaume-Uni</emplacement> <année_rep>4 464</année_rep> <total_rep>509 365</total_rep> <tag1>javascript</tag1> <tag2>html</tag2> <tag3>css</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Jon Skeet</utilisateur> <lien>http://www.stackoverflow.com//users/22656/jon-skeet</link> <lieu>Reading, Royaume-Uni</lieu> <année_rep>4 348</année_rep> <total_rep>921 690</total_rep> <tag1>c#</tag1> <tag2>java</tag2> <tag3>.net</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Felix Kling</utilisateur> <lien>http://www.stackoverflow.com//users/218196/felix-kling</link> <emplacement>Sunnyvale, Californie</emplacement> <année_rep>4 324</année_rep> <total_rep>411 535</total_rep> <tag1>javascript</tag1> <tag2>jquery</tag2> <tag3>asynchrone</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>matt</utilisateur> <lien>http://www.stackoverflow.com//users/341994/matt</link> <emplacement></emplacement> <année_rep>4 313</année_rep> <total_rep>220 515</total_rep> <tag1>rapide</tag1> <tag2>ios</tag2> <tag3>xcode</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Psidom</utilisateur> <lien>http://www.stackoverflow.com//users/4983450/psidom</link> <emplacement>Atlanta, Géorgie, États-Unis</emplacement> <année_rep>4 236</année_rep> <total_rep>36 950</total_rep> <tag1>python</tag1> <tag2>pandas</tag2> <tag3>r</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Martin R</utilisateur> <lien>http://www.stackoverflow.com//users/1187415/martin-r</link> <emplacement>Allemagne</emplacement> <année_rep>4 195</année_rep> <total_rep>269 380</total_rep> <tag1>rapide</tag1> <tag2>ios</tag2> <tag3>swift3</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Barmar</utilisateur> <lien>http://www.stackoverflow.com//users/1491895/barmar</link> <emplacement>Arlington, MA</emplacement> <année_rep>4 179</année_rep> <total_rep>289 989</total_rep> <tag1>javascript</tag1> <tag2>php</tag2> <tag3>jquery</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Alexey Mezenin</utilisateur> <lien>http://www.stackoverflow.com//users/1227923/alexey-mezenin</link> <emplacement>??????</emplacement> <année_rep>4 142</année_rep> <total_rep>31 602</total_rep> <tag1>laravel</tag1> <tag2>php</tag2> <tag3>laravel-5.3</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>BalusC</utilisateur> <lien>http://www.stackoverflow.com//users/157882/balusc</link> <emplacement>Amsterdam, Pays-Bas</emplacement> <année_rep>4 046</année_rep> <total_rep>703 046</total_rep> <tag1>java</tag1> <tag2>jsf</tag2> <tag3>servlets</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>GurV</utilisateur> <lien>http://www.stackoverflow.com//users/6348498/gurv</link> <emplacement></emplacement> <année_rep>4 016</année_rep> <total_rep>7 932</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>serveur SQL</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Nina Scholz</utilisateur> <lien>http://www.stackoverflow.com//users/1447675/nina-scholz</link> <emplacement>Berlin, Allemagne</emplacement> <année_rep>3 950</année_rep> <total_rep>61 135</total_rep> <tag1>javascript</tag1> <tag2>tableaux</tag2> <tag3>objet</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>JB Nizet</utilisateur> <lien>http://www.stackoverflow.com//users/571407/jb-nizet</link> <lieu>Saint-Étienne, France</lieu> <année_rep>3 923</année_rep> <total_rep>418 780</total_rep> <tag1>java</tag1> <tag2>hiberner</tag2> <tag3>java-8</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Frank van Puffelen</utilisateur> <lien>http://www.stackoverflow.com//users/209103/frank-van-puffelen</link> <lieu>San Francisco, Californie</lieu> <année_rep>3 920</année_rep> <total_rep>86 520</total_rep> <tag1>firebase</tag1> <tag2>firebase-database</tag2> <tag3>Android</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>dasblinkenlight</utilisateur> <lien>http://www.stackoverflow.com//users/335858/dasblinkenlight</link> <emplacement>États-Unis</emplacement> <année_rep>3 886</année_rep> <total_rep>475 813</total_rep> <tag1>c#</tag1> <tag2>java</tag2> <tag3>c++</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Tim Biegeleisen</utilisateur> <lien>http://www.stackoverflow.com//users/1863229/tim-biegeleisen</link> <emplacement>Singapour</emplacement> <année_rep>3 814</année_rep> <total_rep>77 211</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>java</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Greg Hewgill</utilisateur> <lien>http://www.stackoverflow.com//users/893/greg-hewgill</link> <emplacement>Christchurch, Nouvelle-Zélande</emplacement> <année_rep>3 796</année_rep> <total_rep>529 137</total_rep> <tag1>git</tag1> <tag2>python</tag2> <tag3>git-pull</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>unutbu</utilisateur> <lien>http://www.stackoverflow.com//users/190597/unutbu</link> <emplacement></emplacement> <année_rep>3 735</année_rep> <total_rep>401 595</total_rep> <tag1>python</tag1> <tag2>pandas</tag2> <tag3>numpy</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Hans Passant</utilisateur> <lien>http://www.stackoverflow.com//users/17034/hans-passant</link> <emplacement>Madison, WI</emplacement> <année_rep>3 688</année_rep> <total_rep>672 118</total_rep> <tag1>c#</tag1> <tag2>.net</tag2> <tag3>winforms</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Jonathan Leffler</utilisateur> <lien>http://www.stackoverflow.com//users/15168/jonathan-leffler</link> <lieu>Californie, États-Unis</lieu> <année_rep>3 649</année_rep> <total_rep>455 157</total_rep> <tag1>c</tag1> <tag2>bash</tag2> <tag3>unix</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>paxdiablo</utilisateur> <lien>http://www.stackoverflow.com//users/14860/paxdiablo</link> <emplacement></emplacement> <année_rep>3 636</année_rep> <total_rep>507 043</total_rep> <tag1>c</tag1> <tag2>c++</tag2> <tag3>bash</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Pranav C Balan</utilisateur> <lien>http://www.stackoverflow.com//users/3037257/pranav-c-balan</link> <emplacement>Ramanthali, Kannur, Kerala, Inde</emplacement> <année_rep>3 604</année_rep> <total_rep>64 476</total_rep> <tag1>javascript</tag1> <tag2>jquery</tag2> <tag3>html</tag3> </topusers> <les meilleurs utilisateurs> <utilisateur>Suragch</utilisateur> <lien>http://www.stackoverflow.com//users/3681880/suragch</link> <emplacement>Hohhot, Chine</emplacement> <année_rep>3 580</année_rep> <total_rep>71 032</total_rep> <tag1>rapide</tag1> <tag2>ios</tag2> <tag3>Android</tag3> </topusers> </stackoverflow> 

Méthodes Python

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 n'est pas None et 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("Entrée.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> < !-- LIGNES DE DONNÉES (SÉPARÉES PAR DES VIRGULES) --> <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:text> </xsl:quand> <xsl:sinon> <xsl:text>&quot;&#xa;</xsl:text> </xsl:sinon> </xsl:choisissez> </xsl:for-each> </xsl:modèle> </xsl:transform> """ xsl = lxet.fromstring(xslstr) transform = lxet.XSLT(xsl) newdom = transform(xml) df = pd.read_csv(StringIO(str(newdom))) 

Timings (avec XML actuel et XML avec 25 fois les enfants (c'est-à-dire 900 enregistrements d'utilisateurs StackOverflow)

# FICHIER PLUS COURT python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_iterfind()" 100 boucles, la meilleure des 3 : 3,87 msec par boucle python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_iterparse()" 100 boucles, la meilleure des 3 : 5,5 msec par boucle python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_lxml_xpath()" 100 boucles, la meilleure des 3 : 3,86 msec par boucle python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_lxml_xsl( )" 100 boucles, la meilleure des 3 : 5,68 msec par boucle # FICHIER PLUS GRAND python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_iterfind()" 100 boucles, la meilleure des 3 : 36 msec par boucle python -mtimeit -n"100" -s"importer readxml_test_runs comme test" "test.read_xml_i terparse()" 100 boucles, la meilleure des 3 : 78,9 msec par boucle python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_lxml_xpath()" 100 boucles, la meilleure des 3 : 32,7 msec par boucle python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_lxml_xsl()" 100 boucles, la meilleure des 3 : 51,4 ms par boucle