Pandas read_xml() Methodenteststrategien

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

Derzeit unterhalten I/O-Tools von Pandas keine read_xml() Methode und das Gegenstück to_xml(). Jedoch read_json beweist, dass baumartige Strukturen für den Dataframe-Import und implementiert werden können read_html für Markup-Formate.

Falls das Pandas-Team eine solche read_xml-Methode für eine zukünftige Pandas-Version in Betracht zieht, welche Implementierung würde es wählen weiterverfolgen: Parsing mit eingebautem xml.etree.ElementTree mit seinen Funktionen iterfind() oder iterparse() oder dem Modul eines Drittanbieters, lxml mit seinen XPath 1.0- und XSLT 1.0-Methoden?

Unten sind meine Testläufe für vier Methodentypen auf einer einfachen, flachen, elementzentrierten XML-Eingabe. Alle sind für die verallgemeinerte Analyse für alle untergeordneten Elemente der zweiten Ebene von root eingerichtet, und jede Methode sollte genau denselben Pandas-Datenrahmen ergeben. Alle außer dem letzten rufen pd.Dataframe() in der Liste der Wörterbücher auf. Die XSLT-Methode transformiert XML in CSV für gecastete StringIO() in pd.read_csv().

Frage (mehrteilig)

  • LEISTUNG: Wie erklären Sie die langsamere iterparse, die oft für größere Dateien empfohlen wird, da die Datei iterativ geparst wird? Liegt es teilweise an den if-Logikprüfungen?

  • SPEICHER: Korreliert der CPU-Speicher mit dem Timing in E/A-Aufrufen? XSLT und XPath 1.0 neigen dazu, sich nicht gut mit größeren XML-Dokumenten zu skalieren, da die gesamte Datei in den Speicher gelesen werden muss, um geparst zu werden.

  • STRATEGIE: Ist die Liste der Wörterbücher eine optimale Strategie für Dataframe() aufrufen? Siehe diese interessanten Antworten: Generatorversion und eine iterwalk benutzerdefinierte Version . Beide Upcast-Listen zum Datenrahmen.

