我使用熊猫数据框架,并希望创建一个新的列作为一个函数的现有列。我还没有看到一个很好的讨论之间的速度差异 df.apply()
和 np.vectorize()
,所以我想我会在这里问。
熊猫的 apply()
功能是缓慢的。根据我的测量(在下面的一些实验中显示) ,使用 np.vectorize()
比使用 DataFrame 功能 apply()
快25倍(或更多) ,至少在我2016年的 MacBook Pro 上是这样。这是一个预期的结果吗? 为什么?
例如,假设我有以下 N
行的数据帧:
N = 10
A_list = np.random.randint(1, 100, N)
B_list = np.random.randint(1, 100, N)
df = pd.DataFrame({'A': A_list, 'B': B_list})
df.head()
# A B
# 0 78 50
# 1 23 91
# 2 55 62
# 3 82 64
# 4 99 80
进一步假设我想创建一个新列,作为两列 A
和 B
的函数。在下面的例子中,我将使用一个简单的函数 divide()
。要应用这个函数,我可以使用 df.apply()
或者 np.vectorize()
:
def divide(a, b):
if b == 0:
return 0.0
return float(a)/b
df['result'] = df.apply(lambda row: divide(row['A'], row['B']), axis=1)
df['result2'] = np.vectorize(divide)(df['A'], df['B'])
df.head()
# A B result result2
# 0 78 50 1.560000 1.560000
# 1 23 91 0.252747 0.252747
# 2 55 62 0.887097 0.887097
# 3 82 64 1.281250 1.281250
# 4 99 80 1.237500 1.237500
如果我将 N
增加到现实世界的大小,比如100万或更多,那么我观察到 np.vectorize()
比 df.apply()
快25倍或更多。
下面是一些完整的基准测试代码:
import pandas as pd
import numpy as np
import time
def divide(a, b):
if b == 0:
return 0.0
return float(a)/b
for N in [1000, 10000, 100000, 1000000, 10000000]:
print ''
A_list = np.random.randint(1, 100, N)
B_list = np.random.randint(1, 100, N)
df = pd.DataFrame({'A': A_list, 'B': B_list})
start_epoch_sec = int(time.time())
df['result'] = df.apply(lambda row: divide(row['A'], row['B']), axis=1)
end_epoch_sec = int(time.time())
result_apply = end_epoch_sec - start_epoch_sec
start_epoch_sec = int(time.time())
df['result2'] = np.vectorize(divide)(df['A'], df['B'])
end_epoch_sec = int(time.time())
result_vectorize = end_epoch_sec - start_epoch_sec
print 'N=%d, df.apply: %d sec, np.vectorize: %d sec' % \
(N, result_apply, result_vectorize)
# Make sure results from df.apply and np.vectorize match.
assert(df['result'].equals(df['result2']))
结果如下:
N=1000, df.apply: 0 sec, np.vectorize: 0 sec
N=10000, df.apply: 1 sec, np.vectorize: 0 sec
N=100000, df.apply: 2 sec, np.vectorize: 0 sec
N=1000000, df.apply: 24 sec, np.vectorize: 1 sec
N=10000000, df.apply: 262 sec, np.vectorize: 4 sec
如果 np.vectorize()
总是比 df.apply()
快,那么为什么没有更多地提到 np.vectorize()
呢?我只看到过与 df.apply()
相关的 StackOverflow 文章,比如: