Pandas中Apply函數加速百倍的技巧
點擊上方“視學算法”,選擇加"星標"或“置頂”
重磅干貨,第一時間送達
來源 | kaggle競賽寶典
編輯 | 極市平臺
導讀
現(xiàn)在的dask,cudf包的出現(xiàn),我們的數據處理得到了大大的加速,但不是很貴的人比較好gpu,非常多的朋友仍然可以使用pandas工具包,但等真的很無奈,熊貓的許多問題我們都需要使用apply函數來進行處理,而apply函數是非常緩慢的,本文我們就介紹如何加速apply函數600倍的技巧。
現(xiàn)在的dask,cudf包的出現(xiàn),我們的數據處理得到了大大的加速,但不是很貴的人比較好gpu,非常多的朋友仍然可以使用pandas工具包,但等真的很無奈,熊貓的許多問題我們都需要使用apply函數來進行處理,而apply函數是非常緩慢的,本文我們就介紹如何加速apply函數600倍的技巧。
實驗對比
01 應用(基線)
我們以應用為案,原來的應用程序處理下面這個問題,需要18.4 秒的時間。
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randint(0, 11, size=(1000000, 5)), columns=('a','b','c','d','e'))
def func(a,b,c,d,e):
if e == 10:
return c*d
elif (e < 10) and (e>=5):
return c+d
elif e < 5:
return a+b
%%time
df['new'] = df.apply(lambda x: func(x['a'], x['b'], x['c'], x['d'], x['e']), axis=1)
CPU times: user 17.9 s, sys: 301 ms, total: 18.2 s
Wall time: 18.4 s
02 迅捷
因為處理是并行的,所以我們可以使用Swift進行加速,在使用Swift之后,相同的操作在我的機器上可以提升到7.67s 。
%%time
# !pip install swifter
import swifter
df['new'] = df.swifter.apply(lambda x : func(x['a'],x['b'],x['c'],x['d'],x['e']),axis=1)
HBox(children=(HTML(value='Dask Apply'), FloatProgress(value=0.0, max=16.0), HTML(value='')))
CPU times: user 329 ms, sys: 240 ms, total: 569 ms
Wall time: 7.67 s
03 矢量化
使用Pandas和Numpy的避免應用方法是將函數直接化。如果我們的操作是可以直接直接化的話,那么我們就很簡單的使用
用于循環(huán); 列表處理; 應用等操作
在將上面的問題轉化為下面的處理之后,我們的時間為:421 ms
%%time
df['new'] = df['c'] * df['d'] #default case e = =10
mask = df['e'] < 10
df.loc[mask,'new'] = df['c'] + df['d']
mask = df['e'] < 5
df.loc[mask,'new'] = df['a'] + df['b']
CPU times: user 134 ms, sys: 149 ms, total: 283 ms
Wall time: 421 ms
04 類別轉化+類別化
我們先將上面的類別轉化為int16型,再進行相同的操作,發(fā)現(xiàn)時間為:116 ms
for col in ('a','b','c','d'):
df[col] = df[col].astype(np.int16)
%%time
df['new'] = df['c'] * df['d'] #default case e = =10
mask = df['e'] < 10
df.loc[mask,'new'] = df['c'] + df['d']
mask = df['e'] < 5
df.loc[mask,'new'] = df['a'] + df['b']
CPU times: user 71.3 ms, sys: 42.5 ms, total: 114 ms
Wall time: 116 ms
05 轉化為值處理
在能轉化為.values的地方典型轉化為.values,再進行操作。
這里先轉化為.values等價于轉化為numpy,這樣我們的操作會更快捷。
于是,上面的操作時間又被延遲為:74.9ms
%%time
df['new'] = df['c'].values * df['d'].values #default case e = =10
mask = df['e'].values < 10
df.loc[mask,'new'] = df['c'] + df['d']
mask = df['e'].values < 5
df.loc[mask,'new'] = df['a'] + df['b']
CPU times: user 64.5 ms, sys: 12.5 ms, total: 77 ms
Wall time: 74.9 ms
實驗總結
通過上面的一些小技巧,我們將簡單的長大了,具體地:
應用:18.4 秒 應用 + Swifter:7.67 秒 熊貓矢量化:421 毫秒 Pandas 矢量化 + 數據類型:116 毫秒 Pandas 向量化 + 值 + 數據類型:74.9ms
參考文獻
https://towardsdatascience.com/do-you-use-apply-in-pandas-there-is-a-600x-faster-way-d2497facfa66
如果覺得有用,就請分享到朋友圈吧!

點個在看 paper不斷!
