12

在我们使用 Pandas 的代码中的许多地方,我们都有一些 Python 函数process(row)。该函数被使用DataFrame.iterrows(),获取每个row,并进行一些处理,并返回一个值,我们最终将其收集到一个新的Series中。

我意识到这种使用模式绕过了 numpy / Pandas 堆栈的大部分性能优势。

  1. 使这种使用模式尽可能高效的最佳方法是什么?
  2. 我们可以在不重写大部分代码的情况下做到这一点吗?

这个问题的另一个方面:所有这些函数都可以转换为 numpy-efficient 表示吗?关于 numpy / scipy / Pandas 堆栈,我还有很多东西要学习,但似乎对于真正的任意逻辑,您有时可能只需要使用像上面那样的慢速纯 Python 架构。是这样吗?

4

1 回答 1

20

您应该沿轴 = 1 应用您的函数。函数将接收一行作为参数,它返回的任何内容都将被收集到一个新的系列对象中

df.apply(you_function, axis=1)

例子:

>>> df = pd.DataFrame({'a': np.arange(3),
                       'b': np.random.rand(3)})
>>> df
   a         b
0  0  0.880075
1  1  0.143038
2  2  0.795188
>>> def func(row):
        return row['a'] + row['b']
>>> df.apply(func, axis=1)
0    0.880075
1    1.143038
2    2.795188
dtype: float64

至于问题的第二部分:使用 pandas 的逐行操作,即使是优化的操作,apply也不是最快的解决方案。它们肯定比 python for 循环快很多,但不是最快的。您可以通过计时操作来测试它,您会看到差异。

一些操作可以转换为面向列的操作(我的示例中的一个可以很容易地转换为 just df['a'] + df['b']),但其他操作不能。特别是如果您有很多分支、特殊情况或其他应该在您的行上执行的逻辑。在这种情况下,如果apply对您来说太慢,我会建议“Cython-izing”您的代码。Cython 与 NumPy C api 配合得非常好,可以为您提供可以达到的最大速度。

或者你可以试试numba。:)

于 2013-08-16T22:23:57.447 回答