CatBoost的Python與R實現

2021-03-02 表哥有話講

作者:徐靜  AI圖像算法研發工程師

博客:https://dataxujing.github.io/

GitHub: https://github.com/DataXujing

CatBoost(Categorical Boosting)算法是一種類似於XGBoost,LightGBM的Gradient Boosting算法,其算法創新主要有兩個:一個是對於離散特徵值的處理,採用了ordered TS(target statistic)的方法;其二是提供了兩種訓練模式:Ordered和Plain,其具體的偽代碼如下圖所示:

通過ordered boosting的思想解決了Gradient Boosting中常出現的prediction shift問題。


CatBoost目前支持通過Python,R和命令行進行調用和訓練,支持GPU,其提供了強大的訓練過程可視化功能,可以使用jupyter notebook,CatBoost Viewer,TensorBoard可視化訓練過程,學習文檔豐富,易於上手。

本文帶大家結合kaggle中titanic公共數據集基於Python和R訓練CatBoost模型。


Python實現CatBoost

1.加載數據:



```pythonfrom catboost.datasets import titanicimport numpy as npfrom sklearn.model_selection import train_test_splitfrom  catboost import CatBoostClassifier, Pool, cvfrom sklearn.metrics import accuracy_score
train_df, test_df = titanic()
X = train_df.drop('Survived', axis=1)y = train_df.Survived
# 數據劃分X_train, X_validation, y_train, y_validation = train_test_split(X, y, train_size=0.75, random_state=42)
X_test = test_df```


這裡我們直接使用數據框的結構,對於CatBoost支持numpy中的數組和pandas中的數據框,同時也提供了一種pool數據結構,如果有速度和內存佔用優化的需求,官方建議使用pool數據結構,本文我們使用數據框結構作為例子。


2.使用hyperopt調參:

```python
import hyperoptfrom numpy.random import RandomState
# 目的是最小化目標函數def hyperopt_objective(params): model = CatBoostClassifier( l2_leaf_reg=int(params['l2_leaf_reg']), learning_rate=params['learning_rate'], iterations=500, eval_metric='Accuracy', random_seed=42, logging_level='Silent' ) cv_data = cv( Pool(X, y, cat_features=categorical_features_indices), model.get_params() ) best_accuracy = np.max(cv_data['test-Accuracy-mean']) return 1 - best_accuracy
# 需要優化的參數備選取值params_space = { 'l2_leaf_reg': hyperopt.hp.qloguniform('l2_leaf_reg', 0, 2, 1), 'learning_rate': hyperopt.hp.uniform('learning_rate', 1e-3, 5e-1),}
trials = hyperopt.Trials()
# 參數搜索best = hyperopt.fmin( hyperopt_objective, space=params_space, algo=hyperopt.tpe.suggest, max_evals=50, trials=trials, rstate=RandomState(123))
# 列印最優的參數組合,並使用交叉驗證重新訓練print(best)
```


在最優參數下做交叉驗證:

```python
model = CatBoostClassifier( l2_leaf_reg=int(best['l2_leaf_reg']), learning_rate=best['learning_rate'], iterations=500, eval_metric='Accuracy', random_seed=42, logging_level='Silent')cv_data = cv(Pool(X, y, cat_features=categorical_features_indices), model.get_params())
model.fit(X, y, cat_features=categorical_features_indices)```


除此之外我們也可以採用網格搜索或隨機參數搜索,下面我們提供了gridsearchCV的過程供參考:

```python
from catboost import CatBoostClassifier
def auc(m, X_train, X_test): return (metrics.roc_auc_score(y——train,m.predict_proba(X_train)[:,1]), metrics.roc_auc_score(y_test,m.predict_proba(X_test)[:,1]))
params = {'depth': [4, 7, 10], 'learning_rate' : [0.03, 0.1, 0.15], 'l2_leaf_reg': [1,4,9], 'iterations': [300]}cb = CatBoostClassifier()model = GridSearchCV(cb, params, scoring="roc_auc", cv = 3)model.fit(X_train,y_train,cat_features=categorical_features_indices)```


訓練過程中會有很多有意思的參數可供調整,主要是針對於訓練速度和精度的參數,除此之外還有一些可視化和和GPU相關的參數,詳細的可參考CatBoost的官方文檔。


3.變量重要性與預測:

```python# 列印變量重要性feature_importances = model.get_feature_importance(X_train)feature_names = X_train.columnsfor score, name in sorted(zip(feature_importances, feature_names), reverse=True):    print('{}: {}'.format(name, score))
# 預測# 3種模式的預測結果展示print(model.predict_proba(data=X_validation))print(model.predict(data=X_validation))raw_pred = model.predict(data=X_validation, prediction_type='RawFormulaVal')print(raw_pred)
import mathdef sigmoid(x): return 1 / (1 + math.exp(-x))probabilities = [sigmoid(x) for x in raw_pred]print(np.array(probabilities))
```


4.模型持久化:

```python# 模型保存(後綴名可以換成其他)model.save_model('catboost_model.bin')
# 模型加載my_best_model.load_model('catboost_model.bin')print(my_best_model.get_params())print my_best_model.random_seed_print my_best_model.learning_rate_
```


R語言實現CatBoost

1.構建Pool數據


A.從文件中讀取:

```Rlibrary(catboost)library(caret)library(titanic)
pool_path <- system.file("extdata","adult_train.1000",package="catboost")column_description_path <- system.file("extdata","adult.cd",package="catboost")pool <- catboost.load_pool(pool_path,column_description=column_description_path)
head(pool,1)
```


主要有兩個文件,一個是具體的特徵值文件pool_path,一個是列的描述文件column_description_path,主要描述了列的屬性,目前主要包括三種:

Target (label);Categ;Num(default type),並且要注意這裡的列的索引沿用了Python方式從0開始。


B.從矩陣中獲取:

```Rpool_path = system.file("extdata", "adult_train.1000", package="catboost")
column_description_vector = rep('numeric', 15)cat_features <- c(3, 5, 7, 8, 9, 10, 11, 15)for (i in cat_features) column_description_vector[i] <- 'factor'
data <- read.table(pool_path, head = F, sep = "\t", colClasses = column_description_vector, na.strings='NAN')
# Transform categorical features to numeric.for (i in cat_features) data[,i] <- as.numeric(factor(data[,i]))

target <- c(1)data_matrix <- as.matrix(data)pool <- catboost.load_pool(as.matrix(data[,-target]), label = as.matrix(data[,target]), cat_features = cat_features)head(pool, 1)
```


注意矩陣中都是數值型的數據,因此,首先在進入矩陣前的數據需進行數值化,然後在構建pool數據結構時指定離散特徵的列標。


C.從數據框中獲取:

```Rtrain_path = system.file("extdata", "adult_train.1000", package="catboost")test_path = system.file("extdata", "adult_test.1000", package="catboost")
column_description_vector = rep('numeric', 15)cat_features <- c(3, 5, 7, 8, 9, 10, 11, 15)for (i in cat_features) column_description_vector[i] <- 'factor' train <- read.table(train_path, head = F, sep = "\t", colClasses = column_description_vector, na.strings='NAN')test <- read.table(test_path, head = F, sep = "\t", colClasses = column_description_vector, na.strings='NAN')target <- c(1)train_pool <- catboost.load_pool(data=train[,-target], label = train[,target])test_pool <- catboost.load_pool(data=test[,-target], label = test[,target])head(train_pool, 1)head(test_pool, 1)
```


注意離散變量需要轉化為因子變量,數值型變量即為數值型變量,label也應該是數值型變量。


2.訓練模型與預測

```Rfit_params <- list(iterations = 100,                   thread_count = 10,                   loss_function = 'Logloss',                   ignored_features = c(4,9),                   border_count = 32,                   depth = 5,                   learning_rate = 0.03,                   l2_leaf_reg = 3.5,                   train_dir = 'train_dir',                   logging_level = 'Silent'                  )model <- catboost.train(train_pool, test_pool, fit_params)
# 更多參數可以help(catboost.train)
# accuracy方法calc_accuracy <- function(prediction, expected) { labels <- ifelse(prediction > 0.5, 1, -1) accuracy <- sum(labels == expected) / length(labels) return(accuracy)}
# 概率預測prediction <- catboost.predict(model, test_pool, prediction_type = 'Probability')cat("Sample predictions: ", sample(prediction, 5), "\n")
# class預測labels <- catboost.predict(model, test_pool, prediction_type = 'Class')table(labels, test[,target])
# works properly only for Loglossaccuracy <- calc_accuracy(prediction, test[,target])cat("\nAccuracy: ", accuracy, "\n")
# 變量重要性計算cat("\nFeature importances", "\n")catboost.get_feature_importance(model, train_pool)
cat("\nTree count: ", model$tree_count, "\n")
```


