大話機器學習之窮人如何玩轉數據挖掘
最近kaggle的一項新的賽事TalkingData AdTracking Fraud Detection Challenge終於結束了,在隊友的強力carry下,拿到了一塊銀牌。因為本身成績距離大佬有點距離,所以具體的比賽思路就不展開了,有興趣的可以看看我朋友包大人的這篇文章,他們團隊最終獲得了14名的成績。這篇文字的重點是,窮人如何才能玩轉數據挖掘比賽。
根據國際不成文的慣例,本文還是得先做以下幾點聲明:
1、窮人的技術只能幫你玩轉挖掘,至於你想通過窮人的技術戰勝土豪,那難度實在是太大了,除非你是傳說中8G內存吊打大眾的大佬。
2、如果你是土豪或者是大佬,建議你可以直接忽略本文。
大家可以直接點擊比賽的鏈接了解比賽,點這。具體的內容建議大家還是直接去官方網頁去看。
比賽數據的size,train.csv為7.01G,test.csv為823M。如果是正常方式,我那台拖拉機是根本不可能跑的動的,強行上路的話,也許就是這個下場。
好在窮人的伎倆幫助了我,讓我能顫顫悠悠的上路,最終還能完成比賽,接下來,我們來總結下哪些窮人的技術,能幫助我們更好的完成比賽。
一、比賽數據的選擇
首先,最直觀的辦法就是訓練數據的選擇上,做一些文章,用的比較多的是以下幾種方式,特別是第三種方式在減少內存消耗的同時,還提升了訓練精度,堪稱黑科技:
- 讀取數據的時候,適當的選擇其中一部分數據作為訓練集,其餘部分直接捨棄了。pandas在讀取csv文件的時候,可以通過nrows參數和skiprows參數來選擇自己想要的部分。
train = pd.read_csv(./data/train.csv, nrows=select_row, usecols=train_col, skiprows=range(1,79087139), dtype = dtypes, parse_dates=[click_time] )
- 選擇和test同時段的數據集,train數據是全時段數據,test是固定幾個時段的數據,我們選擇同時段的數據來減少訓練集的size。
- 對部分負樣本進行採樣處理:在統計特徵的時候,還是按照全局統計,統計出特徵後對負樣本進行了5%的採樣,來減少內存的消耗。TOP3隊伍就採用了這樣的策略,減少內存消耗的同時,還提升了訓練效果。
二、特徵提取和拼接的分離
對於一個窮人來說,如果你試圖一次性搞定所有,顯然是不科學的,因此更科學的辦法是通過時間來換取空間,雖然內存的空間有限,但是硬碟的空間還是闊以的,所以更常用的做法就是先跑一輪,把特徵固化到硬碟內。第二輪只是讀取硬碟里的特徵數據,做特徵拼接來減少內存的消耗。
在TalkingData AdTracking Fraud Detection Challenge的比賽中,很多開源kernel就採用了這樣的模型框架。
GROUPBY_AGGREGATIONS = [ {groupby: ["ip"], select: app, agg: nunique}, {groupby: ["ip"], select: app, agg: count}, ] def get_global_feature(feature): print ("get global feat") data = pd.concat([get_basic_data(day=8),get_basic_data(day=9),get_basic_data(day=10)]) for spec in tqdm(GROUPBY_AGGREGATIONS): new_feature = {}_{}_{}.format(_.join(spec[groupby]), spec[agg], spec[select]) result_path = cache_path + new_feature + %s.hdf%(data.shape[0]) if os.path.exists(result_path): result = pd.read_hdf(result_path, w) result[new_feature] = result[new_feature].astype("float32") else: print("Grouping by {}, and aggregating {} with {}".format(spec[groupby], spec[select], agg_name)) all_features = list(set(spec[groupby] + [spec[select]])) result = data[all_features].groupby(spec[groupby],as_index=False)[spec[select]].agg({new_feature:spec[agg]}) result[new_feature] = result[new_feature].astype("float32") result.to_hdf(result_path, w, complib=blosc, complevel=5) feature = feature.merge(result, on=spec[groupby], how=left,copy=False) return feature
具體的代碼可以參考這塊,groupby的內容放置於一個list中,每個groupby後的特徵,以hdf的格式保存。這樣做有如下優點:
- 方便特徵的增減,增加特徵只需要在GROUPBY_AGGREGATIONS中增加一行,刪除特徵只需要做注釋即可。
- 把特徵保存於hdf格式,第二輪直接從硬碟讀取特徵,可節約大量內存。
- pd.merge()函數,設置copy=False,也可節約內存。
三、根據每列數據的大小,對數據進行astype操作。
比如說,在pandas讀取csv文件時,可設置dtype,可節約內存。
dtypes = { ip : uint32, app : uint16, device : uint16, os : uint16, channel : uint16, is_attributed : uint8, click_id : uint32 }
特徵從硬碟讀取後,做一次astype("float32"),也可節約內存,關於這個辦法,其實網上已經有一篇節約內存的文章,大家可以看【精心解讀】用pandas處理大數據——節省90%內存消耗的小貼士。做了非常詳細的說明。這步能節約大量的內存,但是不可避免的可能會損失部分精度,但是誰讓我們是窮人呢?
四、lightgbm轉換dataset把數據load save操作
lightgbm轉換dataset的時候非常耗費內存,很多時候在這一步報OOM錯誤,真是痛心疾首啊,所以我們可以把數據進行這樣的操作。
train_data_v1.save_binary(train_v1.bin)train = lightgbm.Dataset(train_v1.bin, feature_name=predictors, categorical_feature=categorical)
五、gc.collect()操作
通過這些操作,我的聯想啟天垃圾商務電腦,終於算能跑起來了,至少也能出一個結果,這算是一份數據挖掘的窮人生存手冊吧,未來的挖掘賽數據也許會更加龐大,我等窮人該何去何從?愁。
。。。。。。。。。。。。。。。。。。
推薦閱讀:
※用戶畫像—打用戶行為標籤
※<EYD與機器學習>三:Classifcation
※你問我答之「關於人工智慧客服YiBot的一切」
※用【指數加權平均】構造時間序列問題的特徵
※資源 | 100+個自然語言處理數據集大放送,再不愁找不到數據!
TAG:數據挖掘 |