机器学习CatBoost
CatBoost(categorical boosting)是一种能够很好地处理类别型特征的梯度提升算法库。本文中,对 CatBoost 基本原理及应用实例做个详细介绍。后面小猴子还将针对其中几个重要特性做专门介绍,如 CatBoost 对类别型特征处理、特征选择、文本特征处理、超参数调整以及多标签目标处理!

梯度提升概述

要理解 boosting,首先理解集成学习,为了获得更好的预测性能,集成学习结合多个模型(弱学习器)的预测结果。它的策略就是大力出奇迹,因为弱学习器的有效组合可以生成更准确和更鲁棒的模型。集成学习方法分为三大类:

  • Bagging:该技术使用随机数据子集并行构建不同的模型,并聚合所有预测变量的预测结果。
  • Boosting:这种技术是可迭代的、顺序进行的和自适应的,因为每个预测器都是针对上一个模型的错误进行修正。
  • Stacking:这是一种元学习技术,涉及结合来自多种机器学习算法的预测,例如 bagging 和 boosting。

    什么是 CatBoost

    CatBoost(categorical boosting)是 Yandex 开源的机器学习算法。它可以与深度学习框架轻松集成。它可以处理多种数据类型,以帮助解决企业今天面临的各种问题。CatBoost 和 XGBoost、LightGBM 并称为 GBDT 的三大主流神器,都是在 GBDT 算法框架下的一种改进实现。XGBoost 被广泛的应用于工业界,LightGBM 有效的提升了 GBDT 的计算效率,而 Yandex 的 CatBoost 号称是比 XGBoost 和 LightGBM 在算法准确率等方面表现更为优秀的算法。
    CatBoost 是一种基于 对称决策树(oblivious trees)为基学习器实现的参数较少、支持类别型变量和高准确性的GBDT框架,主要解决的痛点是高效合理地处理类别型特征,这一点从它的名字中可以看出来,CatBoost 是由 Categorical 和 Boosting 组成。此外,CatBoost 还解决了梯度偏差(Gradient Bias)以及预测偏移(Prediction shift)的问题,从而减少过拟合的发生,进而提高算法的准确性和泛化能力。
    此外,CatBoost 梯度提升算法库中的学习算法基于 GPU 实现,打分算法基于 CPU 实现。

    CatBoost 的主要特点

    CatBoost 优于同类产品的一些关键特性:

    1、对称树

    与 XGBoost 和 LightGBM 不同,CatBoost 构建对称(平衡)树。在每一步中,前一棵树的叶子都使用相同的条件进行拆分。选择损失最低的特征分割对并将其用于所有级别的节点。这种平衡的树结构有助于高效的 CPU 实现,减少预测时间,模型结构可作为正则化以防止过度拟合。
    在对称决策树中,只使用一个特性来构建每个树级别上的所有分支。使用图示方法更加清晰地观察三种类型的拆分:”FloatFeature”、”OneHotFeature” 和 “OnlineCtr”。

    FloatFeature

    模型没有类别型特征时,在可视化的树中只有 “FloatFeature” 节点。”FloatFeature” 拆分对应的节点包含特征索引和边界值,用于拆分对象。
    1. boston = load_boston()
    2. y = boston['target']
    3. X = boston['data']
    4. pool = catboost.Pool(data=X, label=y)
    5. model = CatBoostRegressor(depth=2, verbose=False, iterations=1).fit(X, y)
    6. model.plot_tree(tree_idx=0,
    7. # pool=pool, )
    彻底理解 CatBoost 原理及代码 - 图1
    在这个例子中,深度为0的节点表示对象被它们的第0个带边界值的特征分割。类似地,深度1的节点通过其具有边界值的第二个特征来分割对象。

    OneHotFeature

    ```python titanic_df = titanic()

X = titanic_df[0].drop(‘Survived’,axis=1) y = titanic_df[0].Survived

分类变量的缺失值用”NAN”填充,代码略

pool = Pool(X, y, cat_features=cat_features_index, feature_names=list(X.columns)) model = CatBoostClassifier( max_depth=2, verbose=False, max_ctr_complexity=1, random_seed=42, iterations=2).fit(pool) model.plot_tree( tree_idx=0, pool=pool # 对于一个需要使用独热编码的特征,”pool” 是一个必须的参数 )

  1. ![](https://cdn.nlark.com/yuque/0/2022/png/396745/1657866527185-3c3f35f3-6080-4618-998d-ecb54683b199.png#clientId=u0f7e6450-c0a1-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u0f7ae94b&margin=%5Bobject%20Object%5D&originHeight=454&originWidth=1080&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=shadow&taskId=u41c27cef-2977-4c89-a7ae-f12cb54f043&title=)<br />第一棵树只包含一个由"OneHotFeature"特征产生的分裂。这种分割将"Sex=female"的对象放在左边,而"other"的对象放在右边。
  2. <a name="aLoYH"></a>
  3. #### **OnlineCtr**
  4. ```python
  5. model.plot_tree(tree_idx=1, pool=pool)

彻底理解 CatBoost 原理及代码 - 图2

2、Ordered Boosting

经典提升算法存在预测偏移的问题,容易在小的/嘈杂的数据集上过度拟合。在计算数据实例的梯度估计时,这些算法使用与构建模型相同的数据实例,因此没有机会遇到看不见的数据。
另一方面,CatBoost 使用排序提升的概念,这是一种置换驱动的方法,在数据子集上训练模型,同时在另一个子集上计算残差,从而防止目标泄漏和过度拟合。

3、鲁棒性

它减少了对大量超参数调整的需求,并降低了过度拟合的机会,这也导致了更通用的模型。虽然,CatBoost 有多个参数需要调整,它包含树的数量、学习率、正则化、树深度、折叠大小、装袋温度等参数。您可以在此处阅读所有这些参数。

4、原生特征支持,易于使用

CatBoost 支持数字、分类或文本的各种特征,节省了预处理的时间和精力。可以从命令行使用 CatBoost,使用 Python 和 R 的用户友好 API。

CatBoost 的基本使用

导入基本数据

使用 CatBoost 库里自带的经典数据集 titanic。

  1. from catboost.datasets import titanic
  2. import numpy as np
  3. train_df, test_df = titanic()
  4. # 用一些超出分布范围的数字来填充缺失值
  5. train_df.fillna(-999, inplace=True)
  6. test_df.fillna(-999, inplace=True)
  7. # 拆分特征变量及标签变量
  8. X = train_df.drop('Survived', axis=1)
  9. y = train_df.Survived
  10. # 划分训练集和测试集
  11. from sklearn.model_selection import train_test_split
  12. X_train, X_validation, y_train, y_validation = train_test_split(X, y, train_size=0.75, random_state=42)
  13. X_test = test_df

Titanic 数据集中的特征变量具有不同的类型—有些是数值类型,有些是分类类型,甚至有些只是字符串类型,通常应该以某种特定的方式进行处理(例如使用词袋表示进行编码)。但这里可以将这些字符串特征视为分类特征——所有繁重的工作都是在 CatBoost 中完成的。

创建一个baseline模型

首先从一个基础baseline模型开始,认识如何使用catboost进行预测目标。

  1. # !pip install catboost
  2. from catboost import CatBoostClassifier, Pool, metrics, cv
  3. from sklearn.metrics import accuracy_score
  4. model = CatBoostClassifier(
  5. custom_loss=[metrics.Accuracy()], # 该指标可以计算logloss,并且在该规模的数据集上更加光滑
  6. random_seed=42,
  7. logging_level='Silent'
  8. )
  9. # 模型训练
  10. model.fit(
  11. X_train, y_train,
  12. cat_features=categorical_features_indices,
  13. eval_set=(X_validation, y_validation),
  14. # logging_level='Verbose', # you can uncomment this for text output
  15. plot=True
  16. );

可以通过详细输出或使用漂亮的绘图来观察模型学习,使用CatBoost自带的可交互模型过程可视化,查看模型的学习过程。
彻底理解 CatBoost 原理及代码 - 图3

特征变量统计

Float feature

  1. feature = 'Fare'
  2. res = model.calc_feature_statistics(
  3. X_train, y_train, feature, plot=True)

彻底理解 CatBoost 原理及代码 - 图4

One-hot feature

  1. feature = 'Sex'
  2. res = model.calc_feature_statistics(X_train, y_train, feature, plot=True)

彻底理解 CatBoost 原理及代码 - 图5

模型交叉验证

验证模型是否是性能最佳的,使用交叉验证,可能甚至会得到更好的模型。

  1. cv_params = model.get_params()
  2. cv_params.update({
  3. 'loss_function': metrics.Logloss()
  4. })
  5. cv_data = cv(
  6. Pool(X, y, cat_features=categorical_features_indices),
  7. cv_params,
  8. plot=True
  9. )

彻底理解 CatBoost 原理及代码 - 图6
现在得到了每个 boosting 步骤 3folds 平均的损失函数值,这提供了更准确的模型性能估计。

  1. print('Best validation accuracy score: {:.2f}±{:.2f} on step {}'.format(
  2. np.max(cv_data['test-Accuracy-mean']),
  3. cv_data['test-Accuracy-std'][np.argmax(cv_data['test-Accuracy-mean'])],
  4. np.argmax(cv_data['test-Accuracy-mean'])
  5. ))
  6. print('Precise validation accuracy score: {}'.format(np.max(cv_data['test-Accuracy-mean'])))
  1. Best validation accuracy score:
  2. 0.83±0.02 on step 355
  3. Precise validation accuracy score:
  4. 0.8294051627384961

如上所示,最初对单次验证的性能估计并不是特别理想,而经过交叉验证后会有所提升。

模型应用

模型训练结束后,可以保存模型,以供预测使用。

  1. predictions = model.predict(X_test)
  2. predictions_probs = model.predict_proba(X_test)
  3. print(predictions[:10])
  4. print(predictions_probs[:10])
  1. [0 0 0 0 1 0 1 0 1 0]
  2. [[0.85473931 0.14526069]
  3. [0.76313031 0.23686969]
  4. [0.88972889 0.11027111]
  5. [0.87876173 0.12123827]
  6. [0.3611047 0.6388953 ]
  7. [0.90513381 0.09486619]
  8. [0.33434185 0.66565815]
  9. [0.78468564 0.21531436]
  10. [0.39429048 0.60570952]
  11. [0.94047549 0.05952451]]

CatBoost 应用案例

出于演示目的,同样使用 catboost 自带的 amazon 数据集。

  1. import pandas as pd
  2. import os
  3. import numpy as np
  4. np.set_printoptions(precision=4)
  5. import catboost
  6. from catboost import *
  7. from catboost import datasets
  8. (train_df, test_df) = catboost.datasets.amazon()
  9. train_df.head()

彻底理解 CatBoost 原理及代码 - 图7

数据预处理

数据标签提取

  1. y = train_df.ACTION
  2. X = train_df.drop('ACTION', axis=1)

检查数据集中标签平衡性

  1. print('Labels: {}'.format(set(y)))
  2. print('Zero count = {}, One count = {}'.format(len(y) - sum(y), sum(y)))
  1. abels: {0, 1}
  2. Zero count = 1897, One count = 30872

保存数据

  1. dataset_dir = './amazon'
  2. if not os.path.exists(dataset_dir):
  3. os.makedirs(dataset_dir)
  4. train_df.to_csv(
  5. os.path.join(dataset_dir, 'train.csv'),
  6. index=False, sep=',', header=True
  7. )
  8. test_df.to_csv(
  9. os.path.join(dataset_dir, 'test.csv'),
  10. index=False, sep=',', header=True
  11. )

创建 Pool 类

  1. from catboost.utils import create_cd
  2. feature_names = dict()
  3. for column, name in enumerate(train_df):
  4. if column == 0:
  5. continue
  6. feature_names[column - 1] = name
  7. create_cd(
  8. label=0,
  9. cat_features=list(range(1, train_df.columns.shape[0])),
  10. feature_names=feature_names,
  11. output_path=os.path.join(dataset_dir, 'train.cd')
  12. )
  1. !cat amazon/train.cd
  2. 0 Label
  3. 1 Categ RESOURCE
  4. 2 Categ MGR_ID
  5. 3 Categ ROLE_ROLLUP_1
  6. 4 Categ ROLE_ROLLUP_2
  7. 5 Categ ROLE_DEPTNAME
  8. 6 Categ ROLE_TITLE
  9. 7 Categ ROLE_FAMILY_DESC
  10. 8 Categ ROLE_FAMILY
  11. 9 Categ ROLE_CODE

这里展示了几种创建Pool的不同方法,实际中选中其中一种创建方法即可。

  1. pool1 = Pool(data=X, label=y, cat_features=cat_features)
  2. pool2 = Pool(
  3. data=os.path.join(dataset_dir, 'train.csv'),
  4. delimiter=',',
  5. column_description=os.path.join(dataset_dir, 'train.cd'),
  6. has_header=True
  7. )
  8. pool3 = Pool(data=X, cat_features=cat_features)
  9. # 创建Pool的最快方法是从numpy矩阵创建它。
  10. # 如果你想要快速的预测或者以最快的方式在python中加载数据,就应该使用这种方式。
  11. X_prepared = X.values.astype(str).astype(object)
  12. # 对于FeaturesData类,类别特性必须具有str类型
  13. pool4 = Pool(
  14. data=FeaturesData(
  15. cat_feature_data=X_prepared,
  16. cat_feature_names=list(X)
  17. ),
  18. label=y.values
  19. )
  20. print('Dataset shape')
  21. print('dataset 1:' + str(pool1.shape) +
  22. '\ndataset 2:' + str(pool2.shape) +
  23. '\ndataset 3:' + str(pool3.shape) +
  24. '\ndataset 4:' + str(pool4.shape))
  25. print('\n')
  26. print('Column names')
  27. print('dataset 1:')
  28. print(pool1.get_feature_names())
  29. print('\ndataset 2:')
  30. print(pool2.get_feature_names())
  31. print('\ndataset 3:')
  32. print(pool3.get_feature_names())
  33. print('\ndataset 4:')
  34. print(pool4.get_feature_names())
  1. Dataset shape
  2. dataset 1:(32769, 9)
  3. dataset 2:(32769, 9)
  4. dataset 3:(32769, 9)
  5. dataset 4:(32769, 9)
  6. Column names
  7. dataset 1:
  8. ['RESOURCE', 'MGR_ID', 'ROLE_ROLLUP_1',
  9. 'ROLE_ROLLUP_2', 'ROLE_DEPTNAME',
  10. 'ROLE_TITLE', 'ROLE_FAMILY_DESC',
  11. 'ROLE_FAMILY', 'ROLE_CODE']
  12. dataset 2:
  13. ['RESOURCE', 'MGR_ID', 'ROLE_ROLLUP_1',
  14. 'ROLE_ROLLUP_2', 'ROLE_DEPTNAME',
  15. 'ROLE_TITLE', 'ROLE_FAMILY_DESC',
  16. 'ROLE_FAMILY', 'ROLE_CODE']
  17. dataset 3:
  18. ['RESOURCE', 'MGR_ID', 'ROLE_ROLLUP_1',
  19. 'ROLE_ROLLUP_2', 'ROLE_DEPTNAME',
  20. 'ROLE_TITLE', 'ROLE_FAMILY_DESC',
  21. 'ROLE_FAMILY', 'ROLE_CODE']
  22. dataset 4:
  23. ['RESOURCE', 'MGR_ID', 'ROLE_ROLLUP_1',
  24. 'ROLE_ROLLUP_2', 'ROLE_DEPTNAME',
  25. 'ROLE_TITLE', 'ROLE_FAMILY_DESC',
  26. 'ROLE_FAMILY', 'ROLE_CODE']

拆分训练集和测试集

这一步大家应该比较熟悉,就不做过多的介绍。

  1. from sklearn.model_selection import train_test_split
  2. X_train, X_validation, y_train, y_validation = train_test_split(
  3. X, y, train_size=0.8, random_state=1234)

选择目标函数

对于二分类数据集,目标函数可以选择Logloss,如果要预测目标标签的概率值,推荐使用交叉熵CrossEntropy。

  1. from catboost import CatBoostClassifier
  2. model = CatBoostClassifier(
  3. iterations=5,
  4. learning_rate=0.1,
  5. # loss_function='CrossEntropy'
  6. )
  7. model.fit(
  8. X_train, y_train,
  9. cat_features=cat_features,
  10. eval_set=(X_validation, y_validation),
  11. verbose=False
  12. )
  13. print('Model is fitted: ' + str(model.is_fitted()))
  14. print('Model params:')
  15. print(model.get_params())
  1. Model is fitted: True
  2. Model params:
  3. {'iterations': 5, 'learning_rate': 0.1}

训练模型

模型训练与通常sklearn模型训练差异不大,先实例化模型 model,然后直接 fit 训练即可。

  1. from catboost import CatBoostClassifier
  2. model = CatBoostClassifier(
  3. iterations=15,
  4. # verbose=5,
  5. )
  6. model.fit(
  7. X_train, y_train,
  8. cat_features=cat_features,
  9. eval_set=(X_validation, y_validation),
  10. )

彻底理解 CatBoost 原理及代码 - 图8

评估模型

Catboost 做模型评估时,同一般模型少有区别,该模型在 model.fit() 时,传递给参数 eval_set 相应的验证子集,设置参数 plot 为 True,即可在训练模型的同时,用验证集评估模型,并且输出过程可视化结果,可谓是非常方便与惊艳。

  1. from catboost import CatBoostClassifier
  2. model = CatBoostClassifier(
  3. iterations=50,
  4. random_seed=63,
  5. learning_rate=0.5,
  6. custom_loss=['AUC', 'Accuracy']
  7. )
  8. model.fit(
  9. X_train, y_train,
  10. cat_features=cat_features,
  11. eval_set=(X_validation, y_validation),
  12. verbose=False,
  13. plot=True
  14. )

彻底理解 CatBoost 原理及代码 - 图9

模型比较

与模型评估一样,使用相同 CatBoostClassifier 分类器,仅仅设置不同的 learning_rate,并设置train_dir分别为 'learing_rate_0.7''learing_rate_0.01'

  1. model1 = CatBoostClassifier(
  2. learning_rate=0.7,
  3. iterations=100,
  4. random_seed=0,
  5. train_dir='learing_rate_0.7'
  6. )
  7. model2 = CatBoostClassifier(
  8. learning_rate=0.01,
  9. iterations=100,
  10. random_seed=0,
  11. train_dir='learing_rate_0.01'
  12. )
  13. model1.fit(
  14. X_train, y_train,
  15. eval_set=(X_validation, y_validation),
  16. cat_features=cat_features,
  17. verbose=False
  18. )
  19. model2.fit(
  20. X_train, y_train,
  21. eval_set=(X_validation, y_validation),
  22. cat_features=cat_features,
  23. verbose=False
  24. )

然后使用catboost的MetricVisualizer方法比较两个模型。该方法在单个图表上绘制有关训练、指标评估或交叉验证运行的信息。根据输入信息,一个图表可以包含有关一次或多次运行的信息。图表既可以在训练进行时实时绘制,也可以在训练结束后绘制。

  1. from catboost import MetricVisualizer
  2. MetricVisualizer(['learing_rate_0.01', 'learing_rate_0.7']).start()

彻底理解 CatBoost 原理及代码 - 图10

交叉验证

在前面已经提到,使用交叉验证可以得到性能更好的模型,进而得到更好的预测结果。相对使用sklearn 中的交叉验证方法,Catboost 模型自带的交叉验证方法简单、灵活,还可以直接显示可视化交叉验证过程及结果。下面小猴子录制了动画,展示交叉验证过程。

  1. from catboost import cv
  2. # 设置参数空间
  3. params = {}
  4. params['loss_function'] = 'Logloss'
  5. params['iterations'] = 80
  6. params['custom_loss'] = 'AUC'
  7. params['random_seed'] = 63
  8. params['learning_rate'] = 0.5
  9. # 直接使用catboost中自带的cv参数。
  10. cv_data = cv(
  11. params = params,
  12. pool = Pool(X, label=y, cat_features=cat_features), # 设置Pool类。
  13. fold_count=5,
  14. shuffle=True,
  15. partition_random_seed=0,
  16. plot=True, # 设置可视化过程
  17. stratified=False,
  18. verbose=False
  19. )

彻底理解 CatBoost 原理及代码 - 图11
交叉验证过程中所有数据都记录下来并以DataFrame格式返回,可以直接查看,或后续使用,非常方便!

  1. cv_data.head()

彻底理解 CatBoost 原理及代码 - 图12
其实,只关心最佳得分,使用如下方法可以轻松获得:

  1. best_value = np.min(cv_data['test-Logloss-mean'])
  2. best_iter = np.argmin(cv_data['test-Logloss-mean'])
  3. print('Best validation Logloss score, not stratified: {:.4f}±{:.4f} on step {}'.format(
  4. best_value,
  5. cv_data['test-Logloss-std'][best_iter],
  6. best_iter)
  7. )
  1. Best validation Logloss score,
  2. not stratified: 0.1581±0.0104 on step 52

过拟合检验

在创建CatBoostClassifier实例时,设置参数early_stopping_rounds=20(根据实际情况设置),模型可以在 early_stopping_rounds 所设置的迭代轮数内寻找模型效果最好的,这个模型效果评价指标可以通过eval_metric设置,默认 Logloss,也可以设置为”AUC”。还可以通过设置custom_metric参数,使用自定义评价指标函数。

  1. model_with_early_stop = CatBoostClassifier(
  2. eval_metric='AUC',
  3. iterations=200,
  4. random_seed=63,
  5. learning_rate=0.5,
  6. early_stopping_rounds=20
  7. )
  8. model_with_early_stop.fit(
  9. X_train, y_train,
  10. cat_features=cat_features,
  11. eval_set=(X_validation, y_validation),
  12. verbose=False,
  13. plot=True
  14. )

彻底理解 CatBoost 原理及代码 - 图13

  1. print(model_with_early_stop.tree_count_)
  1. 30

可以使用tree_count_属性查看在何时停止的。

选择概率决策边界

绘制 ROC 曲线

彻底理解 CatBoost 原理及代码 - 图14
首先使用catboost的工具函数get_roc_curve获取到在验证池中的数据fpr 和 tpr 值,然后将其输入到 sklearn 中的 auc 函数中,计算得到 roc_auc 面积大小。为了更加直观,绘制如下曲线。

  1. from catboost.utils import get_roc_curve
  2. import sklearn
  3. from sklearn import metrics
  4. eval_pool = Pool(X_validation, y_validation, cat_features=cat_features)
  5. curve = get_roc_curve(model, eval_pool)
  6. (fpr, tpr, thresholds) = curve
  7. roc_auc = sklearn.metrics.auc(fpr, tpr)
  8. lw = 2
  9. plt.plot(fpr, tpr, color='darkorange',
  10. lw=lw, label='ROC curve (area = %0.2f)' % roc_auc, alpha=0.5)
  11. plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--', alpha=0.5)

2022-07-15-14-34-11.439726800.png
除了上面上面用于ROC曲线的FPR,TPR,另外还可以绘制FPR,FNR曲线。

  1. from catboost.utils import get_fpr_curve
  2. from catboost.utils import get_fnr_curve
  3. (thresholds, fpr) = get_fpr_curve(curve=curve)
  4. (thresholds, fnr) = get_fnr_curve(curve=curve)
  5. lw = 2
  6. plt.plot(thresholds, fpr, color='blue', lw=lw, label='FPR', alpha=0.5)
  7. plt.plot(thresholds, fnr, color='green', lw=lw, label='FNR', alpha=0.5)

2022-07-15-14-34-11.542884100.png
返回实现指定FNR或FPR所需的概率边界。

  1. from catboost.utils import select_threshold
  2. print(select_threshold(model=model, data=eval_pool, FNR=0.01))
  3. print(select_threshold(model=model, data=eval_pool, FPR=0.01))
  1. 0.48689529945049076
  2. 0.9899713850692811

模型预测

CatBoost预测有四种方式,predictstaged_predictpredict_probastaged_predict_prob。看下他们之间的区别。
首先 predict 和 predict_proba,将模型应用于给定数据集,预测得到结果,predict 是直接得到计算后的结果,如果是二分类,就是0或1。predict_proba 结果是归属于哪种类别的概率值。

  1. print(model.predict_proba(X=X_validation))
  1. [[0.0608 0.9392]
  2. [0.0141 0.9859]
  3. [0.0126 0.9874]
  4. ...
  5. [0.0148 0.9852]
  6. [0.0215 0.9785]
  7. [0.0333 0.9667]]
  1. print(model.predict(data=X_validation))
  1. [1 1 1 ... 1 1 1]

与常规预测不同,Predict() 函数中有个 prediction_type 参数,支持的预测类型包含多种:

  • Probability
  • Class
  • RawFormulaVal
  • Exponent
  • LogProbability

    1. raw_pred = model.predict(
    2. data=X_validation,
    3. prediction_type='RawFormulaVal'
    4. )
    5. print(raw_pred)
    1. [2.7374 4.2445 4.3614 ... 4.1992 3.8198 3.3681]

    可以通过 Sigmoid 函数将上面结果转换为概率。

    1. from numpy import exp
    2. sigmoid = lambda x: 1 / (1 + exp(-x))
    3. probabilities = sigmoid(raw_pred)
    4. print(probabilities)
    1. [0.9392 0.9859 0.9874 ... 0.9852 0.9785 0.9667]

    另一个就是 staged_predict 及 staged_predict_prob,他是阶段预测,仅考虑 trees 在range[0; i) 内的计算结果值。这个范围是通过参数
    eval_period控制的:
    要在应用模型或计算指标时减少要使用的树的数量,将树索引的范围设置为[ntree_start; ntree_end)并将要使用的树的步长设置为eval_period
    此参数定义迭代范围的步骤[ntree_start; ntree_end)。例如,假设设置了以下参数值:

  • ntree_start设置为 0

  • ntree_end设置为 N(总树数)
  • eval_period设置为 2

在这种情况下,将返回以下树范围的结果:[0, 2), [0, 4), ... , [0, N)

  1. predictions_gen = model.staged_predict_proba(
  2. data=X_validation,
  3. ntree_start=0,
  4. ntree_end=5,
  5. eval_period=1
  6. )
  7. try:
  8. for iteration, predictions in enumerate(predictions_gen):
  9. print('Iteration ' + str(iteration) + ', predictions:')
  10. print(predictions)
  11. except Exception:
  12. pass
  1. Iteration 0, predictions:
  2. [[0.3726 0.6274]
  3. ...
  4. [0.3726 0.6274]]
  5. ...
  6. Iteration 4, predictions:
  7. [[0.1388 0.8612]
  8. ...
  9. [0.175 0.825 ]]

在未知数据集上评估模型

使用 eval_metrics 方法计算指定数据集的指定指标。

  1. metrics = model.eval_metrics(
  2. data=pool1,
  3. metrics=['Logloss','AUC'],
  4. ntree_start=0,
  5. ntree_end=0,
  6. eval_period=1,
  7. plot=True
  8. )

彻底理解 CatBoost 原理及代码 - 图17
从可视化结果看,eval_metrics 只包含 Eval 结果曲线,设置了 metrics=['Logloss','AUC'] ,因此包含’Logloss’和’AUC’两条评估曲线。

  1. print('AUC values:')
  2. print(np.array(metrics['AUC']))

彻底理解 CatBoost 原理及代码 - 图18

特征重要性

使用模型自带的get_feature_importance方法。

  1. model.get_feature_importance(prettified=True)

彻底理解 CatBoost 原理及代码 - 图19
使用第三方解释库 Shap。与一般模型直接使用 Shap 有所不同,使用 model.get_feature_importance() 方法,并设置参数 type='ShapValues', 直接输出 shap_values 值,该值可直接用户输出结果值及绘制相应可视化图形。

  1. shap_values = model.get_feature_importance(
  2. pool1, type='ShapValues')
  3. expected_value = shap_values[0,-1]
  4. shap_values = shap_values[:,:-1]
  5. print(shap_values.shape)
  1. (32769, 9)
  1. import shap
  2. shap.initjs()
  3. shap.force_plot(expected_value, shap_values[3,:], X.iloc[3,:])

彻底理解 CatBoost 原理及代码 - 图20

  1. shap.initjs()
  2. shap.force_plot(expected_value, shap_values[91,:], X.iloc[91,:])

彻底理解 CatBoost 原理及代码 - 图21

  1. shap.summary_plot(shap_values, X)

彻底理解 CatBoost 原理及代码 - 图22

  1. X_small = X.iloc[0:200]
  2. shap_small = shap_values[:200]
  3. shap.force_plot(expected_value, shap_small, X_small)

彻底理解 CatBoost 原理及代码 - 图23

特征评估

CatBoost还有个很厉害的功能,就是对指定特征进行评估,给出评估结果,是好是坏

  1. from catboost.eval.catboost_evaluation import *
  2. learn_params = {'iterations': 20, # 2000
  3. 'learning_rate': 0.5, # we set big learning_rate,
  4. # because we have small
  5. # #iterations
  6. 'random_seed': 0,
  7. 'verbose': False,
  8. 'loss_function' : 'Logloss',
  9. 'boosting_type': 'Plain'}
  10. evaluator = CatboostEvaluation(
  11. 'amazon/train.tsv',
  12. fold_size=10000, # <= 50% of dataset
  13. fold_count=20,
  14. column_description='amazon/train.cd',
  15. partition_random_seed=0,
  16. #working_dir=...
  17. )
  18. result = evaluator.eval_features(
  19. learn_config=learn_params,
  20. eval_metrics=['Logloss', 'Accuracy'],
  21. features_to_eval=[6, 7, 8])

以上设定用来评估的特征是[6, 7, 8],从以下结果看到特征6得到正向结论,而特征8得到负向结论,特征7从各项指标中得不到确切的指标。

  1. from catboost.eval.evaluation_result import *
  2. logloss_result = result.get_metric_results('Logloss')
  3. logloss_result.get_baseline_comparison(
  4. ScoreConfig(ScoreType.Rel, overfit_iterations_info=False)
  5. )

彻底理解 CatBoost 原理及代码 - 图24

模型保存和导入

当得到一个较为理想的模型后,需要保存模型,以后期使用模型,因此,该步骤还是非常重要的。而CatBoost保存模型非常方便,无需借助第三方库如pickle等,直接使用其save_model方法,即可保存模型。
save_model保存模型,可以保存为各种格式: