使用列表解析比普通的for循环要快得多。这里给出的原因是列表解析中不需要append,这是可以理解的。但是我在很多地方发现列表比较比apply快。我也经历过这种情况。但是我不明白是什么内部工作使得它比apply快得多?
我知道这与numpy中的向量化有关,numpy是panda Dataframe 的基本实现,但是为什么列表解析比apply更好,这不是很容易理解的,因为在列表解析中,我们在列表中给予for循环,而在apply中,我们甚至没有给出任何for循环(我假设向量化也在那里发生)
编辑:添加代码:这是在titanic数据集上工作,其中标题从名称中提取: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 µs ± 6.36 µs/循环(7次运行的平均值±标准差,每次运行1000个循环)
499 µs ± 5.76 µs/循环(7次运行的平均值±标准差,每次运行1000个循环)
Edit 2:要为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 s/循环
1圈,3局两胜:2.24 s/循环
Edit 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秒,而apply只需要1.8秒,那么,迭代元组中的这些物理循环和apply有什么区别呢?
1条答案
按热度按时间x6yk4ghg1#
apply
和列表解析之间的性能差异有几个原因。首先,代码中的列表解析不会在每次迭代时都调用函数,而
apply
会,这是一个巨大的差异:其次,apply的作用远不止列表解析,例如,它试图为结果找到合适的数据类型,通过禁用该行为,你可以看到它的影响:
在
apply
中还发生了许多其他的事情,所以在本例中,您可能希望使用map
:它比包含函数调用的列表解析性能更好。
那么为什么要使用
apply
呢?我至少知道一个例子,它的性能优于其他任何东西--当你想要应用的操作是一个矢量化的universal function时。这是因为apply
不像map
,列表解析允许函数在整个Series上运行,而不是在其中的单个对象上运行。让我们来看一个例子: