2014-09-27 9 views
9

Czy ktoś ma sugestię, jak najlepiej otworzyć dane xml na poniższej stronie, aby umieścić go w ramce danych (preferuję pracę z pandami) w pythonie? Plik znajduje się na „dane - XML ​​(SDMX/zip)” link na tej stronie:Jak otworzyć ten plik XML, aby utworzyć ramkę danych w języku Python?

http://www.federalreserve.gov/pubs/feds/2006/200628/200628abs.html

Próbowałem przy użyciu następujących kopiując z http://timhomelab.blogspot.com/2014/01/how-to-read-xml-file-into-dataframe.html i wydaje się, jestem coraz bliżej:

from lxml import objectify 
import pandas as pd 

path = 'feds200628.xml' 
xml = objectify.parse(open(path)) 
root = xml.getroot() 
root.getchildren()[0].getchildren() 
df = pd.DataFrame(columns=('id', 'name')) 

for i in range(0,4): 
    obj = root.getchildren()[i].getchildren() 
    row = dict(zip(['id', 'name'], [obj[0].text, obj[1].text])) 
    row_s = pd.Series(row) 
    row_s.name = i 
    df = df.append(row_s) 

Nadal nie wiem wystarczająco dużo o xml, aby dostać mi resztę drogi.

Każda pomoc byłaby niesamowita - nie potrzebuję nawet potrzebować, aby być w ramce danych, po prostu muszę wymyślić jak przetworzyć tę zawartość w python.

+0

