使用列表推导式比普通的for循环快得多。给出的理由是列表推导式中不需要使用append,这一点是可以理解的。
但我发现在各个地方比较列表还是比apply更快。我也有这样的经历。但不明白内部工作原理为什么会比apply快得多?
我知道这与numpy中的向量化有关,而pandas数据框架的基础实现就是numpy。但是为什么列表推导式比apply更好,就不太容易理解了。因为在列表推导式中,我们在列表内部使用for循环,而在apply中甚至没有for循环(我认为这里也进行了向量化)。
编辑: 添加代码: 这是在“泰坦尼克号”数据集上运行的,从名字中提取标题: https://www.kaggle.com/c/titanic/data
我知道这与numpy中的向量化有关,而pandas数据框架的基础实现就是numpy。但是为什么列表推导式比apply更好,就不太容易理解了。因为在列表推导式中,我们在列表内部使用for循环,而在apply中甚至没有for循环(我认为这里也进行了向量化)。
编辑: 添加代码: 这是在“泰坦尼克号”数据集上运行的,从名字中提取标题: https://www.kaggle.com/c/titanic/data
%timeit train['NameTitle'] = train['Name'].apply(lambda x: 'Mrs.' if 'Mrs' in x else \
('Mr' if 'Mr' in x else ('Miss' if 'Miss' in x else\
('Master' if 'Master' in x else 'None'))))
%timeit train['NameTitle'] = ['Mrs.' if 'Mrs' in x else 'Mr' if 'Mr' in x else ('Miss' if 'Miss' in x else ('Master' if 'Master' in x else 'None')) for x in train['Name']]
结果: 782微秒 ± 6.36微秒每次循环(7次运行的平均值±标准差,每次1000次循环)
499微秒 ± 5.76微秒每次循环(7次运行的平均值±标准差,每次1000次循环)
Edit2: 为了在SO上添加代码,我创建了一个简单的代码,令人惊讶的是,对于下面的代码,结果相反:
import pandas as pd
import timeit
df_test = pd.DataFrame()
tlist = []
tlist2 = []
for i in range (0,5000000):
tlist.append(i)
tlist2.append(i+5)
df_test['A'] = tlist
df_test['B'] = tlist2
display(df_test.head(5))
%timeit df_test['C'] = df_test['B'].apply(lambda x: x*2 if x%5==0 else x)
display(df_test.head(5))
%timeit df_test['C'] = [ x*2 if x%5==0 else x for x in df_test['B']]
display(df_test.head(5))
1次循环,3次中最好的时间为每次2.14秒。
1次循环,3次中最好的时间为每次2.24秒。
编辑3: 正如一些人所建议的那样,apply本质上是一个for循环,但实际情况并非如此,因为如果我使用for循环运行此代码,它几乎永远不会结束,我不得不手动在3-4分钟后停止它,而且在此期间它从未完成。
for row in df_test.itertuples():
x = row.B
if x%5==0:
df_test.at[row.Index,'B'] = x*2
运行上述代码需要大约23秒,但应用程序只需要1.8秒。那么在itertuples中使用物理循环和apply之间有什么区别呢?
.apply
基本上就是一个 for 循环。它不使用向量化。请注意,列表推导式仅比 for 循环略快,如果您缓存.append
方法的解析结果,两者都可以实现基本相同的性能,这实际上就是列表推导式所做的事情(请注意它仍然使用 append)。 - juanpa.arrivillagax = df_test.loc[i,'B']
,尝试使用df.itertuples()
。这是一个循环。你可以自己检查源代码。 - juanpa.arrivillaga