【问题标题】:Optimizing a pandas apply looking back at the prior row mid calculation优化熊猫应用回顾前一行中间计算
【发布时间】:2019-02-06 10:58:24
【问题描述】:

我有一个数据框 - pastebin for minimium code to run

df_dict = {
    'A': [1, 2, 3, 4, 5],
    'B': [5, 2, 3, 1, 5],
    'out': np.nan
}
df = pd.DataFrame(df_dict)

我目前正在执行以下逐行计算:

def transform(row):

    length = 2
    weight = 5
    row_num = int(row.name)
    out = row['A'] / length

    if (row_num >= length):
        previous_out = df.at[ row_num-1, 'out' ]
        out = (row['B'] - previous_out) * weight + previous_out

    df.at[row_num, 'out'] = out


df.apply( lambda x: transform(x), axis=1)

这会产生正确的结果:

   A  B    out
0  1  5    0.5
1  2  2    1.0
2  3  3   11.0
3  4  1  -39.0
4  5  5  181.0

正确计算的细分如下:

   A  B    out
0  1  5    0.5   
out = a / b 

1  2  2    1.0
out = a / b 

row_num >= length:

2  3  3   11.0
out = (b - previous_out) * weight + previous_out
out = (3 - 1) * 5 + 1  = 11

3  4  1  -39.0
out = (1 - 11) * 5 + 11 = 39

4  5  5  181.0
out = (5 - (-39)) * 5 + (-39) = 181

在许多列和循环中执行此操作很慢,因此我想尽可能利用某种矢量化进行优化。

我目前的尝试是这样的:

df['out'] = df['A'] / length
df[length:]['out'] = (df[length:]['B'] - df[length:]['out'].shift() ) * weight + df[length:]['out'].shift()

这不起作用,我不太确定从这里去哪里。

Pastebin of the above code to just copy/paste into a file and run

【问题讨论】:

  • 你能解释一下逻辑吗?
  • 你能给出一些行的示例计算吗?例如你如何得到181.0
  • 我已经更新了示例以更好地显示逻辑和计算,并且还在更新的 pastebin 中包含了该细分
  • 正如答案所说,这是一个自然循环。你可能想看看 Cython nealhughes.net/cython1

标签: python pandas numpy dataframe lambda


【解决方案1】:

您将无法做得比这更好:

df['out'] = df.A / length
for i in range(len(df)):
    if i >= length:
        df.loc[i, 'out'] = (df.loc[i, 'B'] - 
                df.loc[i - 1, 'out']) * weight + df.loc[i - 1, 'out']

原因是“输入取决于先前步骤的结果的计算的迭代性质使矢量化复杂化”(正如评论者 here 所说)。您不能进行计算,其中每个结果都取决于矩阵中的前一个结果 - 幕后总会发生某种循环。

【讨论】:

  • 我明白你在说什么,假设我有 5 x 10,000 行 df...我需要在 5 列上进行此计算,已经有 250,000 次执行,添加 4 x .loc命令,突然之间,我们的总查找量达到了 1m。难道没有更好的方法来编写方程式以使其成为更有效的操作吗?
  • 在我看来就像向量代数的基本限制。但我是一名业余爱好者,很高兴被经验更丰富的 SOers 证明是错误的。
  • 另外,我链接的主题中的所有答案都与您相关。特别注意 jpp 对numba 的推荐,它直接编译成机器码。你仍然需要循环,但你的执行会更快。
  • 谢谢乔希,我现在刚刚接受了答案,因为它看起来就是这样。感谢您提供的链接将阅读更多内容,您发布的内容很有趣,因为这也是我之前一直在关注的内容。
猜你喜欢
  • 2020-11-12
  • 1970-01-01
  • 2016-07-01
  • 2019-11-14
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多