2016-05-31 1 views
2

大きなxlsファイルに大きな問題があります。私のアプリが新しい統計レコード(ファイルの最後に新しい行)を追加すると、非常に長い時間(1分)があります。空のxlsファイルで置き換えると、この作業は最高です(1-2秒)。だから可能ならばこれを最適化しようとしている。xlwtでxlsファイルの行を最適化

私のようなものを使用します。

def add_stats_record(): 
    # Add record 
    lock = LockFile(STATS_FILE) 
    with lock: 
     # Open for read 
     rb = open_workbook(STATS_FILE, formatting_info=True) 
     sheet_records = rb.sheet_by_index(0) 

     # record_id 
     START_ROW = sheet_records.nrows 
     try: 
      record_id = int(sheet_records.cell(START_ROW - 1, 0).value) + 1 
     except: 
      record_id = 1 

     # Open for write 
     wb = copy(rb) 
     sheet_records = wb.get_sheet(0) 

     # Set normal style 
     style_normal = xlwt.XFStyle() 
     normal_font = xlwt.Font() 
     style_normal.font = normal_font 

     # Prepare some data here 
     ........................ 
     # then: 

     for i, col in enumerate(SHEET_RECORDS_COLS): 
      sheet_records.write(START_ROW, i, possible_values.get(col[0], ''), 
           style_normal) 

     wb.save(STATS_FILE) 

をあなたがここに改善するために何かを参照していますか?または、私によりよいアイデアを与えることができますか/これを行う方法の例?

+0

おかげで、Ionică。ソリューションがなければ、csvファイルなどを使用して機能を再実装する必要があるため、ここのソリューションは重要です。 – GhitaB

+0

さらに詳しい情報を教えていただけますか? Excelシートのおおよそのサイズは?どのようなデータですか? –

+0

30000-40000行。シンプルテキスト:文字列と数字。 – GhitaB

答えて

3

あなたが聞きたい答えはありませんが、最適化することはほとんどありません。開口部のための時間を経過

import xlwt, xlrd 
from xlutils.copy import copy as copy 
from time import time 

def add_stats_record(): 
    #Open for read 
    start_time = time() 
    rb = xlrd.open_workbook(STATS_FILE, formatting_info=True) 
    sheet_records_original = rb.sheet_by_index(0) 
    print('Elapsed time for opening:   %.2f' % (time()-start_time)) 
    #Record_id 
    start_time = time() 
    START_ROW = sheet_records_original.nrows 
    SHEET_RECORDS_COLS = sheet_records_original.ncols 
    try: 
     record_id = int(sheet_records.cell(START_ROW - 1, 0).value) + 1 
    except: 
     record_id = 1 
    print('Elapsed time for record ID:   %.2f' % (time()-start_time)) 
    #Open for write 
    start_time = time() 
    wb = copy(rb) 
    sheet_records = wb.get_sheet(0) 
    print('Elapsed time for write:    %.2f' % (time()-start_time)) 
    #Set normal style 
    style_normal = xlwt.XFStyle() 
    normal_font = xlwt.Font() 
    style_normal.font = normal_font 

    #Read all the data and get some stats 
    start_time = time() 
    max_col = {} 
    start_time = time() 
    for col_idx in range(0,16): 
     max_value = 0 
     for row_idx in range(START_ROW): 
      if sheet_records_original.cell(row_idx, col_idx).value: 
       val = float(sheet_records_original.cell(row_idx, col_idx).value) 
       if val > max_value: 
        max_col[col_idx] = str(row_idx) + ';' + str(col_idx) 

    text_cells = [[0 for x in range(15)] for y in range(START_ROW)] 
    for col_idx in range(16,31): 
     max_value = 0 
     for row_idx in range(START_ROW): 
      if sheet_records_original.cell(row_idx, col_idx).value: 
       val = str(sheet_records_original.cell(row_idx, col_idx).value).replace('text', '').count(str(col_idx)) 
       if val > max_value: 
        max_col[col_idx] = str(row_idx) + ';' + str(col_idx) 
    print('Elapsed time for reading data/stats: %.2f' % (time()-start_time)) 
    #Write the stats row 
    start_time = time() 
    for i in range(SHEET_RECORDS_COLS): 
     sheet_records.write(START_ROW, i, max_col[i], style_normal) 

    start_time = time() 
    wb.save(STATS_FILE) 
    print('Elapsed time for writing:   %.2f' % (time()-start_time))  

if __name__ == '__main__': 
    STATS_FILE = 'output.xls' 
    start_time2 = time() 
    add_stats_record() 
    print ('Total time:       %.2f' % (time() - start_time2)) 

:レコードIDのための2.43
経過時間:執筆のための時間を経過2.35
:7.62
データ/統計情報を読み取るための時間を経過:0.00
書き込みのための時間を経過: 3.33
合計時間:15.75

それはかなり明確になり、これらの結果から、あなたのコードに改善の余地はほとんどありません。オープン/コピー/ライトは大量の時間を補いますが、xlrd/xlwtへの単純な呼び出しです。

open_workbookに使用してもどちらでも役に立ちません。

openpyxlを使用してもパフォーマンスは向上しません。 21.11

のUbuntu 14.04(仮想マシン)/Python2.7:ワークブックを保存するための時間を経過0.00
:ワークブックを読み取るための22.35
経過時間:ロードワークブックのための時間を経過

from openpyxl import load_workbook 
from time import time 

#Load workbook 
start_time = time() 
wb = load_workbook('output.xlsx') 
print('Elapsed time for loading workbook: %.2f' % (time.time()-start_time))  

