微信公衆號:「Python讀財」
如有問題或建議,請公衆號留言
Pandas是Python中用於數據處理與分析的屠龍刀,想必大家也都不陌生,但Pandas在使用上有一些技巧和需要注意的地方,尤其是對於較大的數據集而言,如果你沒有適當地使用,那麼可能會導致Pandas的運行速度非常慢。
對於程序猿/媛而言,時間就是生命,這篇文章給大家總結了一些pandas常見的性能優化方法,希望能對你有所幫助!
一、數據讀取的優化
讀取數據是進行數據分析前的一個必經環節,pandas中也內置了許多數據讀取的函數,最常見的就是用pd.read_csv()函數從csv文件讀取數據,那不同格式的文件讀取起來有什麼區別呢?哪種方式速度更快呢?我們做個實驗對比一下。
這裏採用的數據共59萬行,分別保存爲xlsx、csv、hdf以及pkl格式,每種格式進行10次讀取測試,得到下面的結果。
可以看到,對同一份數據,pkl格式的數據的讀取速度最快,是讀取csv格式數據的近6倍,其次是hdf格式的數據,速度最慘不忍睹的是讀取xlsx格式的數據(這僅僅是一份只有15M左右大小的數據集呀)。
所以對於日常的數據集(大多爲csv格式),可以先用pandas讀入,然後將數據轉存爲pkl或者hdf格式,之後每次讀取數據時候,便可以節省一些時間。代碼如下:
import pandas as pd
#讀取csv
df = pd.read_csv('xxx.csv')
#pkl格式
df.to_pickle('xxx.pkl') #格式另存
df = pd.read_pickle('xxx.pkl') #讀取
#hdf格式
df.to_hdf('xxx.hdf','df') #格式另存
df = pd.read_hdf('xxx.pkl','df') #讀取
二、進行聚合操作時的優化
在使用agg
和transform
進行操作時,儘量使用Python的內置函數,能夠提高運行效率。(數據用的還是上面的測試用例)
1、agg+Python內置函數
2、agg+非內置函數
可以看到對 agg 方法,使用內置函數時運行效率提升了60%。
3、transform+Python內置函數
4、transform+非內置函數
對transform
方法而言,使用內置函數時運行效率提升了兩倍。
三、對數據進行逐行操作時的優化
假設我們現在有這樣一個電力消耗數據集,以及對應時段的電費價格,如下圖所示:
數據集記錄着每小時的電力消耗,如第一行代表2001年1月13日零點消耗了0.586kwh的電。不同使用時段的電費價格不一樣,我們現在的目的是求出總的電費,那麼就需要將對應時段的單位電費×消耗電量。下面給出了三種寫法,我們分別測試這三種處理方式,對比一下這三種寫法有什麼不同,代碼效率上有什麼差異。
#編寫求得相應結果的函數
def get_cost(kwh, hour):
if 0 <= hour < 7:
rate = 0.6
elif 7 <= hour < 17:
rate = 0.68
elif 17 <= hour < 24:
rate = 0.75
else:
raise ValueError(f'Invalid hour: {hour}')
return rate * kwh
#方法一:簡單循環
def loop(df):
cost_list = []
for i in range(len(df)):
energy_used = df.iloc[i]['energy_kwh']
hour = df.iloc[i]['date_time'].hour
energy_cost = get_cost(energy_used, hour)
cost_list.append(energy_cost)
df['cost'] = cost_list
#方法二:apply方法
def apply_method(df):
df['cost'] = df.apply(
lambda row: get_cost(
kwh=row['energy_kwh'],
hour=row['date_time'].hour),
axis=1)
#方法三:採用isin篩選出各時段,分段處理
df.set_index('date_time', inplace=True)
def isin_method(df):
peak_hours = df.index.hour.isin(range(17, 24))
simple_hours = df.index.hour.isin(range(7, 17))
off_peak_hours = df.index.hour.isin(range(0, 7))
df.loc[peak_hours, 'cost'] = df.loc[peak_hours, 'energy_kwh'] * 0.75
df.loc[simple_hours,'cost'] = df.loc[simple_hours, 'energy_kwh'] * 0.68
df.loc[off_peak_hours,'cost'] = df.loc[off_peak_hours, 'energy_kwh'] * 0.6
測試結果:
可以看到,採用isin()
篩選出對應數據後分開計算的速度是簡單循環的近606倍,這並不是說 isin()
有多厲害,方法三速度快是因爲它採用了向量化的數據處理方式(這裏的isin()
是其中一種方式,還有其他方式,大家可以嘗試一下) ,這纔是重點。什麼意思呢?
這裏簡單畫了個圖,大家可以結合這個圖和代碼好好體會是一個一個處理快,還是把能進行相同操作的分開然後批量處理快。
四、使用numba進行加
如果在你的數據處理過程涉及到了大量的數值計算,那麼使用numba
可以大大加快代碼的運行效率,numba
使用起來也很簡單,下面給大家演示一下。(代碼處理不具有實際意義,只是展示一下效果)
首先需要安裝numba
模塊
>>>pip install numba
我們用一個簡單的例子測試一下numba
的提速效果
import numba
@numba.vectorize
def f_with_numba(x):
return x * 2
def f_without_numba(x):
return x * 2
#方法一:apply逐行操作
df["double_energy"] = df.energy_kwh.apply(f_without_numba)
#方法二:向量化運行
df["double_energy"] = df.energy_kwh*2
#方法三:運用numba加速
#需要以numpy數組的形式傳入
#否則會報錯
df["double_energy"] = f_with_numba(df.energy_kwh.to_numpy())
從測試結果來看,再次凸顯出向量化處理的優勢,同時numba
對原本速度已經很快的向量化處理也能提高一倍多的效率。更多numba
的使用方法請參考numba的使用文檔。
參考資料:
1、https://pandas.pydata.org/pandasdocs/stable/user_guide/enhancingperf.html
2、https://realpython.com/fast-flexible-pandas/
3、https://www.cnblogs.com/wkang/p/9794678.html
原創不易,如果覺得有點用,希望可以隨手點個贊,拜謝各位老鐵。
掃碼關注公衆號「Python讀財」,第一時間獲取乾貨,還可以加數據分析學習交流羣!!