最近做科研时经常需要遍历整个DataFrame,进行各种列操作,例如把某列的值全部转成pd.Timestamp格式或者将某两列的值进行element-wise运算之类的。大数据的数据量随便都是百万条起跳,如果只用for循环慢慢撸,不仅浪费时间也没效率。在一番Google和摸索后我找到了遍历DataFrame的至少8种方式,其中最快的和最慢的可以相差12000倍!
本文以相加和相乘两种操作为例,测试8种方法的运行速度,并附上示范代码。
测试环境
Macbook Pro Retina with TouchBar (13inch, 2018) i5 8GB 512GB
OS: macOS Catalina 10.5.2
Python 3.7.5 (default, Nov 1 2019, 02:16:23)
[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
示范用数据
本来想造100万笔的,但是100万笔跑%timeit要跑很久,最后造了3000笔,己经足以体现运行速度差异。为了避免快取影响,每个子实验进行前都会用这个代码重造数据。
import pandas as pd
import numpy as np
# 生成樣例數據
def gen_sample():
aaa = np.random.uniform(1,1000,3000)
bbb = np.random.uniform(1,1000,3000)
ccc = np.random.uniform(1,1000,3000)
ddd = np.random.uniform(1,1000,3000)
return pd.DataFrame({'aaa':aaa,'bbb':bbb, 'ccc': ccc, 'ddd': ddd, 'eee': None})aaa、bbb是本文要操作的对象;ccc、ddd不会被操作到,只是要增大数据框的大小,模拟读入整个数据框和只读取aaa、bbb两列的速度差别;eee用来存放结果
实验1 - 两列元素相加
# aaa + bbb
# python 循環 + iloc 定位
def method0_sum(DF):
for i in range(len(DF)):
DF.iloc[i,4] = DF.iloc[i,0] + DF.iloc[i,1]
# python 循環 + iat 定位
def method1_sum(DF):
for i in range(len(DF)):
DF.iat[i,4] = DF.iat[i,0] + DF.iat[i,1]
# pandas.DataFrame.iterrows() 迭代器
def method2_sum(DF):
for index, rows in DF.iterrows():
rows['eee'] = rows['aaa'] + rows['bbb']
# pandas.DataFrame.apply 迭代
def method3_sum(DF):
DF['eee'] = DF.apply(lambda x: x.aaa