3.使用caret包


A.加載數據:

```rset.seed(12345)
data <- as.data.frame(as.matrix(titanic_train), stringsAsFactors=TRUE)
age_levels <- levels(data$Age)most_frequent_age <- which.max(table(data$Age))data$Age[is.na(data$Age)] <- age_levels[most_frequent_age]
drop_columns = c("PassengerId", "Survived", "Name", "Ticket", "Cabin")x <- data[,!(names(data) %in% drop_columns)]y <- data[,c("Survived")]```


B.基於caret的模型訓練:

```rfit_control <- trainControl(method = "cv",                            number = 5,                            classProbs = TRUE)
grid <- expand.grid(depth = c(4, 6, 8), learning_rate = 0.1, iterations = 100, l2_leaf_reg = 0.1, rsm = 0.95, border_count = 64)
model <- train(x, as.factor(make.names(y)), method = catboost.caret, logging_level = 'Silent', preProc = NULL, tuneGrid = grid, trControl = fit_control)
```


C.列印模型和變量重要性:

```r
print(model)
importance <- varImp(model, scale = FALSE)print(importance)```


D.預測:

```rpre_prob <- predict(model, type = 'prob')print(pre_prob)```


Reference

[1] https://github.com/catboost/tutorials

[2] https://github.com/catboost

[3] CatBoost: unbiased boosting with categorical features

[4] CatBoost: gradient boosting with categorical features support

[5] 誰是數據競賽王者? CatBoost vs. Light GBM vs. XGBoost

—————————————

往期精彩:

相關焦點

  • CatBoost詳解
    One-hot encoding可以在數據預處理時完成,也可以在模型訓練的時候完成,從訓練時間的角度,後一種方法的實現更為高效,CatBoost對於低勢類別特徵也是採用後一種實現。顯然,在高勢特徵當中,比如 user ID,這種編碼方式會產生大量新的特徵,造成維度災難。一種折中的辦法是可以將類別分組成有限個的群體再進行 One-hot encoding。
  • 【務實基礎】CatBoost
    所以Catboost中,作者在CatBoost的梯度提升算法中做了些修改,詳見後續偽代碼部分。Catboost捕捉高階依賴的類別特徵組合成額外的類別特徵,例如廣告點擊預測中的用戶ID和廣告話題。特徵組合隨數據集的類別特徵數量增加呈指數型增長,這不太好。所以Catboost使用貪婪策略構建特徵組合,即,對一個樹的每個分裂點,Catboost會組合所有現有樹中已被歷史分裂使用過的類別特徵 (和它們的組合)。
  • XGBoost使用
    例如為了確定估計器的數目,也就是boosting迭代的次數,也可以說是殘差樹的數目,參數名為n_estimators、num_iterations、num_round、num_boost_round都是等價的,都是num_boost_round的別名。後面的代碼示例中對2種API都會分別進行示例說明使用方法。
  • 插件化開發利器--boost.dll
    return a + 2;}void call_from_so(){ typedef int (*plus_ptr)(int); void* handle = dlopen("libmy.so", RTLD_NOW); if(handle){ plus_ptr p = (plus_ptr)dlsym(handle, "plus"); auto r
  • PYTHON中XGBOOST的使用
    1.數據讀取 import xgboost as xgb data = xgb.DMatrix(libsvm文件)
  • Python 調用系統命令的模塊 Subprocess
    Run 方法使用 運行外部命令要實現和 os.system()命令相同的方式,運行外部命令而不與之交互時候,我們可以使用 run()函數。前面提到了這是一個高級函數先看一下其語法結構。r}')    print(f'stderr is {completed.stderr!
  • 入門模塊Subprocess,用Python調用系統命令
    注意:在 Unix 和 Windows 系統上工作的應用編程接口大致相同,但是底層的實現是不同的,因為作業系統中的過程模型不同。這裡顯示的所有示例都是在 Mac 作業系統上測試的。在非 Unix 作業系統上的行為可能會有所不同。例如 unix 系統查看文件列表使用 ls,windows 只能使用 dir.
  • python實現高斯樸素貝葉斯分類器
    python實現高斯樸素貝葉斯分類器    在這篇文章中,我們將使用我最喜歡的機器學習庫scikit-learn在Python中實現樸素貝葉斯分類器。接下來,我們將使用經過訓練的樸素貝葉斯(監督分類法)模型來預測人口收入。
  • Python 還能實現圖片去霧?FFA 去霧算法、暗通道去霧算法用起來!(附代碼)
    其中得到的去霧效果如下:實驗前的準備首先我們使用的python版本是3.6.5所用到的模塊如下:Pytorch模塊用來模型訓練和網絡層建立;其底層和Torch框架一樣,但是使用Python重新寫了很多內容,不僅更加靈活,支持動態圖,而且提供了Python
  • Python 基於直方圖的梯度提升集成方法
    scikit-learn機器學習庫提供了支持直方圖技術的梯度提升的實驗實現。它可能在XGBoost之前實現了直方圖技術,但是XGBoost後來又實現了相同的技術,突出了梯度提升庫之間的「梯度提升效率」競爭。可以使用您喜歡的Python軟體包管理器(例如Pip)安裝LightGBM庫。
  • python 進階知識點總結
    (定義函數時,避免定義與內置函數名一樣)遞歸(實現1~n的和):def fun(num):    if num == 0:        return 0    return fun(num-1) + numfun(5)               #結果得出15python的可變參數: https:/
  • 用Python實現神奇切圖算法Seam Carving
    這個算法能實現什麼效果呢?這項技術能計算出圖像上的「關鍵部分」和「不重要區域」,從而使得隨意改變一個圖像的高寬比但「不會讓圖像內容變得扭曲變形」。而使用接縫剪裁算法就能實現二者兼得。關於算法的核心原理,在原論文中解釋的非常清楚了,網上也有很多解析文章,這裡不再贅述。在本文我(作者Karthik Karanth——譯者注)就以上面所舉的例子為素材,重點講講如何用Python基本實現接縫剪裁算法。
  • Python 中用 XGBoost 和 scikit-learn 進行隨機梯度增強
    _['mean_test_score']stds = grid_result.cv_results_['std_test_score']params = grid_result.cv_results_['params']for mean, stdev, param in zip(means, stds, params): print("%f (%f) with: %r"
  • 每天一個linux命令(10):cat 命令
    1.命令格式:cat [選項] [文件]...2.命令功能:cat主要有三大功能:1.一次顯示整個文件:cat filename2.從鍵盤創建一個文件:cat > filename 只能創建新文件,不能編輯已有文件.
  • 使用python+sklearn實現高斯過程回歸
    本示例以兩種不同的方式來實現簡單的一維回歸:在這兩種情況下,
  • Python系列特別篇-Conda和JupyterLab
    ~% cat ~/.condarc channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ - defaultsshow_channel_urls: true或者通過命令設置:
  • 業界 | Facebook 開源語音識別工具包wav2letter(附實現教程)
    該實現的原作者包括 Ronan Collobert、Christian Puhrsch、Gabriel Synnaeve、Neil Zeghidour 和 Vitaliy Liptchinsky。wav2letter 實現的是論文「Wav2Letter: an End-to-End ConvNet-based Speech Recognition System」以及「Letter-Based Speech Recognition with Gated ConvNets」中提出的架構(如果你使用了這個模型或預訓練模型,請引用以上兩篇論文之一)。
  • 如何把Python和Bash搞在一起解決問題
    以下示例中的一系列命令通過將較小的構建塊連結在一起,顯示了更複雜的實用工具的功能:$ cat names.log | sort | uniq | wc -l    管道符號(|)用於將一個命令的標準輸出傳遞到下一命令的標準輸入。在此處的示例中,cat names.txt的輸出傳遞到sort命令中。
  • 用 Python 實現溺水識別
    所以今天我們也是做一個計算機視覺方面的訓練,用python來判斷用戶溺水行為,結合姿態識別和圖像識別得到結果。其中包括姿態識別和圖像分類。首先圖像分類是根據各自在圖像信息中所反映的不同特徵,把不同類別的目標區分開來的圖像處理方法。