Strategie testowe metody Pandas read_xml()

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

Obecnie narzędzia we/wy pand nie obsługują read_xml() i jej odpowiednikiem to_xml(). Jednak read_json dowodzi, że struktury drzewiaste można zaimplementować do importu ramek danych i read_html dla formatów znaczników.

Jeśli zespół pand rozważy taką metodę read_xml dla przyszłej wersji pand, jaką implementację zrobiliby realizować: parsowanie za pomocą wbudowanego xml.etree.ElementTree z jego funkcjami iterfind() lub iterparse() lub modułem innej firmy, lxml z metodami XPath 1.0 i XSLT 1.0?

Poniżej znajdują się moje przebiegi testów dla czterech typów metod na prostym, płaskim, skoncentrowanym na elementach wejściu XML. Wszystkie są skonfigurowane do uogólnionego analizowania dla dowolnych dzieci drugiego poziomu korzenia, a każda metoda powinna dawać dokładnie tę samą ramkę danych pandas. Wszystkie oprócz ostatniego wywołują pd.Dataframe() na liście słowników. Metoda XSLT przekształca XML na CSV w celu rzutowania StringIO() w pd.read_csv().

Pytanie (wieloczęściowy)

  • WYDAJNOŚĆ: Jak wyjaśnić wolniejszy iterparse często zalecany w przypadku większych plików, ponieważ plik jest analizowany iteracyjnie? Czy jest to częściowo spowodowane sprawdzaniem logiki if?

  • PAMIĘĆ: Czy pamięć procesora jest skorelowana z czasami w wywołaniach I/O? XSLT i XPath 1.0 zwykle nie skalują się dobrze z większymi dokumentami XML, ponieważ cały plik musi być odczytany w pamięci, aby mógł zostać przetworzony.

  • STRATEGIA: Czy lista słowników jest optymalną strategią dla Dataframe() wywołanie? Zobacz te interesujące odpowiedzi: wersja generatora i wersja iterwalk zdefiniowana przez użytkownika . Obydwa przesyłane listy do ramki danych.

Wprowadź Dane (Bieżący najwięksi użytkownicy według roku w tym nasi przyjaciele z pand)

<? xml version="1.0" kodowanie="utf-8"?> <stackoverflow> <topusers> <user>Gordon Linoff</user> <link>http://www.stackoverflow.com//users /1144035/gordon-linoff</link> <location>Nowy Jork, Stany Zjednoczone</location> <year_rep>5985</year_rep> <total_rep>499.408</total_rep>> tag1> <tag2>sql-server</tag2> <tag3>mysql</tag3> </topusers> <topusers> <user>G√ºnter Z√∂chbauer</userlink> 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,4 39</całkowita liczba powtórzeń> <tag1>kątowy2</tag1> <tag2>maszyny</tag2> <tag3>javascript</tag3> </topusers> <topusers> <user>jezrael</user> <link>http://www.stackoverflow.com//users/2901002/jezrael</link> <location>Bratysława, Słowacja</location> <year_rep>5740</year_rep> <total_rep>83,237</total_rep> <tag1>pandy</tag1> <tag2>python</tag2> <tag3>ramka danych</tag3> </topusers> <topusers> <user>VonC</user> <link>http://www.stackoverflow.com//users/6309/vonc</link> <lokalizacja>Francja</lokalizacja> <year_rep>5,577</year_rep> <total_rep>651,397</total_rep> <tag1>git</tag1> <tag2>github</tag2> <tag3>okno dokowane</tag3> </topusers> <topusers> <user>Martijn Pieters</user> <link>http://www.stackoverflow.com//users/100297/martijn-pieters</link> <location>Cambridge, Wielka Brytania</location> <year_rep>5337</year_rep> 525,176</total_rep> <tag1>python</tag1> <tag2>python-3.x</tag2> <tag3>python-2.7</tag3> </topusers> <topusers> <użytkownik>TJ Crowder</user> <link>http://www.stackoverflow.com//users/157247/tj-crowder</link> <lokalizacja>Wielka Brytania</lokalizacja> <year_rep>5258</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> <lokalizacja></lokalizacja> <year_rep>5,188</year_rep> <total_rep>229,553</total_rep> <tag1>r</tag1> <tag2>dplyr</tag2> <tag3>ramka danych</tag3> </topusers> <topusers> <user>Wiktor Stribi?ew</user> <link>http://www.stackoverflow.com//users/3832970/wiktor-stribi%c5%bcew</link> <lokalizacja>Warszawa, Polska</lokalizacja> <year_rep>4948</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> <lokalizacja>Sofia, Bułgaria</lokalizacja> <year_rep>4936</year_rep> <total_rep>709683</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> <lokalizacja></lokalizacja> <year_rep>4.854</year_rep> <total_rep>12 557</total_rep> <tag1>rubin</tag1> <tag2>rubin-on-rail</tag2> <tag3>tablice</tag3> </topusers> <topusers> <user>alecxe</user> <link>http://www.stackoverflow.com//users/771848/alecxe</link> <location>Nowy Jork, Stany Zjednoczone</location> <year_rep>4723</year_rep> <total_rep>233,368</total_rep> <tag1>python</tag1> <tag2>selen</tag2> <tag3>kątomierz</tag3> </topusers> <topusers> <user>Jean-Fran√ßois Fabre</user> <link>http://www.stackoverflow.com//users/6451573/jean-fran%c3%a7ois-fabre</link> <location>Tuluza, Francja</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, Waszyngton, Stany Zjednoczone</location> <year_rep>4,482</year_rep> <total_rep>41,183</total_rep> <tag1>pandy</tag1> <tag2>python</tag2> <tag3>ramka danych</tag3> </topusers> <topusers> <user>CommonsWare</user> <link>http://www.stackoverflow.com//users/115145/commonsware</link> <lokalizacja>Kto chce wiedzieć?</lokalizacja> <year_rep>4475</year_rep> <total_rep>616,135</total_rep> <tag1>Android</tag1> <tag2>java</tag2> <tag3>zamiar Androida</tag3> </topusers> <topusers> <user>Quentin</user> <link>http://www.stackoverflow.com//users/19068/quentin</link> <lokalizacja>Wielka Brytania</lokalizacja> <year_rep>4464</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, Wielka Brytania</location> <year_rep>4348</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> <lokalizacja>Sunnyvale, Kalifornia</lokalizacja> <year_rep>4324</year_rep> <total_rep>411,535</total_rep> <tag1>javascript</tag1> <tag2>jquery</tag2> <tag3>asynchroniczny</tag3> </topusers> <topusers> <user>matowy</user> <link>http://www.stackoverflow.com//users/341994/matt</link> <lokalizacja></lokalizacja> <year_rep>4313</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, Stany Zjednoczone</location> <year_rep>4,236</year_rep> <total_rep>36950</total_rep> <tag1>python</tag1> <tag2>pandy</tag2> <tag3>r</tag3> </topusers> <topusers> <user>Marcin R</user> <link>http://www.stackoverflow.com//users/1187415/martin-r</link> <lokalizacja>Niemcy</lokalizacja> <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> <lokalizacja>Arlington, MA</lokalizacja> <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> <lokalizacja>??????</lokalizacja> <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, Holandia</location> <year_rep>4046</year_rep> <total_rep>703,046</total_rep> <tag1>java</tag1> <tag2>jsf</tag2> <tag3>serwlety</tag3> </topusers> <topusers> <user>GurV</user> <link>http://www.stackoverflow.com//users/6348498/gurv</link> <lokalizacja></lokalizacja> <year_rep>4016</year_rep> <total_rep>7932</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>serwer-sql</tag3> </topusers> <topusers> <user>Nina Scholz</user> <link>http://www.stackoverflow.com//users/1447675/nina-scholz</link> <lokalizacja>Berlin, Niemcy</lokalizacja> <year_rep>3.950</year_rep> <total_rep>61,135</total_rep> <tag1>javascript</tag1> <tag2>tablice</tag2> <tag3>obiekt</tag3> </topusers> <topusers> <user>JB Nizet</user> <link>http://www.stackoverflow.com//users/571407/jb-nizet</link> <location>Saint-Etienne, Francja</location> <year_rep>3923</year_rep> <total_rep>418,780</total_rep> <tag1>java</tag1> <tag2>hibernacja</tag2> <tag3>java-8</tag3> </topusers> <topusers> <user>Frank van Puffelen</user> <link>http://www.stackoverflow.com//users/209103/frank-van-puffelen</link> <lokalizacja>San Francisco, Kalifornia</lokalizacja> <year_rep>3920</year_rep> <total_rep>86,520</total_rep> <tag1>firebase</tag1> <tag2>baza-danych-firebase</tag2> <tag3>Android</tag3> </topusers> <topusers> <user>dasblinkenlight</user> <link>http://www.stackoverflow.com//users/335858/dasblinkenlight</link> <location>Stany Zjednoczone</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> <lokalizacja>Singapur</lokalizacja> <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, Nowa Zelandia</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> <lokalizacja></lokalizacja> <year_rep>3,735</year_rep> <total_rep>401,595</total_rep> <tag1>python</tag1> <tag2>pandy</tag2> <tag3>numpy</tag3> </topusers> <topusers> <user>Hans Passant</user> <link>http://www.stackoverflow.com//users/17034/hans-passant</link> <lokalizacja>Madison, WI</lokalizacja> <year_rep>3,688</year_rep> <total_rep>672,118</total_rep> <tag1>c#</tag1> <tag2>.net</tag2> <tag3>winformuje</tag3> </topusers> <topusers> <user>Jonathan Leffler</user> <link>http://www.stackoverflow.com//users/15168/jonathan-leffler</link> <location>Kalifornia, USA</location> <year_rep>3649</year_rep> <total_rep>455,157</total_rep> <tag1>c</tag1> <tag2>bash</tag2> <tag3>unix</tag3> </topusers> <topusers> <użytkownik>paxdiablo</user> <link>http://www.stackoverflow.com//users/14860/paxdiablo</link> <lokalizacja></lokalizacja> <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, Indie</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, Chiny</location> <year_rep>3,580</year_rep> <total_rep>71,032</total_rep> <tag1>swift</tag1> <tag2>ios</tag2> <tag3>Android</tag3> </topusers> </przepełnienie stosu> 