Input Data (Stack Overflow"s aktuelle Top-Nutzer nach Jahr darunter auch unsere Panda-Freunde)

<? 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, USA</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, Österreich</location> <year_rep>5.835</year_rep> ; <Gesamtrep>154,4 39</total_rep> <tag1>Winkel2</tag1> <tag2>Typoskript</tag2> <tag3>Javascript</tag3> </topusers> <topusers> <user>jezrael</user> <link>http://www.stackoverflow.com//users/2901002/jezrael</link> <location>Bratislava, Slowakei</location> <year_rep>5.740</year_rep> <total_rep>83.237</total_rep> <tag1>Pandas</tag1> <tag2>python</tag2> <tag3>Datenrahmen</tag3> </topusers> <topusers> <Benutzer>VonC</Benutzer> <link>http://www.stackoverflow.com//users/6309/vonc</link> <location>Frankreich</location> <year_rep>5.577</year_rep> <Gesamtrep>651.397</Gesamtrep> <tag1>git</tag1> <tag2>github</tag2> <tag3>Docker</tag3> </topusers> <topusers> <Benutzer>Martijn Pieters</Benutzer> <link>http://www.stackoverflow.com//users/100297/martijn-pieters</link> <location>Cambridge, Vereinigtes Königreich</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> <Benutzer>TJ Crowder</user> <link>http://www.stackoverflow.com//users/157247/tj-crowder</link> <location>Vereinigtes Königreich</location> <year_rep>5.258</year_rep> <total_rep>508.310</total_rep> <tag1>Javascript</tag1> <tag2>jquery</tag2> <tag3>Java</tag3> </topusers> <topusers> <Benutzer>akrun</Benutzer> <link>http://www.stackoverflow.com//users/3732271/akrun</link> <Standort></Standort> <year_rep>5.188</year_rep> <total_rep>229.553</total_rep> <tag1>r</tag1> <tag2>dplyr</tag2> <tag3>Datenrahmen</tag3> </topusers> <topusers> <user>Wiktor Stribi?ew</user> <link>http://www.stackoverflow.com//users/3832970/wiktor-stribi%c5%bcew</link> <location>Warschau, Polen</location> <year_rep>4.948</year_rep> <Gesamtrep>158.134</Gesamtrep> <tag1>regulärer Ausdruck</tag1> <tag2>Javascript</tag2> <tag3>c#</tag3> </topusers> <topusers> <Benutzer>Darin Dimitrov</Benutzer> <link>http://www.stackoverflow.com//users/29407/darin-dimitrov</link> <location>Sofia, Bulgarien</location> <year_rep>4.936</year_rep> <Gesamtrep>709.683</Gesamtrep> <tag1>c#</tag1> <tag2>asp.net-mvc</tag2> <tag3>asp.net-mvc-3</tag3> </topusers> <topusers> <Benutzer>Eric Duminil</Benutzer> <link>http://www.stackoverflow.com//users/6419007/eric-duminil</link> <Standort></Standort> <year_rep>4.854</year_rep> <total_rep>12.557</total_rep> <tag1>Rubin</tag1> <tag2>Rubin auf Schienen</tag2> <tag3>Arrays</tag3> </topusers> <topusers> <Benutzer>alecxe</Benutzer> <link>http://www.stackoverflow.com//users/771848/alecxe</link> <Standort>New York, USA</Standort> <year_rep>4.723</year_rep> <total_rep>233.368</total_rep> <tag1>python</tag1> <tag2>Selen</tag2> <tag3>Winkelmesser</tag3> </topusers> <topusers> <user>Jean-Fran√ßois Fabre</user> <link>http://www.stackoverflow.com//users/6451573/jean-fran%c3%a7ois-fabre</link> <location>Toulouse, Frankreich</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> <Benutzer>piRSquared</Benutzer> <link>http://www.stackoverflow.com//users/2336654/pirsquared</link> <Standort>Bellevue, WA, USA</Standort> <year_rep>4.482</year_rep> <total_rep>41.183</total_rep> <tag1>Pandas</tag1> <tag2>python</tag2> <tag3>Datenrahmen</tag3> </topusers> <topusers> <Benutzer>CommonsWare</Benutzer> <link>http://www.stackoverflow.com//users/115145/commonsware</link> <location>Wer möchte das wissen?</location> <year_rep>4.475</year_rep> <Gesamtrep>616.135</Gesamtrep> <tag1>Android</tag1> <tag2>Java</tag2> <tag3>Android-Absicht</tag3> </topusers> <topusers> <Benutzer>Quentin</Benutzer> <link>http://www.stackoverflow.com//users/19068/quentin</link> <location>Vereinigtes Königreich</location> <year_rep>4.464</year_rep> <total_rep>509.365</total_rep> <tag1>Javascript</tag1> <tag2>html</tag2> <tag3>css</tag3> </topusers> <topusers> <Benutzer>Jon Skeet</Benutzer> <link>http://www.stackoverflow.com//users/22656/jon-skeet</link> <location>Reading, Vereinigtes Königreich</location> <year_rep>4.348</year_rep> <total_rep>921.690</total_rep> <tag1>c#</tag1> <tag2>Java</tag2> <tag3>.net</tag3> </topusers> <topusers> <Benutzer>Felix Kling</Benutzer> <link>http://www.stackoverflow.com//users/218196/felix-kling</link> <Standort>Sunnyvale, CA</Standort> <year_rep>4.324</year_rep> <Gesamtrep>411.535</Gesamtrep> <tag1>Javascript</tag1> <tag2>jquery</tag2> <tag3>asynchron</tag3> </topusers> <topusers> <Benutzer>matt</Benutzer> <link>http://www.stackoverflow.com//users/341994/matt</link> <Standort></Standort> <year_rep>4.313</year_rep> <total_rep>220.515</total_rep> <tag1>schnell</tag1> <tag2>ios</tag2> <tag3>xcode</tag3> </topusers> <topusers> <Benutzer>Psidom</Benutzer> <link>http://www.stackoverflow.com//users/4983450/psidom</link> <Standort>Atlanta, GA, USA</Standort> <year_rep>4.236</year_rep> <total_rep>36.950</total_rep> <tag1>python</tag1> <tag2>Pandas</tag2> <tag3>r</tag3> </topusers> <topusers> <Benutzer>Martin R.</Benutzer> <link>http://www.stackoverflow.com//users/1187415/martin-r</link> <Standort>Deutschland</Standort> <year_rep>4.195</year_rep> <total_rep>269.380</total_rep> <tag1>schnell</tag1> <tag2>ios</tag2> <tag3>swift3</tag3> </topusers> <topusers> <Benutzer>Barmar</Benutzer> <link>http://www.stackoverflow.com//users/1491895/barmar</link> <Standort>Arlington, MA</Standort> <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> <Standort>??????</Standort> <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> <Benutzer>BalusC</Benutzer> <link>http://www.stackoverflow.com//users/157882/balusc</link> <location>Amsterdam, Niederlande</location> <year_rep>4.046</year_rep> <total_rep>703.046</total_rep> <tag1>Java</tag1> <tag2>jsf</tag2> <tag3>Servlets</tag3> </topusers> <topusers> <Benutzer>GurV</Benutzer> <link>http://www.stackoverflow.com//users/6348498/gurv</link> <Standort></Standort> <year_rep>4.016</year_rep> <total_rep>7.932</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>SQL-Server</tag3> </topusers> <topusers> <Benutzer>Nina Scholz</Benutzer> <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>Objekt</tag3> </topusers> <topusers> <Benutzer>JB Nizet</Benutzer> <link>http://www.stackoverflow.com//users/571407/jb-nizet</link> <location>Saint-Etienne, Frankreich</location> <year_rep>3.923</year_rep> <total_rep>418.780</total_rep> <tag1>Java</tag1> <tag2>Ruhezustand</tag2> <tag3>java-8</tag3> </topusers> <topusers> <user>Frank van Puffelen</user> <link>http://www.stackoverflow.com//users/209103/frank-van-puffelen</link> <Standort>San Francisco, CA</Standort> <year_rep>3.920</year_rep> <total_rep>86.520</total_rep> <tag1>Firebase</tag1> <tag2>Firebase-Datenbank</tag2> <tag3>Android</tag3> </topusers> <topusers> <user>dasblinkenlight</user> <link>http://www.stackoverflow.com//users/335858/dasblinkenlight</link> <location>Vereinigte Staaten</location> <year_rep>3.886</year_rep> <Gesamtrep>475.813</Gesamtrep> <tag1>c#</tag1> <tag2>Java</tag2> <tag3>c++</tag3> </topusers> <topusers> <Benutzer>Tim Biegeleisen</Benutzer> <link>http://www.stackoverflow.com//users/1863229/tim-biegeleisen</link> <location>Singapur</location> <year_rep>3.814</year_rep> <total_rep>77.211</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>Java</tag3> </topusers> <topusers> <Benutzer>Greg Hewgill</Benutzer> <link>http://www.stackoverflow.com//users/893/greg-hewgill</link> <location>Christchurch, Neuseeland</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> <Benutzer>unutbu</Benutzer> <link>http://www.stackoverflow.com//users/190597/unutbu</link> <Standort></Standort> <year_rep>3.735</year_rep> <Gesamtrep>401.595</Gesamtrep> <tag1>python</tag1> <tag2>Pandas</tag2> <tag3>numpy</tag3> </topusers> <topusers> <Benutzer>Hans Passant</Benutzer> <link>http://www.stackoverflow.com//users/17034/hans-passant</link> <Standort>Madison, WI</Standort> <year_rep>3.688</year_rep> <Gesamtrep>672.118</Gesamtrep> <tag1>c#</tag1> <tag2>.net</tag2> <tag3>winforms</tag3> </topusers> <topusers> <Benutzer>Jonathan Leffler</Benutzer> <link>http://www.stackoverflow.com//users/15168/jonathan-leffler</link> <location>Kalifornien, USA</location> <year_rep>3.649</year_rep> <Gesamtrep>455.157</Gesamtrep> <tag1>c</tag1> <tag2>bash</tag2> <tag3>unix</tag3> </topusers> <topusers> <user>paxdiablo</user> <link>http://www.stackoverflow.com//users/14860/paxdiablo</link> <Standort></Standort> <year_rep>3.636</year_rep> <total_rep>507.043</total_rep> <tag1>c</tag1> <tag2>c++</tag2> <tag3>bash</tag3> </topusers> <topusers> <Benutzer>Pranav C. Balan</Benutzer> <link>http://www.stackoverflow.com//users/3037257/pranav-c-balan</link> <Standort>Ramanthali, Kannur, Kerala, Indien</Standort> <year_rep>3.604</year_rep> <total_rep>64.476</total_rep> <tag1>Javascript</tag1> <tag2>jquery</tag2> <tag3>html</tag3> </topusers> <topusers> <Benutzer>Suragch</Benutzer> <link>http://www.stackoverflow.com//users/3681880/suragch</link> <Standort>Hohhot, China</Standort> <year_rep>3.580</year_rep> <total_rep>71.032</total_rep> <tag1>schnell</tag1> <tag2>ios</tag2> <tag3>Android</tag3> </topusers> </stackoverflow> 

Python-Methoden

xml.etree.ElementTree als importieren und pandas als pd aus io importieren StringIO aus lxml importieren etree importieren 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 und len(inner) != 0: data.append(inner) inner = {} if el.text ist nicht None und 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("/*/*"): für i in el: inner[i.tag] = i.text data.append(inner) inner = {} df = pd.DataFrame(data) def read_xml_lxml_xsl( ): xml = lxet.parse("Eingabe.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:sonst> <xsl: text>&#xa;</xsl:text> </xsl:sonst> </xsl:choose> </xsl:for-each> <xsl:apply-templates/> </ xsl:template> <!-- DATENREIHEN (KOMMA-GETRENNT) --> <xsl:template match="/*/*" priority="2"> <xsl:for-each select=" *"> <xsl:if test="position() = 1"> <xsl:text>&quot;</xsl:text> </xsl:if> <xsl:value- von select="." /> <xsl:choose> <xsl:when test="position() != last()"> <xsl:text>&quot;,& quot;</xsl:text> </xsl:wann> <xsl:ansonsten> <xsl:text>&quot;&#xa;</xsl:text> </xsl:ansonsten> </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))) 

Timings (mit aktuellem XML und XML mit 25-mal den Kindern (dh 900 StackOverflow-Benutzerdatensätze)

# SHORTER FILE python -mtimeit -s"readxml_test_runs als Test importieren" "test.read_xml_iterfind()" 100 Schleifen, best of 3: 3,87 ms pro Schleife python -mtimeit -s"readxml_test_runs als Test importieren" "test.read_xml_iterparse()" 100 Schleifen, best of 3 : 5,5 ms pro Schleife python -mtimeit -s"readxml_test_runs als Test importieren" "test.read_xml_lxml_xpath()" 100 Schleifen, Best of 3: 3,86 ms pro Schleife python -mtimeit -s"readxml_test_runs als Test importieren" "test.read_xml_lxml_xsl( )" 100 Schleifen, Best of 3: 5,68 ms pro Schleife # GRÖSSERE DATEI python -mtimeit -n"100" -s"readxml_test_runs als Test importieren" "test.read_xml_iterfind()" 100 Schleifen, Best of 3: 36 ms pro Schleife python -mtimeit -n"100" -s"readxml_test_runs als Test importieren" "test.read_xml_i terparse()" 100 Schleifen, Best of 3: 78,9 ms pro Schleife python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_lxml_xpath()" 100 Schleifen, Best of 3: 32,7 ms pro Schleife python -mtimeit -n"100" -s"readxml_test_runs als Test importieren" "test.read_xml_lxml_xsl()" 100 Schleifen, Best of 3: 51,4 ms pro Schleife