Python 在OpenPYXL中运行50k行Excel文件的最快方法

Python 在OpenPYXL中运行50k行Excel文件的最快方法,python,excel,performance,openpyxl,Python,Excel,Performance,Openpyxl,我在python中使用openpyxl,我尝试运行50k行,从每行获取数据并将其放入文件中。然而。。我发现它跑得越远,速度就越慢。第一条1k线路的速度非常快,不到一分钟,但在那之后,接下来的1k线路的运行时间越来越长 我正在打开一个.xlsx文件。我想知道以csv或其他方式打开.txt文件或读取json文件或其他方式是否更快?或者以某种方式转换成阅读速度更快的东西 在给定的列中有20个唯一的值,然后每个值都是随机的。我试图为每个值获取整个唯一值列的字符串 价值1:1243345,34124, 价

我在python中使用openpyxl,我尝试运行50k行,从每行获取数据并将其放入文件中。然而。。我发现它跑得越远,速度就越慢。第一条1k线路的速度非常快,不到一分钟,但在那之后,接下来的1k线路的运行时间越来越长

我正在打开一个.xlsx文件。我想知道以csv或其他方式打开.txt文件或读取json文件或其他方式是否更快?或者以某种方式转换成阅读速度更快的东西

在给定的列中有20个唯一的值,然后每个值都是随机的。我试图为每个值获取整个唯一值列的字符串

价值1:1243345,34124, 价值2:1243345,34124, 等等等等

我正在运行值列表,查看文件中是否存在该名称,如果存在,则它将访问该文件并向其附加新值,如果该文件不存在,则它将创建该文件,然后将其设置为“附加”。我有一个字典,它连接了所有的“附加写文件”的东西,所以每当我想写东西的时候,它都会抓取文件名,附加的东西会出现在dict中,它会查找并写入该文件,所以它不会每次运行都打开新文件

第一个1k不到一分钟。。现在我有4k到5k的记录,5分钟后就可以运行了。。它似乎需要更长的时间,因为它在记录中上升,我想知道如何加快它。它根本没有打印到控制台

writeFile = 1
theDict = {}

for row in ws.iter_rows(rowRange):
    for cell in row:
        #grabbing the value
        theStringValueLocation = "B" + str(counter)
        theValue = ws[theStringValueLocation].value
        theName = cell.value
        textfilename = theName + ".txt"

        if os.path.isfile(textfilename):
            listToAddTo = theDict[theName]
            listToAddTo.write("," + theValue)
            if counter == 1000:
                print "1000"
                st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')

        else:
            writeFileName = open(textfilename, 'w')
            writeFileName.write(theValue)
            writeFileName = open(textfilename, 'a')
            theDict[theName] = writeFileName
        counter = counter + 1
我在上面的代码中添加了一些时间戳,它不在那里,但是您可以看到下面的输出。我看到的问题是,每跑1公里,它就会越来越高。第一时间是2分钟,第三分钟,第五分钟,第七分钟。当它达到50k的时候,我担心它会花上一个小时左右,而且会花太长时间

1000
2016-02-25 15:15:08
20002016-02-25 15:17:07
30002016-02-25 15:20:52
2016-02-25 15:25:28
4000
2016-02-25 15:32:00
5000
2016-02-25 15:40:02
6000
2016-02-25 15:51:34
7000
2016-02-25 16:03:29
8000
2016-02-25 16:18:52
9000
2016-02-25 16:35:30
10000
有些事我应该说清楚。。我事先不知道这些值的名称,也许我应该在一个单独的python脚本中运行并获取这些值,以加快速度

第二,我需要一个由逗号分隔的所有值组成的字符串,这就是为什么我把它放在一个文本文件中以便稍后获取。我正考虑按照建议的清单来做,但我不知道这是否会有同样的问题。我认为这个问题与读取excel有关。无论如何,我可以从中得到一个用逗号分隔的字符串,我可以用另一种方法

或者我可以做try/catch而不是每次都搜索文件,如果有错误,我可以假设创建一个新文件?也许每次查找都会让它运行得很慢?该文件是否存在


这个问题是我原来的问题的延续,我从那里得到了一些建议

看起来您只需要B列中的单元格。在这种情况下,您可以使用
ws.get_squared_range()
来限制要查看的单元格数量

for row in ws.get_squared_range(min_col=2, max_col=2, min_row=1, max_row=ws.max_row):
    for cell in row: # each row is always a sequence
         filename = cell.value
         if os.path.isfilename(filename):
              …

