如何使用Python函数高效地处理DataFrame行?

12
在我们的使用Pandas的代码中,有一些Python函数process(row)。该函数在DataFrame.iterrows()上使用,对每个row进行一些处理并返回一个值,最终我们将这些值收集到一个新的Series中。
我意识到这种使用模式规避了numpy / Pandas栈的大部分性能优势。
1.使这种使用模式尽可能高效的最佳方法是什么? 2.是否可能在不重写大部分代码的情况下实现?
另一个问题是:是否所有这样的函数都可以转换为numpy有效的表示形式?我还有很多关于numpy / scipy / Pandas堆栈的知识需要学习,但似乎对于真正的任意逻辑,有时您可能需要像上面那样使用一个慢速的纯Python架构。是这种情况吗?

如果你在进行数学计算,你应该能够进行向量化操作。如果你使用字符串或其他非固定大小的数据类型,你可以以向量化的方式对数字进行数学运算,然后对其余部分进行基于行的操作... 你能提供一些关于你正在做什么的详细信息吗? - Dav Clark
1个回答

20

你应该沿着axis=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循环要快得多,但不是最快的。您可以通过计时操作来测试,并且会看到差异。
某些操作可以转换为列导向操作(例如,上例中的操作可以轻松转换为df['a'] + df['b']),但其他操作不行。特别是如果您有许多分支,特殊情况或其他应在行上执行的逻辑。在这种情况下,如果apply对您来说太慢了,我建议您尝试将代码“Cython-化”。 Cython与NumPy C API非常兼容,并且将为您提供最大的速度。
或者,您可以尝试使用numba。 :)

applay 中有一个小错别字 :) - Phillip Cloud
@PhillipCloud 我发现你很少使用axis=1的apply方法。这是出于性能方面的考虑吗?不应该这是逐行迭代数组的最快方式吗? - Viktor Kerkez
我相信是这样的。没有特别的原因,只是我通常处理的数据是按列排列的,所以我最终不需要使用它(所以它并不是我首要考虑的问题)。我还怀疑通过某种重塑或“groupby”操作可以大多数情况下避免沿行进行的操作,但我没有证据来支持这一点,只有我的直觉,这可能是错误的。 - Phillip Cloud
没错,如果你能将操作转换为列导向的操作,速度会更快。谢谢。 - Viktor Kerkez
令牌链接到文档中的性能增强部分:http://pandas.pydata.org/pandas-docs/dev/enhancingperf.html - Andy Hayden
我来晚了,但是使用 axis=1 是否可以说,您可以获得与以列为导向保留基于行格式相同的性能? - kuanb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接