2017-08-10 2 views
1

Vielleicht eine einfache Frage für einige von Ihnen.Python Pandas: Verwenden Sie Kartenfunktion auf Iterator

Ich analysiere einen XML-Baum, der eine ziemlich komplexe und verschachtelte Struktur hat. Dies ist Teil des Codes:

import xml.etree.ElementTree as ET 
import pandas as pd 
from bs4 import BeautifulSoup as BS 

tree = ET.parse('input_data.xml') 
root = tree.getroot() 

for unit in root.iter('xml_element_name'): 
    # do something with the unit 

Aber ich mochte die für jede Iteration-loszuwerden, da ich eine Map-Funktion verwenden möchte (zB Pandas.Series.map oder Pandas.Dataframe.map oder Ähnliches). Also das ist Pseudo-Code, den ich gerne erreichen möchte:

items = pd.Series(root.iter('xml_element_name')) 
df = pd.Dataframe(items.map(lambda unit: ....)) 

Aber wie? Irgendeine Idee?

PS: Ein Beispiel XML kann in der tutorial of the ElementTree gefunden werden.

Warum möchte ich dies tun? Da ich später zu PySpark wechseln möchte, wird jedes XMLElement (Unit) parallel behandelt.

Antwort

1

Sie können versuchen, eine flache Datenstruktur aus dem Iterator erstellen über:

flat_list = list(root.iter()) 

und dann ein Datenrahmen aus ihm heraus zu erstellen.

Hier ist der vollständige Code-Schnipsel:

import xml.etree.ElementTree as ET 
import pandas as pd 
from bs4 import BeautifulSoup as BS 
import pdb 

tree = ET.parse('cd_catalog.xml') 
root = tree.getroot() 

flat_list = list(root.iter()) 
df  = pd.DataFrame({'xml_elements':flat_list}) 

# do some arbitrary computation on the df: 
result = df.xml_elements.map(lambda x: x.text) 
print(result.head(n=3)) 

(Link zum xml file)

+0

Das funktioniert . Auch wenn es sinnvoll ist, das erste Element (Hierarchie) bereits beim ersten Lauf zu teilen. Das bedeutet, dass Sie mehr als eine Spalte beim Aufruf von root.iter() erhalten könnten, wodurch Sie entweder ein Wörterbuch oder eine Reihe erstellen würden. – Matthias

1

Nichts entschuldigt die Struktur des Dokuments, das Sie analysieren. Mit Ihrem Beispiel, auf das Sie verwiesen haben, können Sie eine Kombination aus einer Liste und Wörterbuchkompromittierungen verwenden, um etwas an den Konstruktor pd.DataFrame zu übergeben.

Hoffentlich gibt Ihnen und Idee

pd.DataFrame([ 
    {a.tag: a.text for a in c if a.tag != 'neighbor'} 
    for c in root.findall('country') 
]) 

    gdppc rank year 
0 141100 1 2008 
1 59900 4 2011 
2 13600 68 2011 
+0

Keine einfache Code. Vor allem der Konstruktor des Datenrahmens, den Sie verwendet haben. Aber ich verstehe, denke ich. Anmerkung: Das XML, das ich analysiere, ist ein bisschen komplexer. Übrigens: Ihr Code verwendet immer noch for-each im Konstruktor. – Matthias

+0

@Matthias, aber in der Regel scheint die Verständigung schneller zu sein. Im gleichen Sinne ist auch "Karte". – piRSquared

+0

Ich habe Ihren Code verwendet, während der andere oben funktioniert. 'df = pd.DataFrame ([(child.tag, child.attrib) für child in root.iter ('country')])' und 'df.columns = ['tag', 'attributes']' – Matthias

Verwandte Themen