今天我们讨论三种在 Python 数据分析库 Pandas 中加速运算的方法。 Pandas 对于处理存储在电子表格和数据库中的表格数据非常有用。它提供了许多用于操作和转换数据帧或结构数据的功能。
解释:有很多地方我们需要迭代数据框的行并进行一些操作。天真地,我们只是检查每一行数据,没有想太多,这里我们用一个简单的求和运算来展示性能变化
generate a dataframe from random numbers
import pandas as pd
import random
df = pd.DataFrame(
{
"a": [random.randint(0,100) for _ in range(100000)],
"b": [random.randint(100,200) for _ in range(100000)],
}
)
df
a | b | |
---|---|---|
0 | 17 | 161 |
1 | 77 | 150 |
2 | 30 | 121 |
3 | 18 | 130 |
4 | 31 | 178 |
... | ... | ... |
99995 | 5 | 183 |
99996 | 46 | 138 |
99997 | 9 | 133 |
99998 | 25 | 162 |
99999 | 98 | 144 |
100000 rows × 2 columns
%%timeit
results = []
for i in range(len(df)):
results.append(df.iloc[i]['a']+df.iloc[i]['b'])
11.9 s ± 297 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
results = []
for index, row in df.iterrows():
results.append(row['a']+row['b'])
3.61 s ± 156 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
results = []
for row in df.itertuples():
results.append(row.a+row.b)
69.4 ms ± 3.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
结论:使用 itertuples() 比 iterrows() 快 52 倍,比 naive looping 快 171 倍!
说明:当我们需要创建一个新的数据框并向其中添加一个新列时,例如,两个现有列的总和
%%timeit
results = []
for row in df.itertuples():
results.append( (row.a, row.b, row.a+row.b) )
new_df = pd.DataFrame(data=results)
133 ms ± 2.43 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
new_df = df.copy()
new_df['c'] = new_df.apply(lambda row: row['a']+row['b'],axis=1)
988 ms ± 106 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
new_df = df.copy()
new_df['c'] = new_df['a']+new_df['b']
956 µs ± 14 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
结论:如果我们可以在没有 for 循环的情况下利用原生 df 操作,那是最好的,可以快 1000 倍;如果我们有复杂的操作,制作新数据然后从中创建数据框,可能是一个更好的选择
在底层,流行的 apply() 函数是一个带有一些开销的 for 循环;在可能的情况下,我们可以利用矢量化操作的好处;我们这里以条件乘法为例
%%timeit
def condition_multi(a):
if a>30:
return a*2
else:
return a*3
df['c'] = df['a'].apply(condition_multi)
33.4 ms ± 2.41 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
import numpy as np
%%timeit
df['c'] = np.where(df['a']>30, df['a']*2,df['a']*3)
1.18 ms ± 304 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
结论:使用 numpy 速度提高了 28 倍!