通常來講,Gradient Boosting(GB)方法適用於異質化數據。即,若你的數據集全由圖片數據構成或者全由視頻數據構成之類的,咱們稱其爲同質化數據,這時使用神經網絡每每會有更好的表現。但對於異質化數據,好比說數據集中有user gender,user age,也有content data等等的狀況,GB方法的表現每每更好。GB方法比神經網絡的入門門檻更低,使用起來也更簡單。html
NN和GB方法能夠結合起來使用,並經常有很好的表現。咱們可使用NN方法學習embedding feature,而且和其餘一些特徵結合起來,再過GBDT。python
Catboost具備一些和其餘相似的庫不一樣的特徵:git
對於可取值的數量比獨熱最大量還要大的分類變量,CatBoost 使用了一個很是有效的編碼方法,這種方法和均值編碼相似,但能夠下降過擬合狀況。它的具體實現方法以下:github
其中 CountInClass 表示在當前分類特徵值中,有多少樣本的標記值是「1」;Prior 是分子的初始值,根據初始參數肯定。TotalCount 是在全部樣本中(包含當前樣本),和當前樣本具備相同的分類特徵值的樣本數量。能夠用下面的數學公式表示:算法
其次,它用特殊的方式處理categorical features。首先他們會計算一些數據的statistics。計算某個category出現的頻率,加上超參數,生成新的numerical features。這一策略要求同一標籤數據不能排列在一塊兒(即先全是0以後全是1這種方式),訓練以前須要打亂數據集。第二,使用數據的不一樣排列(其實是4個)。在每一輪創建樹以前,先扔一輪骰子,決定使用哪一個排列來生成樹。第三,考慮使用categorical features的不一樣組合。例如顏色和種類組合起來,能夠構成相似於blue dog這樣的feature。當須要組合的categorical features變多時,catboost只考慮一部分combinations。在選擇第一個節點時,只考慮選擇一個feature,例如A。在生成第二個節點時,考慮A和任意一個categorical feature的組合,選擇其中最好的。就這樣使用貪心算法生成combinations。第四,除非向gender這種維數很小的狀況,不建議本身生成one-hot vectors,最好交給算法來處理。網絡
catboost和其餘算法計算leaf-value的方法不一樣。傳統的boosting使用平均數,但這個估計是有偏的,會致使過擬合。而Catboost則採用另外的計算方法。dom
Catboost使用對稱樹。XGboost一層一層地創建節點,lightGBM一個一個地創建節點,而Catboost老是使用徹底二叉樹。它的節點是鏡像的。Catboost稱對稱樹有利於避免overfit,增長可靠性,而且能大大加速預測等等。機器學習
CatBoost使用oblivious樹做爲基本預測器,這種樹是平衡的,不太容易過擬合。oblivious樹中,每一個葉子節點的索引能夠被編碼爲長度等於樹深度的二進制向量。CatBoost首先將全部浮點特徵、統計信息和獨熱編碼特徵進行二值化,而後使用二進制特徵來計算模型預測值。分佈式
任何GBDT算法,對於密集的數值特徵數據集來講,搜索最佳分割是創建決策樹時的主要計算負擔。CatBoost利用oblivious決策樹做爲基礎模型,並將特徵離散化到固定數量的箱子中以減小內存使用。就GPU內存使用而言,CatBoost至少與LightGBM同樣有效。主要改進之處就是利用了一種不依賴於原子操做的直方圖計算方法。函數
CatBoost使用完美哈希來存儲類別特徵的值,以減小內存使用。因爲GPU內存的限制,在CPU RAM中存儲按位壓縮的完美哈希,以及要求的數據流、重疊計算和內存等操做。經過哈希來分組觀察。在每一個組中,咱們須要計算一些統計量的前綴和。該統計量的計算使用分段掃描GPU圖元實現。
CatBoost中的GPU實現可支持多個GPU。分佈式樹學習能夠經過數據或特徵進行並行化。CatBoost採用多個學習數據集排列的計算方案,在訓練期間計算分類特徵的統計數據。
參數對比:
數據集:
在這裏,我使用了 2015 年航班延誤的 Kaggle 數據集,其中同時包含分類變量和數值變量。這個數據集中一共有約 500 萬條記錄,所以很適合用來同時評估比較三種 boosting 算法的訓練速度和準確度。我使用了 1% 的數據:5 萬行記錄。
如下是建模使用的特徵:
月、日、星期:整型數據
航線或航班號:整型數據
出發、到達機場:數值數據
出發時間:浮點數據
到達延誤狀況:這個特徵做爲預測目標,並轉爲二值變量:航班是否延誤超過 10 分鐘
距離和飛行時間:浮點數據
import pandas as pd, numpy as np, time from sklearn.model_selection import train_test_split data = pd.read_csv("flight-delays/flights.csv") data = data.sample(frac = 0.1, random_state=10)#500->50 data = data.sample(frac = 0.1, random_state=10)#50->5 data.shape#(58191, 31) data = data[["MONTH","DAY","DAY_OF_WEEK","AIRLINE","FLIGHT_NUMBER","DESTINATION_AIRPORT", "ORIGIN_AIRPORT","AIR_TIME", "DEPARTURE_TIME","DISTANCE","ARRIVAL_DELAY"]] data.dropna(inplace=True) data["ARRIVAL_DELAY"] = (data["ARRIVAL_DELAY"]>10)*1 #data.head() cols = ["AIRLINE","FLIGHT_NUMBER","DESTINATION_AIRPORT","ORIGIN_AIRPORT"] for item in cols: data[item] = data[item].astype("category").cat.codes +1 train, test, y_train, y_test = train_test_split(data.drop(["ARRIVAL_DELAY"], axis=1), data["ARRIVAL_DELAY"], random_state=10, test_size=0.25)
最終的數據集大概長這個樣子:
和 CatBoost 以及 LGBM 算法不一樣,XGBoost 自己沒法處理分類變量,而是像隨機森林同樣,只接受數值數據。所以在將分類數據傳入 XGBoost 以前,必須經過各類編碼方式:例如標記編碼、均值編碼或獨熱編碼對數據進行處理。
import xgboost as xgb from sklearn.grid_search import GridSearchCV from sklearn import metrics def auc(m, train, test): return (metrics.roc_auc_score(y_train,m.predict_proba(train)[:,1]), metrics.roc_auc_score(y_test,m.predict_proba(test)[:,1])) Parameter Tuning model = xgb.XGBClassifier() param_dist = {"max_depth": [10,30,50], "min_child_weight" : [1], "n_estimators": [200], "learning_rate": [0.16],} grid_search = GridSearchCV(model, param_grid=param_dist, cv = 3, verbose=10, n_jobs=-1) grid_search.fit(train, y_train) grid_search.best_estimator_ model = xgb.XGBClassifier(max_depth=10, min_child_weight=1, n_estimators=200,\ n_jobs=-1 , verbose=1,learning_rate=0.16) train.shape,y_train.shape#((42855, 10), (42855,)) model.fit(train,y_train) auc(model,train,test)#過擬合 (1.0, 0.6990888367179413)
和 CatBoost 相似,LighGBM 也能夠經過使用特徵名稱的輸入來處理屬性數據;它沒有對數據進行獨熱編碼,所以速度比獨熱編碼快得多。LGBM 使用了一個特殊的算法來肯定屬性特徵的分割值。注意,在創建適用於 LGBM 的數據集以前,須要將分類變量轉化爲整型變量;此算法不容許將字符串數據傳給分類變量參數。
import lightgbm as lgb from sklearn import metrics def auc2(m, train, test): return (metrics.roc_auc_score(y_train,m.predict(train)), metrics.roc_auc_score(y_test,m.predict(test))) lg = lgb.LGBMClassifier(silent=False) param_dist = {"max_depth": [25,50, 75], "learning_rate" : [0.01,0.05,0.1], "num_leaves": [300,900,1200], "n_estimators": [200] } grid_search = GridSearchCV(lg, n_jobs=-1, param_grid=param_dist, cv = 3, scoring="roc_auc", verbose=5) grid_search.fit(train,y_train) grid_search.best_estimator_ d_train = lgb.Dataset(train, label=y_train) params = {"max_depth": 50, "learning_rate" : 0.1, "num_leaves": 900, "n_estimators": 300} # Without Categorical Features model2 = lgb.train(params, d_train) auc2(model2, train, test)#(1.0, 0.6813950368358092)
#With Catgeorical Features cate_features_name = ["MONTH","DAY","DAY_OF_WEEK","AIRLINE","DESTINATION_AIRPORT", "ORIGIN_AIRPORT"] d_train = lgb.Dataset(train, label=y_train) model2 = lgb.train(params, d_train, categorical_feature = cate_features_name) auc2(model2, train, test)#(1.0, 0.6781812538027399)
在對 CatBoost 調參時,很難對分類特徵賦予指標。所以,同時給出了不傳遞分類特徵時的調參結果,並評估了兩個模型:一個包含分類特徵,另外一個不包含。我單獨調整了獨熱最大量,由於它並不會影響其餘參數。
若是未在cat_features參數中傳遞任何內容,CatBoost會將全部列視爲數值變量。注意,若是某一列數據中包含字符串值,CatBoost 算法就會拋出錯誤。另外,帶有默認值的 int 型變量也會默認被當成數值數據處理。在 CatBoost 中,必須對變量進行聲明,纔可讓算法將其做爲分類變量處理。
import catboost as cb cat_features_index = [0,1,2,3,4,5,6] def auc(m, train, test): return (metrics.roc_auc_score(y_train,m.predict_proba(train)[:,1]), metrics.roc_auc_score(y_test,m.predict_proba(test)[:,1])) params = {'depth': [4, 7, 10], 'learning_rate' : [0.03, 0.1, 0.15], 'l2_leaf_reg': [1,4,9], 'iterations': [300]} cb = cb.CatBoostClassifier() cb_model = GridSearchCV(cb, params, scoring="roc_auc", cv = 3) cb_model.fit(train, y_train) # With Categorical features clf = cb.CatBoostClassifier(eval_metric="AUC", depth=10, iterations= 500, l2_leaf_reg= 9, learning_rate= 0.15) %timeit clf.fit(train,y_train) auc(clf, train, test)#(0.7994405189483305, 0.7097991233818941)
# With Categorical features clf = cb.CatBoostClassifier(eval_metric="AUC",one_hot_max_size=31, \ depth=10, iterations= 500, l2_leaf_reg= 9, learning_rate= 0.15) clf.fit(train,y_train, cat_features= cat_features_index) auc(clf, train, test)#(0.7937591249216596, 0.7167802198229718)
請記住,CatBoost 在測試集上表現得最好,測試集的準確度最高(0.716)、過擬合程度最小(在訓練集和測試集上的準確度很接近)以及最小的預測和調試時間。但這個表現僅僅在有分類特徵,並且調節了獨熱最大量時纔會出現。若是不利用 CatBoost 算法在這些特徵上的優點,它的表現效果就會變成最差的:僅有 0.709 的準確度。所以咱們認爲,只有在數據中包含分類變量,同時咱們適當地調節了這些變量時,CatBoost 纔會表現很好。
第二個使用的是 XGBoost,它的表現也至關不錯。即便不考慮數據集包含有轉換成數值變量以後能使用的分類變量,它的準確率也和 CatBoost 很是接近了。可是,XGBoost 惟一的問題是:它太慢了。尤爲是對它進行調參,很是使人崩潰。更好的選擇是分別調參,而不是使用 GridSearchCV。
最後一個模型是 LightGBM,這裏須要注意的一點是,在使用 CatBoost 特徵時,LightGBM 在訓練速度和準確度上的表現都很是差。我認爲這是由於它在分類數據中使用了一些修正的均值編碼方法,進而致使了過擬合(訓練集準確率很是高:1.0,尤爲是和測試集準確率相比之下)。但若是咱們像使用 XGBoost 同樣正常使用 LightGBM,它會比 XGBoost 更快地得到類似的準確度,若是不是更高的話(LGBM—0.681, XGBoost—0.699)。
最後必須指出,這些結論在這個特定的數據集下成立,在其餘數據集中,它們可能正確,也可能並不正確。但在大多數狀況下,XGBoost 都比另外兩個算法慢。
參考文獻:
【1】從結構到性能,一文概述XGBoost、Light GBM和CatBoost的同與不一樣
【2】CatBoost vs. Light GBM vs. XGBoost
【3】Catboost學習筆記
【5】github:https://github.com/catboost/catboost/tree/master/catboost/tutorials