Pandas read_xml() 方法測試策略

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

目前,pandas I/O tools 不維護一個 read_xml() 方法和對應的 to_xml()。但是,read_json 證明樹狀結構可以用於數據幀導入和 read_html 用於標記格式。

如果 pandas 團隊確實考慮在未來的 pandas 版本中使用這樣的 read_xml 方法,他們會採用什麼實現方式追求:使用內置的 xml.etree.ElementTree 及其 iterfind()iterparse() 函數或第三方模塊進行解析, lxml 及其 XPath 1.0 和 XSLT 1.0 方法?

下面是我在一個簡單、扁平、以元素為中心的 XML 輸入上對四種方法類型的測試運行。所有這些都設置為對 root 的任何二級子級進行廣義解析,並且每種方法都應該產生完全相同的 pandas 數據幀。除了最後一個調用字典列表上的 pd.Dataframe()。 XSLT 方法將 XML 轉換為 CSV,以便在 pd.read_csv() 中轉換為 StringIO()

Question (多部分)

  • 性能:您如何解釋由於文件被迭代解析而通常推薦用於較大文件的較慢的 iterparse?部分原因是 if 邏輯檢查嗎?

  • MEMORY:CPU 內存是否與 I/O 調用中的時序相關? XSLT 和 XPath 1.0 往往不能很好地適應較大的 XML 文檔,因為必須在內存中讀取整個文件才能進行解析。

  • 策略:字典列表是 <代碼>Dataframe() 調用?查看這些有趣的答案:generator 版本和iterwalk 用戶定義 版本.兩個向上轉換列表到數據幀。

輸入數據(堆棧溢出當前的按年排名最高的用戶,其中包括我們的熊貓朋友)

