2016-03-26 21 views
2

Ich habe einige riesige Excel-Dateien, aber ich bin sogar mit einem "bescheidenen" (50 MB) behaftet. Ich muss die ersten beiden Zeilen überspringen, aber ich denke nicht, dass das die Verlangsamung ist. Kannst du an etwas anderes denken?openpyxl readonly use_iterators

wb = load_workbook(MyFile,read_only=True) 
ws = wb.active 

NDepth = ws.max_row-2 
NTime = ws.max_column -1 

Local_Depth = np.zeros((NDepth,)) 
Local_Temp = np.zeros((NDepth,NTime)) 

iterlist = islice(ws.iter_rows(),2,None) 

start = time.time() 

i=0 
for row in iterlist: 
    Local_Depth[i] = row[0].value 
    j=0 
    for col in row[1:]: 
     Local_Temp[i,j] = col.value 
     j += 1 
    i += 1 

print "Done", time.time()-start 

Es dauert länger als 7 Minuten, um die Datei auf einem M4700 Dell Precision zu laden. Etwa 8000 Zeilen und 800 Spalten. Sicherlich muss etwas falsch sein? Könnte es irgendwo andere Verbesserungen geben, die ich in meinem Python 2.7-Setup machen sollte?

Danke, John

+0

Es hängt davon ab, was werden Sie mit den Daten zu tun, die Sie von dieser Excel-Datei lesen ... Ich persönlich würde dafür verwenden Pandas Modul - es ist sehr einfach und verwendet innen sehr schöne und schnelle Algorithmen – MaxU

+0

7 * 60/(8000 * 800) ~ = 0,066 Millisekunden/Zelle, die nicht zu schlecht scheint. –

+0

Haben Sie versucht, den Code ohne Iteratoren auszuführen, d. H. 'Use_iterators = False'? –

Antwort

0

Ich würde Pandas für diese Aufgabe versuchen. Es ist sehr einfach und gibt dir viel Kraft.

Hier ist ein kleines Beispiel:

import time 
import numpy as np 
import pandas as pd 

# let's generate some sample data (8000 rows, 800 columns) 
data = np.random.randint(0, 100, (8000, 800)) 

# let's generate column names from 'col001' to 'col800' 
cols = ['col{0:02d}'.format(i) for i in range(1,801)] 

# generating Pandas data frame from numpy array 
df = pd.DataFrame(data, columns=cols) 

# write generated DF (Data Frame) to Excel file 
df.to_excel(r'd:/temp/sample.xlsx', index=False) 
# we are done with sample data 

##################################################################### 
# 
# interesting part starts here ... 
# 
##################################################################### 

start = time.time() 

# read up the Excel file (skipping first two rows) 
df = pd.read_excel(r'd:/temp/sample.xlsx', skiprows=2) 

print "Done", time.time()-start 

# print the shape of out DF 
print(df.shape) 

Output (von ipython, auf meinem Heim-Notebook es ca. dauerte 2 Minuten.):

In [24]: %paste 
start = time.time() 

# read up the Excel file 
df = pd.read_excel(r'd:/temp/sample.xlsx', skiprows=2) 

print "Done", time.time()-start 
## -- End pasted text -- 
Done 124.375999928 

In [25]: 

In [25]: df.shape 
Out[25]: (7998, 800) 

In [26]: # print the shape of out DF 

In [27]: print(df.shape) 
(7998, 800) 

Jetzt können Sie alle Ihre Daten im Speicher als Standard ein DF und kann es sehr komfortabel mit allen Pandas Leistung verarbeiten

PS müssten Sie die folgenden Python-Module installieren:

  • numpy
  • Pandas
  • xlrd
  • openpyxl oder XlsxWriter (oder beide)
+0

Leistung beim Lesen großer Excel-Dateien ist sehr ähnlich für openpyxl und xlrd (das ist, was Pandas intern zum Lesen verwendet). In beiden Fällen muss Pandas, da die Daten Zeile für Zeile gespeichert werden, die Zeilen in Spalten konvertieren, bevor sie überhaupt etwas tun können. Für eine einfache Operation wird das also nicht schneller laufen. Natürlich sind Pandas schneller für aggregierte Operationen. –

-1

Wenn ich als nehmen gegeben, dass die Excel-Datei ein rechteckiges Blatt ist dann habe ich eine enorme Geschwindigkeit bekommen indem du einfach direkt zu ZIP gehst. Attached ist ein Teil des Codes für den Generator, der eine Reihe von Zeilen zurückgibt, die ich dann analysieren kann, um in jeder Zeile nach den tatsächlichen Werten zwischen <v> und </v> zu suchen. Ich habe nicht versucht, das hübsch zu machen - es sieht sehr unpythonisch aus.

