【问题标题】:Improve the speed of a For Loop Python提高 For 循环 Python 的速度
【发布时间】:2019-08-01 01:42:50
【问题描述】:

我有一个返回字典的函数。该函数通过根据数据帧中的数组计算值来工作。

数据框有大约 1000,000 行,如下所示:

                  col1                  
row1         [2, 3, 44, 89.6,...]           
row2         [10, 4, 33.3, 1.11,...]
row3         [3, 4, 3, 2.6, 5.9, 8, 10,...]  

我的函数接受每一行中的每个数组,进行一些计算并根据这些计算返回一个字典。但是,它非常缓慢。有很多数据需要筛选,我很欣赏,但有什么方法可以提高速度吗?

问题 数据框很长。每个数组可以包含 100 多个值。范围约为 10-80。

我的代码如下所示:

list1 = []

for i in df.itertuples():
    list1.append(list(function(i.data).values()))

这里的想法是我遍历“df”中的每一行,将我的函数应用于“数据”列并将结果附加到列表“list1”。

功能说明

我的函数计算了一些非常基本的东西。它接受一个数组作为参数并根据该数组计算东西,例如多长时间,数组中的平均值,数组的最小值和最大值。我计算 8 个值并将它们存储在字典中。我的函数做的最后一件事是查看这些计算值并以布尔值的形式向字典添加最终键。

【问题讨论】:

  • 如果您将列表存储在数据框的单元格中,那么不,您无法加快速度。如果您选择不同的数据结构,您也许可以这样做
  • 可以添加你的功能吗?或者添加一些示例功能?是否可以将列表转换为标量,这意味着 [2, 3, 44, 89.6,...] 转换为列,其他列表类似?也许那时有必要改变你的功能。
  • 瓶颈几乎可以肯定是将function应用于容器的每个元素(部分);容器的类型(数据框、列表等)并不重要。
  • 如果您想将函数应用于独立于所有其他行的每一行,那么您可以使用multiprocessing 稍微加快它的速度。请注意,仅当您(在行上)执行复杂计算时才适用,否则可能会减慢您的速度。
  • 根据您的函数的功能,使用Cython 也可能很有趣。我们需要更多细节来正确回答这个问题。

标签: python pandas loops apply


【解决方案1】:

就像我在 cmets 中所说,如果您的函数成本很高(减少每一行是代码中耗时的部分),那么第一步是使用 multiprocessing,因为它很容易测试。

您可以尝试以下方法:

import time
from multiprocessing import Pool

def f(x):
  time.sleep(10*10**-6) # Faking complex computation
  return x

def seq_test(input_array):
  return list(map(f, input_array))

def par_test(input_array):
  pool = Pool(8)  #  "nproc --all" or "sysctl -n hw.ncpu" on osx
  return pool.map(f, input_array)

def run_test(test_function):
  test_size = 10*10**4
  test_input = [i for i in range(test_size)]

  t0 = time.time()
  result = test_function(test_input)
  t1 = time.time()

  print(f"{test_function.__name__}: {t1-t0:.3f}s")

run_test(seq_test)
run_test(par_test)

在我的机器上,并行版本的运行速度大约快 7 倍(非常接近我们希望的 8 倍):

seq_test: 2.131s
par_test: 0.300s

如果这还不够,下一步是用另一种语言编写函数f,再一次,这里似乎更简单的是使用Cython。但是为了讨论这一点,我们需要看看你的函数里面有什么。

【讨论】:

    【解决方案2】:

    我建议更改您的数据格式,例如:

    print (df)
                                col1
    row1            [2, 3, 44, 89.6]
    row2         [10, 4, 33.3, 1.11]
    row3  [3, 4, 3, 2.6, 5.9, 8, 10]
    
    from itertools import chain
    
    df = pd.DataFrame({
        'idx' : df.index.repeat(df['col1'].str.len()),
        'col1' : list(chain.from_iterable(df['col1'].tolist()))
    })
    print (df)
         idx   col1
    0   row1   2.00
    1   row1   3.00
    2   row1  44.00
    3   row1  89.60
    4   row2  10.00
    5   row2   4.00
    6   row2  33.30
    7   row2   1.11
    8   row3   3.00
    9   row3   4.00
    10  row3   3.00
    11  row3   2.60
    12  row3   5.90
    13  row3   8.00
    14  row3  10.00
    

    然后汇总您的数据:

    df1 = df.groupby('idx')['col1'].agg(['sum','mean','max','min'])
    print (df1)
             sum       mean   max   min
    idx                                
    row1  138.60  34.650000  89.6  2.00
    row2   48.41  12.102500  33.3  1.11
    row3   36.50   5.214286  10.0  2.60
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-21
      • 1970-01-01
      • 2017-10-06
      • 1970-01-01
      相关资源
      最近更新 更多