<? xml version="1.0" encoding="utf-8"?> <stackoverflow> <topusers> <user>Gordon Linoff</user> <link>http://www.stackoverflow.com//users /1144035/gordon-linoff</link><location>美國紐約</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>奧地利林茨</location><year_rep>5,835</year_rep> ; <total_rep>154,4 39</total_rep> <tag1>angular2</tag1> <tag2>打字稿</tag2> <tag3>javascript</tag3> </頂級用戶> <頂級用戶> <用戶>jezrael</用戶> <鏈接>http://www.stackoverflow.com//users/2901002/jezrael</link> <location>斯洛伐克布拉迪斯拉發</location> <year_rep>5,740</year_rep> <total_rep>83,237</total_rep> <tag1>熊貓</tag1> <tag2>python</tag2> <tag3>數據幀</tag3> </頂級用戶> <頂級用戶> <用戶>VonC</用戶> <鏈接>http://www.stackoverflow.com//users/6309/vonc</link> <location>法國</location> <year_rep>5,577</year_rep> <total_rep>651,397</total_rep> <tag1>git</tag1> <tag2>github</tag2> <tag3>泊塢窗</tag3> </頂級用戶> <頂級用戶> <user>Martijn Pieters</user> <鏈接>http://www.stackoverflow.com//users/100297/martijn-pieters</link> <location>英國劍橋</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> </頂級用戶> <頂級用戶> <用戶>TJ克勞德</用戶> <鏈接>http://www.stackoverflow.com//users/157247/tj-crowder</link> <location>英國</location> <year_rep>5,258</year_rep> <total_rep>508,310</total_rep> <tag1>javascript</tag1> <tag2>jquery</tag2> <tag3>java</tag3> </頂級用戶> <頂級用戶> <用戶>akrun</用戶> <鏈接>http://www.stackoverflow.com//users/3732271/akrun</link> <位置></位置> <year_rep>5,188</year_rep> <total_rep>229,553</total_rep> <tag1>r</tag1> <tag2>dplyr</tag2> <tag3>數據幀</tag3> </頂級用戶> <頂級用戶> <user>Wiktor Stribi?ew</user> <鏈接>http://www.stackoverflow.com//users/3832970/wiktor-stribi%c5%bcew</link> <location>波蘭華沙</location> <year_rep>4,948</year_rep> <total_rep>158,134</total_rep> <tag1>正則表達式</tag1> <tag2>javascript</tag2> <tag3>c#</tag3> </頂級用戶> <頂級用戶> <用戶>達林·迪米特洛夫</用戶> <鏈接>http://www.stackoverflow.com//users/29407/darin-dimitrov</link> <location>保加利亞索非亞</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> </頂級用戶> <頂級用戶> <用戶>埃里克·杜米尼</用戶> <鏈接>http://www.stackoverflow.com//users/6419007/eric-duminil</link> <位置></位置> <year_rep>4,854</year_rep> <total_rep>12,557</total_rep> <tag1>紅寶石</tag1> <tag2>ruby-on-rails</tag2> <tag3>數組</tag3> </頂級用戶> <頂級用戶> <用戶>alecxe</用戶> <鏈接>http://www.stackoverflow.com//users/771848/alecxe</link> <location>美國紐約</location> <year_rep>4,723</year_rep> <total_rep>233,368</total_rep> <tag1>python</tag1> <tag2>硒</tag2> <tag3>量角器</tag3> </頂級用戶> <頂級用戶> <user>Jean-Fran√ßois Fabre</user> <鏈接>http://www.stackoverflow.com//users/6451573/jean-fran%c3%a7ois-fabre</link> <location>法國圖盧茲</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> </頂級用戶> <頂級用戶> <用戶>piRSquared</用戶> <鏈接>http://www.stackoverflow.com//users/2336654/pirsquared</link> <location>美國華盛頓州貝爾維尤</location> <year_rep>4,482</year_rep> <total_rep>41,183</total_rep> <tag1>熊貓</tag1> <tag2>python</tag2> <tag3>數據幀</tag3> </頂級用戶> <頂級用戶> <user>CommonsWare</user> <鏈接>http://www.stackoverflow.com//users/115145/commonsware</link> <location>誰想知道?</location> <year_rep>4,475</year_rep> <total_rep>616,135</total_rep> <tag1>android</tag1> <tag2>java</tag2> <tag3>android-intent</tag3> </頂級用戶> <頂級用戶> <用戶>昆汀</用戶> <鏈接>http://www.stackoverflow.com//users/19068/quentin</link> <location>英國</location> <year_rep>4,464</year_rep> <total_rep>509,365</total_rep> <tag1>javascript</tag1> <tag2>html</tag2> <tag3>css</tag3> </頂級用戶> <頂級用戶> <用戶>喬恩·斯基特</用戶> <link>http://www.stackoverflow.com//users/22656/jon-skeet</link> <location>雷丁,英國</location> <year_rep>4,348</year_rep> <total_rep>921,690</total_rep> <tag1>c#</tag1> <tag2>java</tag2> <tag3>.net</tag3> </頂級用戶> <頂級用戶> <用戶>費利克斯·克林</用戶> <鏈接>http://www.stackoverflow.com//users/218196/felix-kling</link> <位置>加利福尼亞州森尼維爾</位置> <year_rep>4,324</year_rep> <total_rep>411,535</total_rep> <tag1>javascript</tag1> <tag2>jquery</tag2> <tag3>異步</tag3> </頂級用戶> <頂級用戶> <用戶>馬特</用戶> <鏈接>http://www.stackoverflow.com//users/341994/matt</link> <位置></位置> <year_rep>4,313</year_rep> <total_rep>220,515</total_rep> <tag1>swift</tag1> <tag2>ios</tag2> <tag3>xcode</tag3> </頂級用戶> <頂級用戶> <user>Psidom</user> <鏈接>http://www.stackoverflow.com//users/4983450/psidom</link> <location>美國喬治亞州亞特蘭大</location> <year_rep>4,236</year_rep> <total_rep>36,950</total_rep> <tag1>python</tag1> <tag2>熊貓</tag2> <tag3>r</tag3> </頂級用戶> <頂級用戶> <用戶>馬丁 R</用戶> <鏈接>http://www.stackoverflow.com//users/1187415/martin-r</link> <位置>德國</位置> <year_rep>4,195</year_rep> <total_rep>269,380</total_rep> <tag1>swift</tag1> <tag2>ios</tag2> <tag3>swift3</tag3> </頂級用戶> <頂級用戶> <user>Barmar</user> <鏈接>http://www.stackoverflow.com//users/1491895/barmar</link> <位置>馬薩諸塞州阿靈頓</位置> <year_rep>4,179</year_rep> <total_rep>289,989</total_rep> <tag1>javascript</tag1> <tag2>php</tag2> <tag3>jquery</tag3> </頂級用戶> <頂級用戶> <用戶>Alexey Mezenin</用戶> <鏈接>http://www.stackoverflow.com//users/1227923/alexey-mezenin</link> <位置>??????</位置> <year_rep>4,142</year_rep> <total_rep>31,602</total_rep> <tag1>laravel</tag1> <tag2>php</tag2> <tag3>laravel-5.3</tag3> </頂級用戶> <頂級用戶> <user>BalusC</user> <鏈接>http://www.stackoverflow.com//users/157882/balusc</link> <location>阿姆斯特丹,荷蘭</location> <year_rep>4,046</year_rep> <total_rep>703,046</total_rep> <tag1>java</tag1> <tag2>jsf</tag2> <tag3>servlet</tag3> </頂級用戶> <頂級用戶> <用戶>GurV</用戶> <鏈接>http://www.stackoverflow.com//users/6348498/gurv</link> <位置></位置> <year_rep>4,016</year_rep> <total_rep>7,932</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>sql-server</tag3> </頂級用戶> <頂級用戶> <用戶>妮娜·舒爾茨</用戶> <鏈接>http://www.stackoverflow.com//users/1447675/nina-scholz</link> <location>柏林,德國</location> <year_rep>3,950</year_rep> <total_rep>61,135</total_rep> <tag1>javascript</tag1> <tag2>數組</tag2> <tag3>對象</tag3> </頂級用戶> <頂級用戶> <user>JB 尼澤特</user> <鏈接>http://www.stackoverflow.com//users/571407/jb-nizet</link> <location>法國聖艾蒂安</location> <year_rep>3,923</year_rep> <total_rep>418,780</total_rep> <tag1>java</tag1> <tag2>休眠</tag2> <tag3>java-8</tag3> </頂級用戶> <頂級用戶> <user>Frank van Puffelen</user> <鏈接>http://www.stackoverflow.com//users/209103/frank-van-puffelen</link> <location>加利福尼亞州舊金山</location> <year_rep>3,920</year_rep> <total_rep>86,520</total_rep> <tag1>firebase</tag1> <tag2>firebase 數據庫</tag2> <tag3>安卓</tag3> </頂級用戶> <頂級用戶> <用戶>dasblinkenlight</用戶> <鏈接>http://www.stackoverflow.com//users/335858/dasblinkenlight</link> <location>美國</location> <year_rep>3,886</year_rep> <total_rep>475,813</total_rep> <tag1>c#</tag1> <tag2>java</tag2> <tag3>c++</tag3> </頂級用戶> <頂級用戶> <用戶>蒂姆·比格萊森</用戶> <鏈接>http://www.stackoverflow.com//users/1863229/tim-biegeleisen</link> <位置>新加坡</位置> <year_rep>3,814</year_rep> <total_rep>77,211</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>java</tag3> </頂級用戶> <頂級用戶> <用戶>格雷格·休吉爾</用戶> <鏈接>http://www.stackoverflow.com//users/893/greg-hewgill</link> <location>新西蘭基督城</location> <year_rep>3,796</year_rep> <total_rep>529,137</total_rep> <tag1>git</tag1> <tag2>python</tag2> <tag3>git-pull</tag3> </頂級用戶> <頂級用戶> <user>unutbu</user> <link>http://www.stackoverflow.com//users/190597/unutbu</link> <位置></位置> <year_rep>3,735</year_rep> <total_rep>401,595</total_rep> <tag1>python</tag1> <tag2>熊貓</tag2> <tag3>numpy</tag3> </頂級用戶> <頂級用戶> <用戶>漢斯·帕桑特</用戶> <鏈接>http://www.stackoverflow.com//users/17034/hans-passant</link> <位置>威斯康星州麥迪遜</位置> <year_rep>3,688</year_rep> <total_rep>672,118</total_rep> <tag1>c#</tag1> <tag2>.net</tag2> <tag3>winforms</tag3> </頂級用戶> <頂級用戶> <用戶>喬納森·萊弗勒</用戶> <鏈接>http://www.stackoverflow.com//users/15168/jonathan-leffler</link> <location>美國加利福尼亞州</location> <year_rep>3,649</year_rep> <total_rep>455,157</total_rep> <tag1>c</tag1> <tag2>bash</tag2> <tag3>unix</tag3> </頂級用戶> <頂級用戶> <用戶>paxdiablo</用戶> <鏈接>http://www.stackoverflow.com//users/14860/paxdiablo</link> <位置></位置> <year_rep>3,636</year_rep> <total_rep>507,043</total_rep> <tag1>c</tag1> <tag2>c++</tag2> <tag3>bash</tag3> </頂級用戶> <頂級用戶> <user>Pranav C Balan</user> <鏈接>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> </頂級用戶> <頂級用戶> <user>Suragch</user> <鏈接>http://www.stackoverflow.com//users/3681880/suragch</link> <location>中國呼和浩特</location> <year_rep>3,580</year_rep> <total_rep>71,032</total_rep> <tag1>swift</tag1> <tag2>ios</tag2> <tag3>安卓</tag3> </頂級用戶> </stackoverflow> 

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 不是 None 和 len(el.text.strip()) > 0: 內部[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> <!-- 數據行(逗號分隔)--> <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:何時> <xsl:否則> <xsl:text>&quot;&#xa;</xsl:text> </xsl:否則> </xsl:選擇> </xsl:for-each> </xsl:模板> </xsl:transform> """ xsl = lxet.fromstring(xslstr) transform = lxet.XSLT(xsl) newdom = transform(xml) df = pd.read_csv(StringIO(str(newdom))) 

Timings (使用當前 XML 和帶有 25 次子級的 XML(即 900 條 StackOverflow 用戶記錄))

# SHORTER FILE python -mtimeit -s“import readxml_test_runs as test”“test.read_xml_iterfind()”100 個循環,最好的 3:每個循環 3.87 毫秒 python -mtimeit -s“import readxml_test_runs as test”“test.read_xml_iterparse()”100 個循環,最好的 3 :每循環 5.5 毫秒 python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_lxml_xpath()" 100 個循環,最好的 3:每循環 3.86 毫秒 python -mtimeit -s"import readxml_test_runs as test" "test.read_xml_lxml_xsl( )" 100 個循環,3 個中最好的:每個循環 5.68 毫秒 # LARGER FILE python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_iterfind()" 100 個循環,3 個中最好的:每個循環 36 毫秒python -mtimeit -n"100" -s"導入 readxml_test_runs 作為測試""test.read_xml_i terparse()" 100 個循環,最好的 3:每循環 78.9 毫秒 python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_lxml_xpath()" 100 循環,最好的 3:每循環 32.7 毫秒 python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_lxml_xsl()" 100 次循環,最好的 3 次:每個循環 51.4 毫秒