def rowList(): 
with zipfile.ZipFile('MyFile.xlsx', mode='r') as z: 
    with z.open('xl/worksheets/sheet1.xml', 'r') as f: 
     irow =-1 
     while irow <0: 
      hstring = f.read(50000) 
      if hstring == "": 
       break; 
      irow = hstring.find("sheetData") 
     if irow < 0: 
      return 
     ist = hstring.find("<dimension") 
     string = hstring[ist+16: ist+50] 
     itl = string.find("/>") 
     yield string[:itl-1] 
     string = hstring[irow+10:] 
     while True: 
      irow = string.find("</row>") 
      while irow<0: 
       hstring = f.read(50000) 
       if hstring == "": 
        break; 
       string += hstring 
       irow = string.find("</row>") 
      if irow < 0: 
       return 
      irow +=6 
      ist = string.find("<c") 
      yield string[ist:irow-6] 
      string = string[irow:] 

Lässt die Berechnungszeit von Minuten auf Sekunden fallen.

Das lässt mich fragen, ob es etwas Ähnliches gibt, das für openpyxl in Betracht gezogen wird - ein Parameter, der ihm sagt, dass er eine sehr flache Datei öffnet.

+0

Während xlsx-Dateien immer zip-Archive sind, ist dieser Ansatz extrem unflexibel und fehleranfällig. Zum Beispiel ist es sehr wahrscheinlich, dass das Dimensions-Tag fehlt. Aus diesem Grund müssen Sie eine Art XML-Bibliothek zum Lesen der Quelle verwenden. Wie sich herausstellt, ist Itersparse sehr schnell. Ich vermute, dass der Geschwindigkeitsunterschied, den Sie beobachten, durch etwas völlig anderes verursacht wird. –

+0

Werfen in den Parsing für Spalten ... bekommt mich 105 Sekunden für die volle Datenlast. Nicht so schnell wie das Panda-Beispiel darunter. Ich stimme zu, dass dieser Hack nicht der richtige Weg sein sollte, aber er hilft vielleicht, den Engpass zu klären. Openpyx hat die Dimensionen schnell gefunden. Ich hatte die Tunneller

+0

Wenn Sie eine Profilerstellung ausführen, sehen Sie, dass die Zeit für das Konvertieren des Zeichenfolgenwerts der Zelle in den entsprechenden Python-Wert (Zahl, Boolean, Datetime, String oder Formel) verwendet wird. Mit dem Instanziieren von Zellenobjekten, die ein benutzerdefinierter Parser vermeiden könnte, sind einige Gemeinkosten verbunden. Aber Pypy sollte Ihnen den besten Schub geben. –

0

Ich bin bis auf 22 Sekunden

import numpy as np 
import time 
from openpyxl import Workbook 
from openpyxl import load_workbook 
import zipfile 


def rowList(fullfilename): 
with zipfile.ZipFile(fullfilename, mode='r') as z: 
    with z.open('xl/worksheets/sheet1.xml', 'r') as f: 
     irow =-1 
     while irow <0: 
      hstring = f.read(50000) 
      if hstring == "": 
       break; 
      irow = hstring.find("sheetData") 
      if irow < 0: 
       return 
     string = hstring[irow+10:] 
     while True: 
      irow = string.find("</row>") 
      while irow<0: 
       hstring = f.read(50000) 
       if hstring == "": 
        break; 
       string += hstring 
       irow = string.find("</row>") 
      if irow < 0: 
       return 
      irow +=6 
      ist = string.find("<c") 
      yield string[ist:irow-6] 
      string = string[irow:] 


def splitRow(func,row): 

j = 0 
c1 = row.find("<v") 
c2 = 0 
while c1 > 0: 
    c1 += c2 + 3 
    c2 = c1 + row[c1:].find("</v") 
    yield func(row[c1:c2]) 
    j += 1 
    c2 += 3 
    c1 = row[c2:].find("<v") 


start = time.time() 

wb = load_workbook(MyFile,read_only=True, use_iterators=True) 
ws = wb.active 
NDepth = ws.max_row-2 
NTime = ws.max_column -1 
wb._archive.close() 

Local_Store = np.empty((NDepth,NTime+1)) 
Local_Time = np.empty((NTime,)) 

print NDepth, NTime 
print "Data Accessed via Iterators", time.time()-start 

start = time.time() 

print "About to call RowList" 

i = -2 
j = 1 
for row in rowList(MyFile): 
if i == -2: 
    True 
else: 
    if i == -1: 
     Local_Time[:] = list(splitRow(float,row)) 
    else: 
     Local_Store[i,:] = list(splitRow(float,row)) 

i += 1 

print i, "Rows Parsed", time.time()-start 
+0

Um die Zeile zu analysieren, habe ich versucht \t \t root = ET.fromstring (Zeile); Meine Liste = root.itertext(); floaty = map (float, mylist) aber es ging wieder langsamer zurück als ein Hund. Der Aufruf an OpenPyXL, Abmessungen zu erhalten, war knapp eine Hundertstelsekunde. – Tunneller