现在还不清楚代码的
else
分支发生了什么,但您可能应该在完成打开的所有文件后立即关闭它们。

我认为您试图做的是从行的B列中获取一个键,并使用该键作为要附加到的文件名。让我们加快速度:

from collections import defaultdict
Value_entries = defaultdict(list) # dict of lists of row data

for row in ws.iter_rows(rowRange):
    key = row[1].value

    Value_entries[key].extend([cell.value for cell in row])

# All done. Now write files:
for key in Value_entries.keys():
    with open(key + '.txt', 'w') as f:
        f.write(','.join(Value_entries[key]))

根据您链接到的另一个问题和上面的代码,您似乎有一个名称-值对的电子表格。名称在列A中,值在列B中。名称可以在列A中出现多次,并且每次在列B中都可以有不同的值。目标是创建为每个名称显示的所有值的列表

首先,对上述代码的一些观察:

  • 计数器
    从未初始化。大概它被初始化为1

  • open(textfilename,…)
    被调用两次,其间不关闭文件。调用open会分配一些内存来保存与文件操作相关的数据。分配给第一次打开调用的内存可能要到很久以后才能释放,可能要到程序结束时才会释放。更好的做法是在处理完文件后关闭它们(请参阅使用open作为上下文管理器)

  • 循环逻辑不正确。考虑:

  • 内循环的第一次迭代:

    for cell in row:                        # cell refers to A1
        valueLocation = "B" + str(counter)  # valueLocation is "B1"
        value = ws[valueLocation].value     # value gets contents of cell B1
        name = cell.value                   # name gets contents of cell A1
        textfilename = name + ".txt"
        ...
        opens file with name based on contents of cell A1, and
        writes value from cell B1 to the file
        ...
        counter = counter + 1                        # counter = 2
    
    for cell in row:                          # cell now refers to cell B1
        valueLocation = "B" + str(counter)    # valueLocation is "B2"
        value = ws[valueLocation].value       # value gets contents of cell B2
        name = cell.value                     # name gets contents of cell B1
        textfilename = name + ".txt"
        ...
        opens file with name based on contents of cell "B1"  <<<< wrong file
        writes the value of cell "B2" to the file            <<<< wrong value
        ...
        counter = counter + 1        # counter = 3 when cell B1 is processed
    
    但每行至少有两个单元格,因此在内部循环的第二次迭代中:

    for cell in row:                        # cell refers to A1
        valueLocation = "B" + str(counter)  # valueLocation is "B1"
        value = ws[valueLocation].value     # value gets contents of cell B1
        name = cell.value                   # name gets contents of cell A1
        textfilename = name + ".txt"
        ...
        opens file with name based on contents of cell A1, and
        writes value from cell B1 to the file
        ...
        counter = counter + 1                        # counter = 2
    
    for cell in row:                          # cell now refers to cell B1
        valueLocation = "B" + str(counter)    # valueLocation is "B2"
        value = ws[valueLocation].value       # value gets contents of cell B2
        name = cell.value                     # name gets contents of cell B1
        textfilename = name + ".txt"
        ...
        opens file with name based on contents of cell "B1"  <<<< wrong file
        writes the value of cell "B2" to the file            <<<< wrong value
        ...
        counter = counter + 1        # counter = 3 when cell B1 is processed
    

    代码的缩进是错误的,这意味着我们无法判断循环的结构。为什么要迭代单元格,然后访问某行B列中的单元格?我猜
    ws[“B”+str(计数器)]。value
    以线性时间wrt运行<代码>计数器,不是在恒定时间内。否缩进没有错误。你明白了。。我有两个价值观。B一是“值”所在的位置。“cell.value”是名称。我在用柜台抓住彼此在同一排的那一个。哦,是的,你说得对。。第行的单元格后面应该有缩进。。我会修好的,我不知道你想做什么。提供输入电子表格的几行/几列以及一个或两个输出文件的外观可能会有所帮助。另外,您要打开多少个文件?性能应该是线性的。如果不是这样,那么你可能在某个地方有一个嵌套循环。else分支是如果文件不存在,它会创建文件,然后保持打开状态,这样我就可以在每个文件的末尾添加“,”,这样它就不必每次都重新打开文件,它只会保持打开状态,大约有20个文件将被打开,我建议您使用标准库中的profile模块来找出代码在哪里花费了大部分时间,而不是在这里提供一个带有时间戳的不完整脚本。。我不知道他们有,有没有一个超快速的方法来设置?看起来我看到的一切都很复杂你不需要计算A1