我正在使用Pandas数据框架,并希望创建一个新列作为现有列的函数。我没有看到关于df.apply()
和np.vectorize()
速度差异的好讨论,所以我想在这里问一下。
Pandas的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()”: Suppose further that I want to create a new column as a function of the two columns A
and B
. In the example below, I'll use a simple function divide()
. To apply the function, I can use either df.apply()
or 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
增加到一百万或更多这样的真实世界规模,那么我发现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帖子,例如:
np.vectorize
并不是矢量化的。这是一个众所周知的用词错误。 - roganjoshiterrows
不是Python方法。你应该更关心的是库在底层做了什么。 - roganjoshA_arr, B_arr = df['A'].values, df['B'].values
然后调用%timeit for a, b in zip(A_arr, B_arr): foo(a, b)
将计时缩短到:1.88 s ± 57 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
。这里发生的事情不仅仅是“python循环”。 - PMende.str
属性。在许多情况下,它们比列表解析慢。我们经常过于自以为是。 - roganjosh