用win32com编写数组来优化python

我正在做一个分析数据文件的Python。 parsing的数据然后发送到Excel文件。 数据可能相当庞大。 我在看10到20列,但行数可以超过100.000。

写这么多的数据,胜过win32com需要相当长的时间。 我的第一步是迭代Excel文件中的单元格,这非常耗时。 经过一番挖掘,我发现我可以用一个通话写一行,从而大大减less了所需的时间。

但是,当我需要发送100.000行的数据时,仍然需要很长时间。 我很确定,通过一次性发送完整的arrays,我可以进一步提高速度。 不过,我目前无法做到这一点。

请参阅下面的代码,它演示了这个问题。 代码显示了时间的差异。 但是,第三步,将一个调用发送到一个范围的完整数组不会导致在Excel中正确的数据。 我究竟做错了什么?

import win32com.client import time #create data array row = range(0,10) i = 0 data_array = [] while i < 1000: data_array.append(row) i += 1 #write the array to an excel file excel = win32com.client.Dispatch("Excel.Application") excel.Visible = True excel.ScreenUpdating = False book = excel.Workbooks.Add() sh1 = book.Worksheets(1) sh2 = book.Worksheets(2) sh3 = book.Worksheets(3) #double loop, writing individual cells print "Writing with double loop to inidividual cells." start = time.time() row = 0 for line in data_array: row += 1 col = 0 for field in line: col += 1 sh1.Cells(row, col).Value = field print "Processing time: " + str(time.time() - start) + " seconds." #single loop, writing a row to a range print "Writing with double loop to inidividual cells." start = time.time() row = 0 for line in data_array: row += 1 sh2.Range(sh2.Cells(row,1), sh2.Cells(row, len(line))).Value = line print "Processing time: " + str(time.time() - start) + " seconds." #no loop, write array to range print "Writing with double loop to inidividual cells." start = time.time() try: sh3.Range(sh3.Cells(row,1), sh3.Cells(len(data_array), len(data_array[0]))).Value = data_array print "Processing time: " + str(time.time() - start) + " seconds." except: print "Failed to write array to excel file." excel.ScreenUpdating = True sheet = None book = None excel.Quit() excel = None 

我一直在做这方面的研究。 并得出了一些有趣的结论。

确实有多个解决scheme来写入数据,以从Python中脱颖而出。 我最终集中在三个模块。

win32com.client

工作缓慢。 但是,文档可以在Excel中打开。 所以最终的结果是可供用户在Excel中开始工作的。 对于大量的数据不是很好。

用我的电脑(核心i5)应用程序写10万行的10,000行。 70秒。

 import win32com.client import time #create data array row = range(0,10) i = 0 data_array = [] while i < 10000: data_array.append(row) i += 1 #write the array to an excel file excel = win32com.client.Dispatch("Excel.Application") excel.Visible = True excel.ScreenUpdating = False book = excel.Workbooks.Add() sheet = book.Worksheets(1) #single loop, writing a row to a range print "Writing using win32com.client" start = time.time() row = 0 for line in data_array: row += 1 sheet.Range(sheet.Cells(row,1), sheet.Cells(row, len(line))).Value = line print "Processing time: " + str(time.time() - start) + " seconds." print "Completed: " + str(time.time() - start) + " seconds." excel.ScreenUpdating = True sheet = None book = None excel.Quit() excel = None 

openpyxl

速度有点快,但还是不太好。 这个模块将数据传输到excel内存对象的速度很慢,但保存速度非常快。 它在22.3秒内创build10行10列,并保存0.5秒。 当我用100,000行和10列testing这个。 数据创build时间为228.3秒,保存文件的时间为2.9秒。 相当慢,但文件保存速度很快。 因此,openpyxl可能对现有数据进行更改(格式设置),尽pipe我还没有对此进行testing。 另一个优点是用openpyxl编码比使用win32com.client更容易。

 import openpyxl import sys import time #create data array row = range(0,10) i = 0 data_array = [] while i < 10000: data_array.append(row) i += 1 #create an excel workbook and sheet object book = openpyxl.Workbook(optimized_write = True) #single loop, writing rows start = time.time() print "Writing with single loop using openpyxl" sheet = book.create_sheet() for line in data_array: sheet.append(line) print "Processing time: " + str(time.time() - start) + " seconds." #close and save the file. book.save('openpyxl.xlsx') print "Total time: " + str(time.time() - start) + " seconds." 

我正面临另一个问题与openpyxl。 在我的真实工具中,openpyxl在保存大量数据(> 10,000行)时遇到了问题。 我还没有弄清楚,也许我不打算再看看。

PyExcelerate

这首先是很快的。 它在0.17秒内创build10,000行和10列。 保存文件不过需要2.2秒。 到目前为止,三者中最快的select。 当我尝试使用这个模块保存100,000行和10列时,excel数据只需1.8秒。 但是现在保存文件需要21.7秒。 因此,这个模块真的很快,但是在编写文件时会有一些惩罚。 总的来说还是最快的。 PyExcelerate的另一个优点是编码非常简单,而且更容易,就像openpyxl一样。

 import pyexcelerate import sys import time #create data array row = range(0,10) i = 0 data_array = [] while i < 10000: data_array.append(row) i += 1 print sys.version #create an excel workbook and sheet object book = pyexcelerate.Workbook() #single loop, writing rows start = time.time() print "Writing with single loop using PyExcelerate" book.new_sheet("data", data = data_array) print "Processing time: " + str(time.time() - start) + " seconds." #close and save the file. book.save('pyexcelerate.xlsx') print "Total time: " + str(time.time() - start) + " seconds." 

所以我的结论是PyExcelerate是迄今为止最快的。 win32com.client的好处在于,创build的excel文件可以在excel中打开,使创build的数据可供用户开始使用。 在创build它之后,Openpyxl可能会对样式进行更改。 不过,我还没有testing过。 因此,将win32com.client,openpyxl和PyExcelerate结合在一个应用程序中可能是有益的。

使用COM从excel文件中读取文件是极其浪费时间的。 这就像用坦克杀死苍蝇。 考虑到win32com使用Windows API进行复杂的调用,这与Excel的谈话,检索数据,并将其发送回到Python。 为什么当信息已经在那里作为一个文件?

有一些库可以直接parsingexcel文件,正如你可以想象的那样,它们可以快100倍,因为对win API没有太复杂的调用。

我已经用openpyxl成功地做了很多工作,但还有其他的库可以做得更好,甚至更好。

只是一个大数据的例子(使用生成器而不是将所有内容加载到内存中):

 from openpyxl import load_workbook wb = load_workbook(filename='large_file.xlsx', use_iterators=True) ws = wb.get_sheet_by_name(name='big_data') # ws is now an IterableWorksheet for row in ws.iter_rows(): # it brings a new method: iter_rows() for cell in row: print cell.internal_value 

等价方法可用于写入单元格。 你甚至可以格式化它们,虽然它不是(或者以前)是非常完整的。

编辑

有关如何将大量信息写入xlsx文件的示例:

 from openpyxl import Workbook from openpyxl.cell import get_column_letter wb = Workbook() dest_filename = r'empty_book.xlsx' ws = wb.active ws.title = "range names" for col_idx in xrange(1, 40): col = get_column_letter(col_idx) for row in xrange(1, 600): ws.cell('%s%s'%(col, row)).value = '%s%s' % (col, row) ws = wb.create_sheet() ws.title = 'Pi' ws['F5'] = 3.14 wb.save(filename=dest_filename) 

我知道这个post有点老了。
然而,由于某些其他原因(macros执行)被困在win32com中,并且需要一个类似的解决scheme来第三张表单(一次完整的数组),我尝试了你的初始文章的代码,发现一个小错误,阻止它的工作。
所以要回答你原来的问题:“我做错了什么?”:
在'#no循环中,将数组写入范围'部分之前,您忘记将行variables重新初始化为1
下面是比较后更新的win32com部分:

 print "Writing using win32com.client" start = time.time() row = 1 sheet.Range(sheet.Cells(row,1), sheet.Cells(row+len(data_array)-1, len(data_array[0]))).Value = data_array print "Processing time: " + str(time.time() - start) + " seconds." book.SaveAs(Filename="C:\Temp\Temp.xls", FileFormat=56) print "Completed: " + str(time.time() - start) + " seconds." 

那么,时机并不是那么糟糕:
用win32com.client写
处理时间:0.322000026703秒。
完成:1.73699998856秒。
那么相当快。 也许你的比较可以更新,因为PyExcelerate数字不再是如此不同(和我的电脑更慢)。