微信公眾號:「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/stabl...
2、https://realpython.com/fast-flexible-panda...
3、https://www.cnblogs.com/wkang/p/9794678.ht...
原創不易,如果覺得有點用,希望可以隨手點個贊,拜謝各位老鐵。
掃碼關注公眾號「Python讀數」,第一時間獲取乾貨,還可以加Python學習交流群!!
本作品採用《CC 協議》,轉載必須註明作者和本文連結