Możliwy duplikat [Jak mogę otworzyć plik Excela w Pythonie?] (Http://stackoverflow.com/questions/3239207/how-can-i-open-an-excel-file-in-python) – poolie

Odpowiedz

6

Wyeksportowałbym plik XLS formatted file do pliku CSV (za pomocą bezpłatnego programu, takiego jak Gnumeric lub LibreOffice, lub jeśli go masz, Excel), a następnie odczytaj plik CSV na pandy. Wiem, że to nie jest dokładnie odpowiedź na twoje ostatnie pytanie, ale parsowanie XML jest zbyt skomplikowanym rozwiązaniem tego, co próbujesz zrobić.

Jeśli chodzi o parsowanie XML w Pythonie, biblioteką lxml jest moja ulubiona biblioteka. Uważam, że używanie języka zapytań XPath wraz z parserem lxml to najlepsza trasa.

8

XML jest strukturą przypominającą drzewo, podczas gdy Pandas DataFrame jest strukturą przypominającą tabelę 2D. Więc nie ma automatycznego sposobu na konwersję między tymi dwoma. Musisz zrozumieć strukturę XML i wiedzieć, jak chcesz zmapować swoje dane na tabelę 2D. Tak więc każdy problem XML-to-DataFrame jest inny.

Twój XML ma 2 zestawy danych, z których każdy zawiera serię. Każda Seria zawiera wiele elementów Obs.

Każda seria ma atrybut NAME, a każdy z atrybutów Obs ma OBS_STATUS, TIME_PERIOD i OBS_VALUE. Być może rozsądnie byłoby utworzyć tabelę z kolumnami NAME, OBS_STATUS, TIME_PERIOD i OBS_VALUE.

Znalazłem wyciągając pożądane dane z XMLa nieco skomplikowane, co sprawia, że ​​wątpię, że znalazłem najlepszy sposób to zrobić. Ale tutaj jest jeden sposób (PS pomysł Thomasa Maloney z dnia począwszy od tabelarycznego danych XLS 2D powinny być sposób prostszy.):

import lxml.etree as ET 
import pandas as pd 

path = 'feds200628.xml' 

def fast_iter(context, func, *args, **kwargs): 
    """ 
    http://lxml.de/parsing.html#modifying-the-tree 
    Based on Liza Daly's fast_iter 
    http://www.ibm.com/developerworks/xml/library/x-hiperfparse/ 
    See also http://effbot.org/zone/element-iterparse.htm 
    http://stackoverflow.com/a/7171543/190597 (unutbu) 
    """ 
    for event, elem in context: 
     func(elem, *args, **kwargs) 
     # It's safe to call clear() here because no descendants will be 
     # accessed 
     elem.clear() 
     # Also eliminate now-empty references from the root node to elem 
     for ancestor in elem.xpath('ancestor-or-self::*'): 
      while ancestor.getprevious() is not None: 
       del ancestor.getparent()[0] 
    del context 

data = list() 
obs_keys = ['OBS_STATUS', 'TIME_PERIOD', 'OBS_VALUE'] 
columns = ['NAME'] + obs_keys 

def process_obs(elem, name): 
    dct = elem.attrib 
    # print(dct) 
    data.append([name] + [dct[key] for key in obs_keys]) 

def process_series(elem): 
    dct = elem.attrib 
    # print(dct) 
    context = ET.iterwalk(
     elem, events=('end',), 
     tag='{http://www.federalreserve.gov/structure/compact/common}Obs' 
     ) 
    fast_iter(context, process_obs, dct['SERIES_NAME']) 

def process_dataset(elem): 
    nsmap = elem.nsmap 
    # print(nsmap) 
    context = ET.iterwalk(
     elem, events=('end',), 
     tag='{{{prefix}}}Series'.format(prefix=elem.nsmap['kf']) 
     ) 
    fast_iter(context, process_series) 

with open(path, 'rb') as f: 
    context = ET.iterparse(
     f, events=('end',), 
     tag='{http://www.federalreserve.gov/structure/compact/common}DataSet' 
     ) 
    fast_iter(context, process_dataset) 
    df = pd.DataFrame(data, columns=columns) 

plony

  NAME OBS_STATUS TIME_PERIOD OBS_VALUE 
0  SVENY01   A 1961-06-14  2.9825 
1  SVENY01   A 1961-06-15  2.9941 
2  SVENY01   A 1961-06-16  3.0012 
3  SVENY01   A 1961-06-19  2.9949 
4  SVENY01   A 1961-06-20  2.9833 
5  SVENY01   A 1961-06-21  2.9993 
6  SVENY01   A 1961-06-22  2.9837 
... 
1029410  TAU2   A 2014-09-19 3.72896779 
1029411  TAU2   A 2014-09-22 3.12836171 
1029412  TAU2   A 2014-09-23 3.20146575 
1029413  TAU2   A 2014-09-24 3.29972110 
-1

Ten kod to działa przekształcić df tego typu Excel pliku XML:

import pandas as pd 
from xml.sax import ContentHandler, parse 

# Reference https://goo.gl/KaOBG3 
class ExcelHandler(ContentHandler): 
    def __init__(self): 
     self.chars = [ ] 
     self.cells = [ ] 
     self.rows = [ ] 
     self.tables = [ ] 
    def characters(self, content): 
     self.chars.append(content) 
    def startElement(self, name, atts): 
     if name=="Cell": 
      self.chars = [ ] 
     elif name=="Row": 
      self.cells=[ ] 
     elif name=="Table": 
      self.rows = [ ] 
    def endElement(self, name): 
     if name=="Cell": 
      self.cells.append(''.join(self.chars)) 
     elif name=="Row": 
      self.rows.append(self.cells) 
     elif name=="Table": 
      self.tables.append(self.rows) 

excelHandler = ExcelHandler() 
parse('feds200628.xls', excelHandler) 
df1 = pd.DataFrame(excelHandler.tables[0][10:], columns=excelHandler.tables[0][9]) 
print df1.head() 

nie mogę zrobić komentarz (o niskiej reputacji), ale odpowiedź na to pytanie o „How to open Excel XML file programmatically” (z Python i pandy) powinno działać.

+0

To nie daje odpowiedzi na pytanie. Aby skrytykować lub poprosić o wyjaśnienie od autora, zostaw komentarz pod swoim postem - zawsze możesz komentować swoje posty, a gdy już masz wystarczającą [reputację] (http://stackoverflow.com/help/whats-reputation), być w stanie [komentować dowolny wpis] (http://stackoverflow.com/help/privileges/comment). – UmNyobe

+0

@UmNyobe Ok, dodałem kod. Właśnie zmieniłem nazwę pliku i numer wiersza, w którym rozpoczynają się dane. – jrovegno

Powiązane problemy