pandas內存優化分享
緣由
最近在做Kaggle上的wiki文章流量預測項目,這里由於個人電腦配置問題,我一直都是用的Kaggle的kernel,但是我們知道kernel的內存限制是16G,如下:
在處理數據過程中發現會超出,雖然我們都知道對於大數據的處理有諸如spark等分布式處理框架,但是依然存在下面的問題:
- 對於個人來說,沒有足夠的資源讓這些框架發揮其優勢;
- 從處理數據的庫豐富程度上,還是pandas等更具有優勢;
- 很多時候並不是pandas無法處理,只是數據未經優化;
所以這里還是考慮針對數據進行內存方面的優化,以達到減少內存占用,並在kernel上正常運行為最終目的;
整個嘗試的過程
只加載當前用到的
這個不用多說,雖然一般為了省事,都是開頭一起load到內存中,但是特殊情況下,這里還是要注意的,如下:
可以看到,雖然可用數據文件很多,但是由於當前處理需要的僅僅是train2.csv,所以只加載其即可,不要小看這一步,這里每個文件加載過來都是幾百M的;
類型轉換
這里是在預處理部分能做的對內存影響最大的一部分,基本思路如下:
- object考慮是否需要轉換為category;
- numeric,即各種數值類型,是否在允許范圍內降低類型,例如假如某一列為整型且最大值為100,那么就是用用int8類型來描述;
- 對於日期類型,可以先不着急轉為datetime64,我們直到datetime類型占用內存是比object還多的,可以先考慮轉為category,后續處理完釋放了沒用對象后再轉回來即可(這種方式比較少用,但是對於這個項目還是挺有用的,因為最終內存峰值也就在那幾G上);
如下是未做轉換前的DataFrame信息:
如下是我對原始數據各字段的類型轉換以及轉換后的DataFrame信息:
看到內存占用直接降了一半,不要小看這幾百M,在DataFrame進行各種apply、groupby運算時,臨時占用的內存是非常多的,也很容易超過峰值導致kernel重啟;
PS:當然,這里如果直接加載時指定數據類型也是可以的,我這邊為了展示轉換前后效果,所以直接指定,實時上更常見的做法時,先直接加載,info或者describe看數據信息,然后判斷數據應該的類型,修改代碼為直接指定;
使用union_categoricals代替pd.concat實現表的連接
做過時序數據預測的朋友應該直到,時序數據構建時,一個特點是需要連接訓練和測試數據,然后同時針對這些數據做時序上的延遲特征、各種維度的統計特征等等,因此這里就涉及到數據連接,一定要注意要用union_categoricals代替pd.concat,如果直接使用concat,那么category類型的列會被轉為object,那么在連接的過程中,內存就會超過峰值,導致kernel重啟,那就悲劇了。。。。
如下,是對數據做reshape的操作,這個是該競賽數據的一個特點,由於其把每一天對應的訪問數據都放到了一起,也就是一行中包含了一篇文章的每一天的訪問量,而這是不利於后續做延遲特征構建的,需要將每一天的信息單獨作為一行,因此需要reshape:
如下這種連接、即時銷毀的方式雖然看着丑,但是效果還是可以的:
如下是采取這種方式鏈接后的DataFrame信息,其實難點不在於DataFrame多大,而是它在運算過程中的內存峰值會超過限制:
注意
- 即時del掉不用的對象;
- 對於category列的連接,使用union_categoricals;
- 在不同類型的列連接時,結果類型會取大的那個,比如int8連接int64,那么結果就都是int64;
- 關於category類型,不僅可以降低內存占用,而且還能加快運算速度,關鍵在於特征的取值可能數量是否遠小於行數;
Kaggle競賽鏈接
https://www.kaggle.com/c/web-traffic-time-series-forecasting
Kaggle kernel鏈接,該kernel已經設置為public,大家可以隨意copy
https://www.kaggle.com/holoong9291/web-traffic-time-series-forecasting
最后
大家可以到我的Github上看看有沒有其他需要的東西,目前主要是自己做的機器學習項目、Python各種腳本工具、數據分析挖掘項目以及Follow的大佬、Fork的項目等:
https://github.com/NemoHoHaloAi