Pandas read_xml() 메서드 테스트 전략

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

현재 pandas I/O 도구read_xml() 메서드와 대응하는 to_xml(). 그러나 read_json 데이터 프레임 가져오기 및 에 대해 트리와 같은 구조를 구현할 수 있음을 증명합니다. 마크업 형식에 대한 read_html.

pandas 팀이 향후 pandas 버전에 대해 이러한 read_xml 메서드를 고려한다면 어떤 구현을 하시겠습니까? 추구: iterfind() 또는 iterparse() 함수 또는 타사 모듈과 함께 기본 제공 xml.etree.ElementTree로 구문 분석, XPath 1.0 및 XSLT 1.0 메서드가 있는 lxml?

아래는 단순하고 단순하며 요소 중심의 XML 입력에 대한 네 가지 메서드 유형에 대한 테스트 실행입니다. 모두 루트의 두 번째 수준 자식에 대한 일반화된 구문 분석을 위해 설정되며 각 방법은 정확히 동일한 pandas 데이터 프레임을 생성해야 합니다. 마지막을 제외한 모든 사전 목록에서 pd.Dataframe()을 호출합니다. XSLT 메소드는 pd.read_csv()의 캐스트된 StringIO()에 대해 XML을 CSV로 변환합니다.

질문 (multi-part)

  • 성능: 파일이 반복적으로 구문 분석되기 때문에 큰 파일에 권장되는 느린 iterparse를 어떻게 설명합니까? 부분적으로 if 로직 검사 때문인가요?

  • MEMORY: CPU 메모리가 I/O 호출의 타이밍과 상관 관계가 있습니까? XSLT 및 XPath 1.0은 구문 분석을 위해 전체 파일을 메모리에서 읽어야 하므로 대용량 XML 문서에서는 잘 확장되지 않는 경향이 있습니다.

  • 전략: 사전 목록이 Dataframe() 호출? 다음 흥미로운 답변을 참조하세요. generator 버전 및 iterwalk 사용자 정의 버전 . 두 업캐스트 목록은 모두 데이터 프레임입니다.

입력 데이터 (Stack Overflow의 현재 연도별 상위 사용자 , 팬더 친구들이 포함됨)

<? xml version="1.0" encoding="utf-8"?> <stackoverflow> <topusers> <user>Gordon Linoff</user> <link>http://www.stackoverflow.com//users /1144035/gordon-linoff 뉴욕, 미국 5,985 499,408</total_rep> 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, Austria</location> <year_rep>5,835</year_rep> ; <total_rep>154,4 39</total_rep> <tag1>angular2</tag1> <tag2>타입스크립트</tag2> <tag3>자바스크립트</tag3> </topusers> <topusers> <사용자>jezrael</user> <링크>http://www.stackoverflow.com//users/2901002/jezrael</link> <location>슬로바키아 브라티슬라바</location> <연도_렙>5,740</연도_렙> <total_rep>83,237</total_rep> <tag1>팬더</tag1> <tag2>파이썬</tag2> <tag3>데이터프레임</tag3> </topusers> <topusers> <사용자>VonC</user> <링크>http://www.stackoverflow.com//users/6309/vonc</link> <location>프랑스</location> <연도_렙>5,577</연도_렙> <total_rep>651,397</total_rep> <tag1>git</tag1> <tag2>github</tag2> <tag3>도커</tag3> </topusers> <topusers> <user>Martijn Pieters</user> <링크>http://www.stackoverflow.com//users/100297/martijn-pieters</link> <location>영국 케임브리지</location> <연도_렙>5,337</연도_렙> <total_rep>525,176</total_rep> <tag1>파이썬</tag1> <tag2>python-3.x</tag2> <tag3>python-2.7</tag3> </topusers> <topusers> <사용자>TJ Crowder</user> <링크>http://www.stackoverflow.com//users/157247/tj-crowder</link> <location>영국</location> <year_rep>5,258</year_rep> <total_rep>508,310</total_rep> <tag1>자바스크립트</tag1> <tag2>jquery</tag2> <tag3>자바</tag3> </topusers> <topusers> <user>akrun</user> <링크>http://www.stackoverflow.com//users/3732271/akrun</link> <위치></location> <연도_렙>5,188</연도_렙> <total_rep>229,553</total_rep> <tag1>r</tag1> <tag2>dplyr</tag2> <tag3>데이터프레임</tag3> </topusers> <topusers> <user>Wiktor Stribi?ew</user> <링크>http://www.stackoverflow.com//users/3832970/wiktor-stribi%c5%bcew</link> <location>폴란드 바르샤바</location> <연도_렙>4,948</연도_렙> <total_rep>158,134</total_rep> <tag1>정규식</tag1> <tag2>자바스크립트</tag2> <tag3>c#</tag3> </topusers> <topusers> <user>Darin Dimitrov</user> <링크>http://www.stackoverflow.com//users/29407/darin-dimitrov</link> <location>불가리아 소피아</location> <연도_렙>4,936</연도_렙> <total_rep>709,683</total_rep> <tag1>c#</tag1> <tag2>asp.net-mvc</tag2> <tag3>asp.net-mvc-3</tag3> </topusers> <topusers> <user>Eric Duminil</user> <링크>http://www.stackoverflow.com//users/6419007/eric-duminil</link> <위치></location> <연도_렙>4,854</연도_렙> <total_rep>12,557</total_rep> <tag1>루비</tag1> <tag2>루비온레일</tag2> <tag3>배열</tag3> </topusers> <topusers> <사용자>alecxe</user> <링크>http://www.stackoverflow.com//users/771848/alecxe</link> <location>미국 뉴욕</location> <연도_렙>4,723</연도_렙> <total_rep>233,368</total_rep> <tag1>파이썬</tag1> <tag2>셀레늄</tag2> <tag3>각도기</tag3> </topusers> <topusers> <user>Jean-Fran√ßois Fabre</user> <링크>http://www.stackoverflow.com//users/6451573/jean-fran%c3%a7ois-fabre</link> <location>프랑스 툴루즈</location> <연도_렙>4,526</연도_렙> <total_rep>30,027</total_rep> <tag1>파이썬</tag1> <tag2>python-3.x</tag2> <tag3>python-2.7</tag3> </topusers> <topusers> <사용자>piRSquared</user> <링크>http://www.stackoverflow.com//users/2336654/pirsquared</link> <location>미국 워싱턴주 벨뷰</location> <연도_렙>4,482</연도_렙> <total_rep>41,183</total_rep> <tag1>팬더</tag1> <tag2>파이썬</tag2> <tag3>데이터프레임</tag3> </topusers> <topusers> <사용자>CommonsWare</user> <링크>http://www.stackoverflow.com//users/115145/commonsware</link> <location>누가 알고 싶습니까?</location> <연도_렙>4,475</연도_렙> <total_rep>616,135</total_rep> <tag1>안드로이드</tag1> <tag2>자바</tag2> <tag3>android-intent</tag3> </topusers> <topusers> <사용자>쿠엔틴</user> <링크>http://www.stackoverflow.com//users/19068/quentin</link> <location>영국</location> <연도_렙>4,464</연도_렙> <total_rep>509,365</total_rep> <tag1>자바스크립트</tag1> <tag2>html</tag2> <tag3>css</tag3> </topusers> <topusers> <user>Jon Skeet</user> <링크>http://www.stackoverflow.com//users/22656/jon-skeet</link> <location>영국, 레딩</location> <연도_렙>4,348</연도_렙> <total_rep>921,690</total_rep> <tag1>c#</tag1> <tag2>자바</tag2> <tag3>.net</tag3> </topusers> <topusers> <user>Felix Kling</user> <링크>http://www.stackoverflow.com//users/218196/felix-kling</link> <location>미국 캘리포니아주 서니베일</location> <연도_렙>4,324</연도_렙> <total_rep>411,535</total_rep> <tag1>자바스크립트</tag1> <tag2>jquery</tag2> <tag3>비동기</tag3> </topusers> <topusers> <사용자>매트</user> <링크>http://www.stackoverflow.com//users/341994/matt</link> <위치></location> <연도_렙>4,313</연도_렙> <total_rep>220,515</total_rep> <tag1>swift</tag1> <tag2>ios</tag2> <tag3>xcode</tag3> </topusers> <topusers> <user>Psidom</user> <링크>http://www.stackoverflow.com//users/4983450/psidom</link> <location>미국 조지아주 애틀랜타</location> <연도_rep>4,236</연도_rep> <total_rep>36,950</total_rep> <tag1>파이썬</tag1> <tag2>판다</tag2> <tag3>r</tag3> </topusers> <topusers> <user>Martin R</user> <링크>http://www.stackoverflow.com//users/1187415/martin-r</link> <location>독일</location> <연도_렙>4,195</연도_렙> <total_rep>269,380</total_rep> <tag1>swift</tag1> <tag2>ios</tag2> <tag3>swift3</tag3> </topusers> <topusers> <user>Barmar</user> <링크>http://www.stackoverflow.com//users/1491895/barmar</link> <location>매사추세츠주 알링턴</location> <연도_rep>4,179</연도_rep> <total_rep>289,989</total_rep> <tag1>자바스크립트</tag1> <tag2>php</tag2> <tag3>jquery</tag3> </topusers> <topusers> <user>Alexey Mezenin</user> <링크>http://www.stackoverflow.com//users/1227923/alexey-mezenin</link> <위치>????????</location> <연도_렙>4,142</연도_렙> <total_rep>31,602</total_rep> <tag1>라라벨</tag1> <tag2>php</tag2> <tag3>laravel-5.3</tag3> </topusers> <topusers> <사용자>BalusC</user> <링크>http://www.stackoverflow.com//users/157882/balusc</link> <location>네덜란드 암스테르담</location> <연도_렙>4,046</연도_렙> <total_rep>703,046</total_rep> <tag1>자바</tag1> <tag2>jsf</tag2> <tag3>서블릿</tag3> </topusers> <topusers> <사용자>GurV</user> <링크>http://www.stackoverflow.com//users/6348498/gurv</link> <위치></location> <연도_렙>4,016</연도_렙> <total_rep>7,932</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>sql-server</tag3> </topusers> <topusers> <user>Nina Scholz</user> <링크>http://www.stackoverflow.com//users/1447675/nina-scholz</link> <location>독일 베를린</location> <연도_렙>3,950</연도_렙> <total_rep>61,135</total_rep> <tag1>자바스크립트</tag1> <tag2>배열</tag2> <tag3>객체</tag3> </topusers> <topusers> <유저>JB 니제</user> <링크>http://www.stackoverflow.com//users/571407/jb-nizet</link> <location>프랑스 생테티엔</location> <연도_렙>3,923</연도_렙> <total_rep>418,780</total_rep> <tag1>자바</tag1> <tag2> 최대 절전 모드</tag2> <tag3>java-8</tag3> </topusers> <topusers> <user>Frank van Puffelen</user> <링크>http://www.stackoverflow.com//users/209103/frank-van-puffelen</link> <location>캘리포니아주 샌프란시스코</location> <연도_렙>3,920</연도_렙> <total_rep>86,520</total_rep> <tag1>firebase</tag1> <tag2>firebase-database</tag2> <tag3>안드로이드</tag3> </topusers> <topusers> <user>dasblinkenlight</user> <링크>http://www.stackoverflow.com//users/335858/dasblinkenlight</link> <location>미국</location> <연도_렙>3,886</연도_렙> <total_rep>475,813</total_rep> <tag1>c#</tag1> <tag2>자바</tag2> <tag3>c++</tag3> </topusers> <topusers> <user>Tim Biegeleisen</user> <링크>http://www.stackoverflow.com//users/1863229/tim-biegeleisen</link> <location>싱가포르</location> <연도_렙>3,814</연도_렙> <total_rep>77,211</total_rep> <tag1>sql</tag1> <tag2>mysql</tag2> <tag3>자바</tag3> </topusers> <topusers> <user>Greg Hewgill</user> <링크>http://www.stackoverflow.com//users/893/greg-hewgill</link> <location>뉴질랜드 크라이스트처치</location> <연도_렙>3,796</연도_렙> <total_rep>529,137</total_rep> <tag1>git</tag1> <tag2>파이썬</tag2> <tag3>git-pull</tag3> </topusers> <topusers> <user>unutbu</user> <링크>http://www.stackoverflow.com//users/190597/unutbu</link> <위치></location> <연도_rep>3,735</연도_rep> <total_rep>401,595</total_rep> <tag1>파이썬</tag1> <tag2>판다</tag2> <tag3>numpy</tag3> </topusers> <topusers> <user>Hans Passant</user> <링크>http://www.stackoverflow.com//users/17034/hans-passant</link> <location>위스콘신주 매디슨</location> <연도_렙>3,688</연도_렙> <total_rep>672,118</total_rep> <tag1>c#</tag1> <tag2>.net</tag2> <tag3>winforms</tag3> </topusers> <topusers> <user>Jonathan Leffler</user> <링크>http://www.stackoverflow.com//users/15168/jonathan-leffler</link> <location>미국 캘리포니아</location> <연도_렙>3,649</연도_렙> <total_rep>455,157</total_rep> <tag1>c</tag1> <tag2>bash</tag2> <tag3>유닉스</tag3> </topusers> <topusers> <사용자>paxdiablo</user> <링크>http://www.stackoverflow.com//users/14860/paxdiablo</link> <위치></location> <연도_rep>3,636</연도_rep> <total_rep>507,043</total_rep> <tag1>c</tag1> <tag2>c++</tag2> <tag3>bash</tag3> </topusers> <topusers> <user>Pranav C Balan</user> <링크>http://www.stackoverflow.com//users/3037257/pranav-c-balan</link> <location>Ramanthali, Kannur, Kerala, India</location> <연도_렙>3,604</연도_렙> <total_rep>64,476</total_rep> <tag1>자바스크립트</tag1> <tag2>jquery</tag2> <tag3>html</tag3> </topusers> <topusers> <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> </topusers> </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 및 len(inner) != 0: data.append(inner) inner = {} if el.text가 None이 아니고 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") 데이터 = [] 내부 = {} 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("입력.xml") xslstr = """ <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 버전="1.0"> <xsl:출력 버전="1.0" 인코딩= "UTF-8" indent="yes" method="text"/> <xsl:strip-space elements="*"/> <!-- HEADERS --> <xsl:템플릿 일치 = "/*"> <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;,& </xsl:text> </xsl:언제> <xsl:그렇지 않으면> <xsl:text>&quot;&#xa;</xsl:text> </xsl:그렇지 않으면> </xsl:선택> </xsl:for-each> </xsl:템플릿> </xsl:변환> """ xsl = lxet.fromstring(xslstr) 변환 = lxet.XSLT(xsl) newdom = transform(xml) df = pd.read_csv(StringIO(str(newdom))) 

타이밍 (현재 XML 및 XML의 25배 하위 항목 포함(예: StackOverflow 사용자 레코드 900개)

# SHORTER FILE python -mtimeit -s"readxml_test_runs를 테스트로 가져오기" "test.read_xml_iterfind()" 루프 100개, 최고 3: 루프당 3.87msec python -mtimeit -s"readxml_test_runs를 테스트로 가져오기" "test.read_xml_iterparse()" 루프 100개, 최고 : 루프당 5.5 msec python -mtimeit -s" readxml_test_runs as test" "test.read_xml_lxml_xpath()" 100개 루프, 최고 3개: 루프당 3.86 msec python -mtimeit -s"import readxml_test_runs as test" "test.read )" 100개 루프, 3개 중 최고: 루프당 5.68msec # 더 큰 파일 python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_iterfind()" 100개 루프, 최고 3개: 루프당 36msec python -mtimeit -n"100" -s" readxml_test_runs를 테스트로 가져오기" "test.read_xml_i terparse()" 100개 루프, 최고 3개: 루프당 78.9msec python -mtimeit -n"100" -s"import readxml_test_runs as test" "test.read_xml_lxml_xpath()" 100개 루프, 최고 3개: 루프당 32.7onsec -mtimeit -n"100" -s" readxml_test_runs를 테스트로 가져오기" "test.read_xml_lxml_xsl()" 100개 루프, 3개 중 최고: 루프당 51.4msec