2017-07-03 3 views
0
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
    <document DateTime="2017-06-23T04:27:08.592Z"> 
     <PeakInfo No="1" mz="505.2315648572003965" 
       Intensity="4531.0000000000000000" 
       Rel_Intensity="3.2737729673489735" 
       Resolution="1879.5638812957554364" 
       SNR="14.0278637770897561" 
       Area="1348.1007591467391649" 
       Rel_Area="2.3371194184605959" 
       Index="238.9999999999976694"/> 
     <PeakInfo No="2" mz="522.1330917856538463" 
       Intensity="3382.0000000000000000" 
       Rel_Intensity="2.4435886505350317" 
       Resolution="3502.9921209527169594" 
       SNR="10.4705882352940982" 
       Area="881.4468100654634100" 
       Rel_Area="1.5281101521284057" 
       Index="925.0000000000000000"/> 
    </document> 

Oben ist ein Teil einer XML-Datei, mit der ich in letzter Zeit gearbeitet habe. Jede Datei enthält mehr als 400 PeakInfo ist, und ich habe ein Python-Skript machen jede Datei zu analysieren:Beschleunigung des XML-Parsing-Prozesses mit lxml und xpath

from lxml import etree 
import pandas as pd 
import tkinter.filedialog 
import os 
import pandas.io.formats.excel 

full_path = tkinter.filedialog.askdirectory(initialdir='.') 
newfolder = full_path+'\\xls files' 
os.chdir(full_path) 
os.makedirs(newfolder) 

data = {} 
for files in os.listdir(full_path): 
     if os.path.isfile(os.path.join(full_path, files)): 
      plist = pd.DataFrame() 
      filename = os.path.basename(files).rpartition('.')[0] 

      if len(filename) == 2: 
       filename = filename[:1]+'0'+filename[1:] 

      xmlp = etree.parse(files) 
      for p in xmlp.xpath('//PeakInfo'): 
       data['Exp. m/z'] = p.attrib['mz'] 
       data['Intensity'] = p.attrib['Intensity'] 
       plist = plist.append(data, ignore_index=True) 
       plist['Exp. m/z'] = plist['Exp. m/z'].astype(float) 
       plist['Exp. m/z'] = plist['Exp. m/z'].map('{:.4f}'.format) 
       plist['Intensity'] = plist['Intensity'].astype(float) 
       plist['Intensity'] = plist['Intensity'].map('{:.0f}'.format) 
       pandas.io.formats.excel.header_style = None 
       plist.to_excel(os.path.join(newfolder, filename+'.xls'),index=False) 

Dieser Code ändert den Dateinamen, wenn es nur zwei Zeichen (dh A1 bis A01) hat, und dann zieht mz und Intensität und speichern Sie als xls Dateien. Das Problem besteht darin, dass das Parsen jeder Datei zu lange dauert. Gibt es einen Tipp, den Prozess deutlich zu beschleunigen?

+0

Dies ist das schlechteste Szenario, um mit 'pandas' zu arbeiten. Verwenden Sie einen XML-Parser und schreiben Sie mit einem 'xlsx-Paket 'nach Excel. – stovfl

+0

@stovfl was meinst du mit xlsx paket? meinst du openpyxl oder sowas? –

+0

Ja, 'openpyxl' zum Beispiel kann direkt in' xlsx' schreiben. – stovfl

Antwort

1
from lxml import etree 
import pandas as pd 
import tkinter.filedialog 
import os 
import pandas.io.formats.excel 

full_path = tkinter.filedialog.askdirectory(initialdir='.') 
newfolder = full_path+'\\xls files' 
os.chdir(full_path) 
os.makedirs(newfolder) 

data = {} 
for files in os.listdir(full_path): 
     if os.path.isfile(os.path.join(full_path, files)): 
      plist = pd.DataFrame() 
      filename = os.path.basename(files).rpartition('.')[0] 

      if len(filename) == 2: 
       filename = filename[:1]+'0'+filename[1:] 

      xmlp = etree.parse(files) 
      for p in xmlp.xpath('//PeakInfo'): 
       data['Exp. m/z'] = p.attrib['mz'] 
       data['Intensity'] = p.attrib['Intensity'] 
       plist = plist.append(data, ignore_index=True) 
plist['Exp. m/z'] = plist['Exp. m/z'].astype(float) 
plist['Exp. m/z'] = plist['Exp. m/z'].map('{:.4f}'.format) 
plist['Intensity'] = plist['Intensity'].astype(float) 
plist['Intensity'] = plist['Intensity'].map('{:.0f}'.format) 
pandas.io.formats.excel.header_style = None 
plist.to_excel(os.path.join(newfolder, filename+'.xls'),index=False) 

nur den Raum zu ändern, Sie wie to_excel ausführen zu viele Zeit-Code, und es ist langsam, und „AsType“ wird Element kopieren und zu viel Speicher dann die Geschwindigkeit verlangsamen.

+0

Aus irgendeinem Grund dachte ich, ich brauche die exportierenden Zeilen innerhalb der for-Schleife. Einfach den Abstand zu ändern scheint viel besser zu funktionieren. Vielen Dank! –

+0

IO ist eine sehr langsame Operation, also nächstes Mal genauer betrachten. @ BongKyoSeo – obgnaw

0

könnten Sie versuchen, C Implementierung von ElementTree http://effbot.org/zone/celementtree.htm

Nach dem doc

celementtree ist 15-20 mal schneller als die Python-Version von ElementTree verwenden, und verwendet 2-5-mal weniger Speicher .

+0

OP verwendet bereits 'lxml', nicht die stdlib ElementTree. (Siehe http://lxml.de/performance.html) – AKX

+0

Das Ändern von 'import xml.etree.ElementTree als ET' in' import xml.etree.cElementTree als ET' scheint die Geschwindigkeit für mich nicht zu verbessern. Jede XML-Datei hat ungefähr 5000 Datenpunkte und mein Code holt ~ 1000 Datenpunkte heraus und speichert sie als xls-Datei. –