#Read all data 
start_time = time() 
ws = wb.active 
cell_range1 = ws['A1':'P20001'] 
cell_range2 = ws['Q1':'AF20001'] 
print('Elapsed time for reading workbook: %.2f' % (time.time()-start_time))  

#Save to a new workbook 
start_time = time() 
wb.save("output_tmp.xlsx") 
print('Elapsed time for saving workbook: %.2f' % (time.time()-start_time))  

-64bit/Regular hard disk(ネイティブWindows 10の同様の結果で、Python 3の読み込み速度は悪くなりますが、書き込みは良くなります)。


ランダムデータは、私はわずかに改善された解決策を見つけたmultiprocessingをいじる幾つか後


パンダとnumpyの

import pandas as pd 
import numpy as np 
#just random numbers 
df = pd.DataFrame(np.random.rand(20000,30), columns=range(0,30)) 
#convert half the columns to text 
for i in range(15,30): 
    df[i].apply(str) 
    df[i] = 'text' + df[i].astype(str) 
writer = pd.ExcelWriter(STATS_FILE) 
df.to_excel(writer,'Sheet1') 
writer.save() 
を使用して生成されました。 copy操作が最も時間のかかる操作であり、共有された workbookがパフォーマンスを悪化させたため、別の方法が採用されました。両方のスレッドは元のワークブックを読み取り、データを読み取り、統計を計算してファイルに書き込んで( tmp.txt)、もう1つはワークブックをコピーし、統計ファイルが表示されるのを待ち、新しくコピーされたワークブックに書き込みます。

差:合計で12%少ない時間が必要です(両方のスクリプトでn = 3)。 Excelファイルを使用しない場合を除いて、別のやり方を考えることはできません。

xls_copy.py

def xls_copy(STATS_FILE, START_ROW, style_normal): 
    from xlutils.copy import copy as copy 
    from time import sleep, time 
    from os import stat 
    from xlrd import open_workbook 
    print('started 2nd thread') 
    start_time = time() 
    rb = open_workbook(STATS_FILE, formatting_info=True) 
    wb = copy(rb) 
    sheet_records = wb.get_sheet(0) 
    print('2: Elapsed time for xls_copy:   %.2f' % (time()-start_time)) 

    counter = 0 
    filesize = stat('tmp.txt').st_size 

    while filesize == 0 and counter < 10**5: 
     sleep(0.01) 
     filesize = stat('tmp.txt').st_size 
     counter +=1 
    with open('tmp.txt', 'r') as f: 
     for line in f.readlines(): 
      cells = line.split(';') 
      sheet_records.write(START_ROW, int(cells[0]), cells[1], style_normal) 

    start_time = time() 
    wb.save('tmp_' + STATS_FILE) 
    print('2: Elapsed time for writing:   %.2f' % (time()-start_time))  

xlsx_multi.py

from xls_copy import xls_copy 
import xlwt, xlrd 
from time import time 
from multiprocessing import Process 

def add_stats_record(): 

    #Open for read 
    start_time = time() 
    rb = xlrd.open_workbook(STATS_FILE, formatting_info=True) 
    sheet_records_original = rb.sheet_by_index(0) 
    print('Elapsed time for opening:   %.2f' % (time()-start_time)) 
    #Record_id 
    start_time = time() 
    START_ROW = sheet_records_original.nrows 
    f = open('tmp.txt', 'w') 
    f.close() 
    #Set normal style 
    style_normal = xlwt.XFStyle() 
    normal_font = xlwt.Font() 
    style_normal.font = normal_font 

    #start 2nd thread 
    p = Process(target=xls_copy, args=(STATS_FILE, START_ROW, style_normal,)) 
    p.start() 
    print('continuing with 1st thread') 
    SHEET_RECORDS_COLS = sheet_records_original.ncols 
    try: 
     record_id = int(sheet_records.cell(START_ROW - 1, 0).value) + 1 
    except: 
     record_id = 1 
    print('Elapsed time for record ID:   %.2f' % (time()-start_time)) 

    #Read all the data and get some stats 
    start_time = time() 
    max_col = {} 
    start_time = time() 
    for col_idx in range(0,16): 
     max_value = 0 
     for row_idx in range(START_ROW): 
      if sheet_records_original.cell(row_idx, col_idx).value: 
       val = float(sheet_records_original.cell(row_idx, col_idx).value) 
       if val > max_value: 
        max_col[col_idx] = str(row_idx) + ';' + str(col_idx) 

    text_cells = [[0 for x in range(15)] for y in range(START_ROW)] 
    for col_idx in range(16,31): 
     max_value = 0 
     for row_idx in range(START_ROW): 
      if sheet_records_original.cell(row_idx, col_idx).value: 
       val = str(sheet_records_original.cell(row_idx, col_idx).value).replace('text', '').count(str(col_idx)) 
       if val > max_value: 
        max_col[col_idx] = str(row_idx) + ';' + str(col_idx) 
    #write statistics to a temp file 
    with open('tmp.txt', 'w') as f: 
     for k in max_col: 
      f.write(str(k) + ';' + max_col[k] + str('\n')) 
    print('Elapsed time for reading data/stats: %.2f' % (time()-start_time)) 
    p.join() 
if __name__ == '__main__': 

    done = False 
    wb = None 
    STATS_FILE = 'output.xls' 
    start_time2 = time() 
    add_stats_record() 
    print ('Total time:       %.2f' % (time() - start_time2)) 
関連する問題