Metody Pythona

import xml.etree.ElementTree as i importuj pandy jako pd z io importuj StringIO z lxml importuj 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 nie ma wartości None, a 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" kodowanie= "UTF-8" indent="tak" method="text"/> <xsl:strip-space elements="*"/> <!-- HEADERS --> <xsl:template match = "/*"> <xsl:for-each select="*[1]/*"> <xsl:value-of select="nazwa_lokalnej()" /> <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> <!-- WIERSZE DANYCH (ODDZIELONE PRZECINEKAMI) --> <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:tekst> </xsl:kiedy> <xsl:inaczej> <xsl:text>&quot;&#xa;</xsl:text> </xsl:inaczej> </xsl:wybierz> </xsl:dla każdego> </xsl:szablon> </xsl:transformacja> """ xsl = lxet.fromstring(xslstr) transform = lxet.XSLT(xsl) newdom = transform(xml) df = pd.read_csv(StringIO(str(newdom))) 

Czasy (z bieżącym XML i XML z 25-krotnością liczby dzieci (tj. 900 rekordów użytkowników StackOverflow)

# SHORTER FILE python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_iterfind()" 100 pętli, najlepiej 3: 3,87 ms na pętlę Pythona -mtimeit -s"import readxml_test_runs jako test" "test.read_xml_iterparse()" 100 pętli, najlepiej 3 : 5,5 ms na pętlę python -mtimeit -s"import readxml_test_runs jako test" "test.read_xml_lxml_xpath()" 100 pętli, najlepiej 3: 3,86 ms na pętlę python -mtimeit -s"import readxml_test_runs jako test" "test.read_xml_lxml_xs )" 100 pętli, najlepiej 3: 5,68 ms na pętlę # WIĘKSZY PLIK python -mtimeit -n"100" -s"import readxml_test_runs jako test" "test.read_xml_iterfind()" 100 pętli, najlepiej 3: 36 ms na pętlę python -mtimeit -n"100" -s"import readxml_test_runs jako test" "test.read_xml_i terparse()" 100 pętli, najlepiej 3: 78,9 ms na python w pętli -mtimeit -n"100" -s"import readxml_test_runs jako test" "test.read_xml_lxml_xpath()" 100 pętli, najlepiej 3: 32,7 ms na pętlę python -mtimeit -n"100" -s"import readxml_test_runs jako test" "test.read_xml_lxml_xsl()" 100 pętli, najlepiej 3: 51,4 ms na pętlę