我有一个可能如下所示的数据框:
A B C
foo bar foo bar
bar foo foo bar
我想查看每行的每个元素(或每列的每个元素)并应用以下函数来获取后续数据帧:
def foo_bar(x):
return x.replace('foo', 'wow')
应用该函数后,我的数据框将如下所示:
A B C
wow bar wow bar
bar wow wow bar
是否有一个简单的单行代码可以将函数应用于每个单元格?
这是一个简单的示例,因此除了应用函数之外,可能还有一种更简单的方法来执行这个特定示例,但我真正要问的是如何在数据帧内的每个单元格中应用函数。
applymap()
,这对于您的情况来说是简洁的。
df.applymap(foo_bar)
# A B C
#0 wow bar wow bar
#1 bar wow wow bar
apply
方法:
import numpy as np
df.apply(np.vectorize(foo_bar))
# A B C
#0 wow bar wow bar
#1 bar wow wow bar
我想你可以使用
np.vectorize
:
>>> df[:] = np.vectorize(foo_bar)(df)
>>> df
A B C
foo bar wow bar
bar wow wow bar
>>>
这可能会更快,因为它使用的是
numpy
。
扩展 Psidom 的答案,如果您定义的函数接受其他参数,那么您可以使用 kwargs 传递它们。例如,要在 OP 中切换
repl
或 foo_bar()
:
def foo_bar(x, bar=''):
return x.replace('foo', bar)
df.applymap(foo_bar, bar='haha')
applymap
特别有用的常见情况之一是字符串操作(如OP中所示)。由于 pandas 中的字符串操作未进行优化,因此循环通常比向量化操作执行得更好,尤其是在有很多操作的情况下。例如,对于以下使用条件替换帧中的值的简单任务,applymap
比等效的矢量化 Pandas 代码快 3 倍以上。
def foo_bar(x):
return x.replace('foo', 'wow') if len(x)>3 else x + ' this'
df = pd.DataFrame([['foo', 'bar', 'foo bar'], ['bar foo', 'foo', 'bar']]*500000, columns=[*'ABC'])
%timeit df.applymap(foo_bar)
# 1.47 s ± 37.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit df.apply(lambda x: np.where(x.str.len()>3, x.str.replace('foo', 'wow'), x + ' this'))
# 4.64 s ± 597 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)