尝试为大型数据集(400 万行)优化 Python for 循环
Trying to optimize a Python for loop for large data set (4 million rows)
我是 Python 的新手,正在习惯这些非常方便的隐式 array/list 操作,所以请多多包涵。我已经完成了一个概念验证代码(120 种组合),但正如预期的那样,它在处理完整数据集(400 万种组合)时遇到了显着的放缓。当前减速在以下for循环中:
for i in Combinations:
PropList = function.CalculateTotalPoints(ItemDict, i)
CombinationSets.loc[Combinations.index(i), 'Density':] = PropList
我尽量不把它变成文字墙,而是提供足够的信息来理解目标。
- Combinations - 这是一个数据框,包含 4 个项目(400 万行)的所有唯一组合。我最终在循环后删除了它,当它不再需要时
- PropList - 这是特定行中 4 项的累积属性的返回列表
- ItemDict - 这是一个数据框,其中包含各个项目的所有 属性 值
- CombinationSets - 这是“最终”数据框,其中包含来自 Combinations 的 4 个独特项目以及来自 CalculatedTotalPoints 函数的附加 PropList。
- CalculateTotalPoints - 此函数接受 4 个项目的列表 (i) 和对具有所有 属性 值的数据框的引用 (ItemDict)。它实际上只是执行一堆简单的加法和除法运算,并加入一些逻辑并返回各种累积属性的列表。
我敢肯定这里发生了很多“不太好 Python”的事情,但我目前的想法是:
- Python 可能有一个 better/faster 方法来实现这个循环而不是指定一个 for 循环(列表理解?)
- ItemDict 不是很大,但每次都传递给函数可能是不必要的开销
- 由于 CombinationSet 数据帧的每一行彼此独立,我应该尝试实现多处理以便可以处理多行
编辑 1:
我无法弄清楚如何将代码隔离到足以产生一个小示例问题。不适合 post 长寿,但我已将主要代码添加到 for 循环、支持函数和样本数据到 Github 要点(已删除)
编辑 2:
从我在别处读到的内容看来,for 循环通常不是 Python 中循环的首选方法。我还没有成功地向量化我的函数。但是,我确实研究了这个 for 循环的时间、函数(内部有一个 for 循环)和 PropList 的赋值。当 运行 一个小的(120 种组合)或一个大的(450 万)集合时,for 循环和函数具有相似(相当快)的性能。在这两种情况下,下面的行花费的时间最长。对于大数据集,大约需要 1 秒。
CombinationSets.loc[Combinations.index(i), 'Density':] = PropList
编辑 3:
我能够减少循环操作的时间,而不是在循环内执行合并操作 CombinationSets.loc[ ...
,我列出了返回的 PropList
。退出 for 循环后,我立即执行了所有合并操作。由于目前通过 for 循环设置单个 运行 是 ~0.004s 与 1 秒。可能还有其他优化可以完成,但我会把它留到单独的 post.
将列表移动到 for 循环之外的数据帧合并操作。请参阅编辑 3。
我是 Python 的新手,正在习惯这些非常方便的隐式 array/list 操作,所以请多多包涵。我已经完成了一个概念验证代码(120 种组合),但正如预期的那样,它在处理完整数据集(400 万种组合)时遇到了显着的放缓。当前减速在以下for循环中:
for i in Combinations:
PropList = function.CalculateTotalPoints(ItemDict, i)
CombinationSets.loc[Combinations.index(i), 'Density':] = PropList
我尽量不把它变成文字墙,而是提供足够的信息来理解目标。
- Combinations - 这是一个数据框,包含 4 个项目(400 万行)的所有唯一组合。我最终在循环后删除了它,当它不再需要时
- PropList - 这是特定行中 4 项的累积属性的返回列表
- ItemDict - 这是一个数据框,其中包含各个项目的所有 属性 值
- CombinationSets - 这是“最终”数据框,其中包含来自 Combinations 的 4 个独特项目以及来自 CalculatedTotalPoints 函数的附加 PropList。
- CalculateTotalPoints - 此函数接受 4 个项目的列表 (i) 和对具有所有 属性 值的数据框的引用 (ItemDict)。它实际上只是执行一堆简单的加法和除法运算,并加入一些逻辑并返回各种累积属性的列表。
我敢肯定这里发生了很多“不太好 Python”的事情,但我目前的想法是:
- Python 可能有一个 better/faster 方法来实现这个循环而不是指定一个 for 循环(列表理解?)
- ItemDict 不是很大,但每次都传递给函数可能是不必要的开销
- 由于 CombinationSet 数据帧的每一行彼此独立,我应该尝试实现多处理以便可以处理多行
编辑 1: 我无法弄清楚如何将代码隔离到足以产生一个小示例问题。不适合 post 长寿,但我已将主要代码添加到 for 循环、支持函数和样本数据到 Github 要点(已删除)
编辑 2: 从我在别处读到的内容看来,for 循环通常不是 Python 中循环的首选方法。我还没有成功地向量化我的函数。但是,我确实研究了这个 for 循环的时间、函数(内部有一个 for 循环)和 PropList 的赋值。当 运行 一个小的(120 种组合)或一个大的(450 万)集合时,for 循环和函数具有相似(相当快)的性能。在这两种情况下,下面的行花费的时间最长。对于大数据集,大约需要 1 秒。
CombinationSets.loc[Combinations.index(i), 'Density':] = PropList
编辑 3:
我能够减少循环操作的时间,而不是在循环内执行合并操作 CombinationSets.loc[ ...
,我列出了返回的 PropList
。退出 for 循环后,我立即执行了所有合并操作。由于目前通过 for 循环设置单个 运行 是 ~0.004s 与 1 秒。可能还有其他优化可以完成,但我会把它留到单独的 post.
将列表移动到 for 循环之外的数据帧合并操作。请参阅编辑 3。