2017-11-30 14 views
1

私は多少大きめの.xlsxファイルを持っています - 19列、5185行。ファイルを開き、すべての値を1つの列に読み込み、それらの値にいくつかの要素を加えて、同じブックに新しい列を作成して、変更した値を書き出したいとします。したがって、私は同じファイルに読み書きすることができる必要があります。openpyxlの読み取り専用ワークブックの列を繰り返します。

私の元のコードは、これをしなかった:ワークブックがあまりにも大きかったので、

def readExcel(doc): 
    wb = load_workbook(generalpath + exppath + doc) 
    ws = wb["Sheet1"] 

    # iterate through the columns to find the correct one 
    for col in ws.iter_cols(min_row=1, max_row=1): 
     for mycell in col: 
      if mycell.value == "PerceivedSound.RESP": 
       origCol = mycell.column 

    # get the column letter for the first empty column to output the new values 
    newCol = utils.get_column_letter(ws.max_column+1) 

    # iterate through the rows to get the value from the original column, 
    # do something to that value, and output it in the new column 
    for myrow in range(2, ws.max_row+1): 
     myrow = str(myrow) 
     # do some stuff to make the new value 
     cleanedResp = doStuff(ws[origCol + myrow].value) 
     ws[newCol + myrow] = cleanedResp 

    wb.save(doc) 

しかし、Pythonは行3853の後にメモリエラーを投げました。 openpyxlのドキュメントは、大きなワークブックを処理するために読み取り専用モード(https://openpyxl.readthedocs.io/en/latest/optimized.html)を使用すると述べています。私は今それを使用しようとしています。しかし、私はREAD_ONLY =真のparamを追加するとき、列を反復処理する方法はないように思える:

def readExcel(doc): 
    wb = load_workbook(generalpath + exppath + doc, read_only=True) 
    ws = wb["Sheet1"] 

    for col in ws.iter_cols(min_row=1, max_row=1): 
     #etc. 

Pythonは、このエラーがスローされます。 はAttributeError:「ReadOnlyWorksheet」オブジェクトが無属性「iter_cols」

を持っています

私は上記のスニペットの最後の行を変更した場合: 時:

for col in ws.columns: 

のpythonは、同じエラーがスローされますtributeError: 'ReadOnlyWorksheet' オブジェクトが行に対して何ら属性 '列'

反復処理が細かいしていない(と私は上記のリンク先のドキュメントに含まれています):

for col in ws.rows: 

(エラーなし)

はAttritubeErrorについて尋ねますが、解決策は読み取り専用モードを削除することです。これはopenpyxlが読み取り専用モードではなくブック全体を読み取らないため、私にとっては機能しません。

So:大きなブックの列をどのように反復処理しますか?

私はまだこれに遭遇していませんが、一度、私は列を繰り返すことができます:同じブックを読み書きするにはどうしたらいいですか?

ありがとうございます!

答えて

0

documentationによると、ReadOnlyモードは行ベースの読み取りのみをサポートしています(列読み取りは実装されていません)。しかし、それは解決することは難しいことではありません。

wb2 = Workbook(write_only=True) 
ws2 = wb2.create_sheet() 

# find what column I need 
colcounter = 0 
for row in ws.rows: 
    for cell in row: 
     if cell.value == "PerceivedSound.RESP": 
      break 
     colcounter += 1 

    # cells are apparently linked to the parent workbook meta 
    # this will retain only values; you'll need custom 
    # row constructor if you want to retain more 

    row2 = [cell.value for cell in row] 
    ws2.append(row2) # preserve the first row in the new file 

break 

for row in ws.rows: 
    row2 = [cell.value for cell in row] 
    row2.append(doStuff(row2[colcounter])) 
    ws2.append(row2) # write a new row to the new wb 

wb2.save('newfile.xlsx') 
wb.close() 
wb2.close() 

# copy `newfile.xlsx` to `generalpath + exppath + doc` 
# Either using os.system,subprocess.popen, or shutil.copy2() 

あなたが同じブックへの書き込みができませんが、上記のようにあなたは、(書き込み専用モードで)新しいブックを開き、それに書き込み、古いを上書きすることができますOSコピーを使用してください。

+0

異なるワークブック間でセルオブジェクトを渡すことができないため、これは機能しません。 –

+0

'row = [cell.value for cell in row]'のような行を使って行を直列化できますか? – cowbert

+0

確かに、これは書式設定、コメントなどを失うことを忘れないでください。 –

0

ワークシートのセル数が約100,000個の場合、メモリに問題はありません。あなたはこれをさらに調査すべきでしょう。

iter_cols()は、読み取り専用モードでは使用できません。これは、基本となるXMLファイルの定数が非常に非効率的に再解析されるためです。ただし、行をiter_rows()からzipを使用して列に変換するのは比較的簡単です。

+0

これは私にとって巨大なワークブックのようなものではなかったので、最初はメモリエラーが発生したときに驚きました。しかしそれにもかかわらず、それはしました。さらに調査することをどのように示唆していますか? – Jona

+0

あなたはPythonプロセスが使用しているメモリの量とブックにあるものを調べる必要があります。ファイルがなければ、私はそれ以上のことは言えません。 –

+0

上記のコード全体を投稿しました。あなたが見ることができるように、そこにはメモリが集中しているということはあまりありません。 「ほかに何が入っているの?」というのは、セル内にテキスト(および整数)を含む単なるブックです。数式、参照、任意のセルには巨大な量のテキストはなく、ワークシート内で何も計算されません。参加者のデータであるためファイルを共有できませんが、探している方向に私を向けることができればさらに喜んでできます! – Jona

関連する問題