[学习笔记]机器学习——算法及模型(六):Catboost

Catboost 原论文笔记及操作实例

  • 一、Catboost是什么?
  • 二、Catboost 的原理
    • 2.1、类别型特征
      • 2.1.1、Greedy TS
      • 2.1.2、Holdout TS
      • 2.1.3、Leave-one-out TS
      • 2.1.4、Ordered TS
    • 2.2、解决预测偏移
      • 2.2.1、Prediction shift
      • 2.2.2、Ordered boosting
    • 2.3、ordered boosting的实际措施
      • 2.3.1 Building a tree
      • 2.3.2 Choosing leaf values
      • 2.3.3 Complexity
      • 2.3.4 Feature combinations
  • 三、python代码
    • 3.1参数
      • 3.1.1通用参数
      • 3.1.2 性能参数
      • 3.1.3 属性
      • 3.1.4 方法
    • 3.2 实例
  • 参考文献

一、Catboost是什么?

CatBoost是俄罗斯的搜索巨头Yandex在2017年开源的机器学习库,是Categorical Features(类别型特征)+Gradient Boosting(梯度提升) ,也是基于梯度提升决策树的机器学习框架。

大多数流行的梯度提升算法利用决策树作为基本预测器。对于数值型特征使用决策树很方便,但是实际中,许多数据集包括类别型特征,这些特征对预测也很重要。类别型特征具有离散的值,比如省份名(山东,山西,河北等),城市名(北京,上海,南京等)。梯度提升算法中处理这类特征的最常用的方法就是在学习之前,也就是数据预处理阶段,将这些特征的值转换为数字。一般类别型特征会转化为一个或多个数值型特征(one-hot编码等)。

而Catboost从名字就可以看出:可以很好的处理类别型特征的梯度提升算法,该算法的改进之处就在于在学习的时候处理这些特征,而不是在数据预处理阶段,不需要任何显式的预处理来将类别转换为数字。

二、Catboost 的原理

Catboost引入了两个关键的算法改进——实现了有序提升,排列驱动以代替经典算法和用于处理分类特征的创新算法。这些方法旨在解决prediction shift(普遍存在于梯度提升算法中)。

2.1、类别型特征

一种有效的处理类别特征的方法就是:使用一个计算出的数值(target statistic (TS))来代替,即第 k k k个训练样本的第 i i i个类别特征( x k i x_k^i xki),通常根据类别条件估计预期目标y,表达式为: x ^ k i = E ( y ∣ x i = x k i ) \hat{x}_k^i = E(y|x^i = x_k^i) x^ki=E(yxi=xki)

2.1.1、Greedy TS

在决策树中,标签平均值将作为节点分裂的标准。这种方法被称为 Greedy Target Statistics , 简称 Greedy TS,用公式来表达就是:
x ^ k i = ∑ j = 1 n I { x j i = x k i } ⋅ y j ∑ j = 1 n I { x j i = x k i } \hat{x}_k^i = \frac{\sum_{j=1}^nI_{\{x_j^i=x_k^i\}}\cdot y_j} {\sum_{j=1}^nI_{\{x_j^i = x_k^i\}}} x^ki=j=1nI{xji=xki}j=1nI{xji=xki}yj
这里的 I I IIverson brackets(指示函数),即括号里的两个相等时取1,否则取0:
{ x j i = x k i } = { x j i = x k i 1 o t h e r w i s e 0 \{x_j^i = x_k^i\}=\begin{cases} x_j^i=x_k^i &1\\ otherwise &0 \end{cases} {xji=xki}={xji=xkiotherwise10
如果某个标称值 x k i x_k^i xki,只有一条记录的时候,则这个标称值转换成数字后就等于该记录的标签值。这样的处理过程,显然会造成过拟合。
对于这样的低频类别来说是有噪声的,通常用一些先验值p来平滑它:

x ^ k i = ∑ j = 1 n I { x j i = x k i } ⋅ y j + a ⋅ P ∑ j = 1 n I { x j i = x k i } + a \hat{x}_k^i = \frac{\sum_{j=1}^nI_{\{x_j^i=x_k^i\}}\cdot y_j+a\cdot P} {\sum_{j=1}^nI_{\{x_j^i = x_k^i\}}+a} x^ki=j=1nI{xji=xki}+aj=1nI{xji=xki}yj+aP

这里 a > 0 a>0 a>0为参数, P P P通常取作所有数据中目标变量的平均值。
但是这样的贪婪方法会带来是目标泄漏的问题:用 X K X_K XK 的目标值 y k y_k yk 来计算 x k i x_k^i xki;这就会造成条件偏移(condition shift),即:训练集合测试集的 x i ∣ y x^i|y xiy的分布不同。

举一个极端例子,来说明这可能会对所学习模型的泛化误差产生显著的影响:
假设第i个特征是类别型特征,并且该特征所有值都是唯一的,那么对于每一个类型A,在分类任务下,我们能得到 P ( Y = 1 ∣ x i = A ) = 0.5 P(Y=1|x^i=A)=0.5 P(Y=1xi=A)=0.5

  • 训练集里 x ^ k i = y k + a p 1 + a \hat{x}_k^i=\frac{y_k+ap}{1+a} x^ki=1+ayk+ap,这样只需要使用阈值 t = 0.5 + a p 1 + a t=\frac{0.5+ap}{1+a} t=1+a0.5+ap进行一次分割就能对所有的训练集诗句完美分类了。
  • 而在测试集中, x k i x_k^i xki的值为 p p p,对模型进行预测:如果 p < t p<t p<t ,预测值为0,否则为1;最后精准度都是0.5。

避免条件偏移问题有很多方法,通常使用不包括 x k x_k xk样本的其他集合来计算 x k i x_k^i xki的值: D k ⊂ D − { x k } D_k \subset D-\{x_k\} DkD{xk}:
x ^ k i = ∑ X j ∈ D k I { x j i = x k i } ⋅ y j + a ⋅ P ∑ X j ∈ D k I { x j i = x k i } + a \hat{x}_k^i = \frac{\sum_{X_j \in D_k}I_{\{x_j^i=x_k^i\}}\cdot y_j+a\cdot P} {\sum_{X_j \in D_k}I_{\{x_j^i = x_k^i\}}+a} x^ki=XjDkI{xji=xki}+aXjDkI{xji=xki}yj+aP

2.1.2、Holdout TS

将数据集划分为两部分, 一部分用来计算TS,另一部分用来训练,这个方法虽然可以避免条件偏移的问题,但也减少了用于训练模型和计算统计信息数据的数据量。

2.1.3、Leave-one-out TS

乍一看,这种 l e a v e − o n e − o u t leave-one-out leaveoneout 的方法应该行得通,对训练样本 x k i x_k^i xki用排除了 x k x_k xk的剩下样本计算TS,对测试样本则用全量计算TS。但仔细想想,这没有解决target泄露的问题,如:一个不变的分类特征,这样又回到了之前所说的条件偏移的问题。

2.1.4、Ordered TS

Catboost 使用了一种更有效的策略,这个策略是使用了排序原则(ordering principle)也是Catboost 的核心思想,这个是收到了在线学习算法的启发(在线学习算法是通过时间序列来获得训练样本)。
简单地说,就是TS值的计算依靠目前已经观察的样本集。为了适应标准的离线训练时,我们可以随机生成一个排列来实现带时序的训练集,CatBoost在不同的梯度提升步中使用不同的排列。

2.2、解决预测偏移

2.2.1、Prediction shift

在每一步的梯度提升的过程中,也存在预测偏移 prediction shift 的问题,是由一种特殊的目标泄漏引起的。Catboost的解决方案称为有序增强( o r d e r e d ordered ordered b o o s t i n g boosting boosting),类似于Ordered TS方法。

梯度提升算法中,在提升步做法如下:
(1) h t = a r g m i n { h ∈ H } 1 n ∑ k = 1 n ( − g t ( x k , y k ) − h ( x k ) ) h_t=argmin_{\{h\in H\}}\frac{1}{n}\sum^n_{k=1}(-g^t(x_k,y_k)-h(x_k))\tag1 ht=argmin{hH}n1k=1n(gt(xk,yk)h(xk))(1)

h t h_t ht 为新生成的弱分类器, − g t ( x k , y k ) -g^t(x_k,y_k) gt(xk,yk)为损失函数在当前模型的负梯度,即弱分类器要拟合的值

链式偏移可以描述如下:

  • 梯度的条件分布 g t ( x k , y k ) ∣ x k g_t(x_k,y_k)|x_k gt(xk,yk)xk 和训练样本 g t ( x , y ) ∣ x g_t(x,y)|x gt(x,y)x 分布存在偏移;
  • 从而,公式 ( 1 ) ^{(1)} (1)和公式 ( 2 ) ^{(2)} (2)也存在着偏差。
  • 最终,会影响模型 F t F^t Ft的泛化能力。

(2) h t = a r g m i n { h ∈ H } E ( − g t ( x , y ) − h ( x ) ) 2 h_t=argmin_{\{h\in H\}}E(-g^t(x,y)-h(x))^2\tag2 ht=argmin{hH}E(gt(x,y)h(x))2(2)

预测偏移的实例分析:
以具有二次损失函数的回归任务为例,损失函数为 L ( y , y ^ ) = ( y − y ^ ) 2 L(y,\hat{y})=(y-\hat{y})^2 L(y,y^)=(yy^)2,这里负梯度 − g t − 1 ( x k , y k ) = y k − F t − 1 ( x k ) -g^{t-1}(x_k,y_k)=y_k-F^{t-1}(x_k) gt1(xk,yk)=ykFt1(xk)
假设有两个特征 x 1 x^1 x1 x 2 x^2 x2独立同服从伯努利分布(p=0.5),并且 y = f ∗ ( X ) = c 1 x 1 + c 2 x 2 y=f^*(X)=c_1x^1+c_2x^2 y=f(X)=c1x1+c2x2。通过两次梯度提升(深度、步长均为1)的迭代后,我们得到模型: F = F 2 = h 1 + h 2 F=F^2=h^1+h^2 F=F2=h1+h2,假设 h 1 h^1 h1基于变量 x 1 x^1 x1, h 2 h^2 h2基于变量 x 2 x^2 x2

得到以下两个定理(具体证明见原论文):

  • 如果大小相同的两个独立样本 D 1 D_1 D1 D 2 D_2 D2被分别用来估算 h 1 h^1 h1 h 2 h^2 h2,通过公式 ( 1 ) ^{(1)} (1)计算,有
    E D 1 , D 2 F 2 ( x ) = f ∗ ( x ) + O ( 1 / 2 n ) E_{D_1,D_2}F^2(x) =f^*(x)+O(1/2^n) ED1,D2F2(x)=f(x)+O(1/2n),对任意 x ∈ { 0 , 1 } 2 x\in\{0,1\}^2 x{0,1}2
  • 如果相同的数据集 D = D 1 = D 2 D=D_1=D_2 D=D1=D2均用于 h 1 h^1 h1 h 2 h^2 h2,则有 E D F 2 ( x ) = f ∗ ( x ) − 1 n − 1 c 2 ( x 2 − 1 2 ) + O ( 1 / 2 n ) E_{D}F^2(x) =f^*(x)-\frac{1}{n-1}c_2(x^2-\frac{1}{2})+O(1/2^n) EDF2(x)=f(x)n11c2(x221)+O(1/2n)

以上两个定理意味着:当我们在每个梯度步骤中使用独立的数据集时,训练后的模型是对 y = f ∗ ( x ) y =f^*(x) y=f(x)真实依赖关系的无偏估计。否则,使用相同的数据集,则会得到有偏估计的模型,且数据集越大,偏差越小。

2.2.2、Ordered boosting

为了解决上述提到的 prediction shift,方法如下:

  • 随机生成一个[1,n]的排列 σ \sigma σ的训练样本;
  • 来支持n个不同模型 M 1 , ⋯   , M 2 M_1,\cdots,M_2 M1,,M2,使得 M i M_i Mi只用排列中的前 i i i个样本学习的模型。
  • 每一步的迭代,我们通过模型 M j − 1 M_{j-1} Mj1(如下),都可以得到第 j j j个样本残差。
    [学习笔记]机器学习——算法及模型(六):Catboost_第1张图片
    伪代码:
    [学习笔记]机器学习——算法及模型(六):Catboost_第2张图片
    但是,由于上面的方法需要训练n个不同的模型,使得算法的空间复杂度和内存需求增加了n倍。在CatBoost中,对以决策树为基础的梯度增强算法(GBDT)的基础上对该算法进行了修改。

2.3、ordered boosting的实际措施

CatBoost有两种选择树结构的模式:Ordered and Plain
Plain模式:是对应于标准GBDT算法内嵌有序目标统计量的组合(使用了随机排列 σ 0 \sigma^0 σ0);
Ordered模式:是对算法1【Algorithm.1】的有效改进。

2.3.1 Building a tree

在CatBoost中,基本预测器是无关决策树,也称为决策表(类似规则 if…then…else )。这样的“无关”意味着在树的整个层次上使用相同的分割标准。这样的树是平衡的,不容易过度拟合,并允许在测试时显著加快执行。
[学习笔记]机器学习——算法及模型(六):Catboost_第3张图片
Ordered Mode 中,在学习训练的过程中,维护的模型 M r , j M_{r,j} Mr,j,如 M r , j ( i ) M_{r,j}(i) Mr,j(i)则是用排列 σ r \sigma_r σr的前 j j j个样本来计算第 i i i个样本。在算法中每步迭代 t t t中,都在一个随机排列 σ r \sigma_r σr的基础上构建树 T t T_t Tt

2.3.2 Choosing leaf values

在所有树结构都建立好的情况下,对两种模式均采用标准梯度增强程序计算最终模型F的叶子节点值。对于分类变量就需要使用随机排列 σ r \sigma_r σr

2.3.3 Complexity

Ordered Mode 中,只储存和更新 M r , j ′ ( i ) : = M r , 2 j ( i ) M_{r,j}^{'}(i):=M_{r,2^j}(i) Mr,j(i):=Mr,2j(i) j = 1 , ⋯   , [ l o g 2 n ] j =1,\cdots,[log_2n] j=1,,[log2n] σ r ( i ) < = 2 j + 1 \sigma_r(i)<= 2^{j+1} σr(i)<=2j+1),这样,计算模型的时间复杂度就从 O ( s O(s O(s n 2 ) n^2) n2)减少为 O ( s O(s O(s n ) n) n)

每次迭代中两种CatBoost模式不同模式的计算复杂度:
在这里插入图片描述
这里的 N T S , t N_{TS,t} NTS,t 是在迭代t中要计算TS的数量, C C C是在给定迭代中要考虑的候选分割集;由此可见,使用决策树实现的有序增强与使用有序TS的标准GBDT具有相同的渐近复杂度。

2.3.4 Feature combinations

CatBoost的另一个重要细节是使用分类特征的组合作为附加分类特征,比如:在广告点击预测任务中捕获用户ID和广告主题的联合信息等,此类高阶依赖关系的信息。但是,组合数量随着数据集中分类特征的数量呈指数增长,所以,不可能处理所有这些组合。

CatBoost以贪婪的方式构造组合。也就是说:对于树的第一次分割,不考虑任何组合,对于树的下一个分割,CatBoost将当前树中用于以前分割的所有分类特性(及其组合)与数据集中的所有分类特性组合在一起。组合被动态转换为TS。

三、python代码

3.1参数

from catboost import CatBoostClassifier #分类
from catboost import CatBoostRegressor  #回归

3.1.1通用参数

这里介绍几个比较常用的参数,详细参数的解释,见catboost官网

  • learning_rate(eta)=automatically or 0.03学习率,数值or automatically。数值越小,训练所需的迭代次数就越高。
  • depth(max_depth)=6树的深度。可以试任何不大于32的int。推荐值:1-10
  • l2_leaf_reg(reg_lambda)=3L2正则化系数。可以是任何正值。
  • iterations=1000: 解决ml问题的树的最大数量
  • one_hot_max_size=2: 对于所有具有多个不同值小于或等于给定参数值的特性,使用one-hot编码。
  • loss_function=’Logloss’:损失函数
  • od_type =IncToDec:过拟合检查类型.{IncToDec;Iter}
  • od_wait=20:在最小化损失函数后的迭代次数;
  • leaf_estimation_method =None:迭代求解的方法,{Newton;Gradient}

3.1.2 性能参数

  • thread_count=-1:训练时所用的cpu/gpu核数
  • used_ram_limit=None:CTR问题,计算时的内存限制
  • gpu_ram_part=None:GPU内存限制
  • task_type=CPU:训练的器件
  • devices=None:训练的GPU设备ID

3.1.3 属性

  • tree_count_:返回模型中的树的数量(int)。
  • feature_importances_:输出计算出的特征重要性(numpy.ndarray)。
  • best_score_:返回针对每个验证数据集计算的每个度量方法的最佳结果。
    eg:
{'validation_0': {'Logloss': 0.6085537606941837, 'AUC': 0.0568}}

3.1.4 方法

fit(X: 输入数据数据类型可以是,[list,pandas.DataFrame]; pandas.Series
    y:None 训练的目标值
    cat_features=None [list,pandas.DataFrame]:将类型特征的列,否则catboost不会对类型特征进行处理。
    sample_weight=None: 输入数据的样本权重
    logging_level=None: 控制是否输出日志信息,或者何种信息
    plot=False: 训练过程中,绘制,度量值,所用时间等
    eval_set=None: 验证集合,数据类型list(X, y) tuples)

predict(data:输入需要预测的数据,
             返回验证样本所属类别,数据类型为np.array)
predict_proba(返回验证样本所属类别的概率,数据类型为np.array)
get_feature_importance(data=None,
                       type=EFstrType.FeatureImportance,
                       prettified=False,
                       thread_count=-1,
                       verbose=False
					   计算并返回特征重要性)

3.2 实例

利用Amazon的员工编号相关信息,来分析和预测当员工申请访问某个编号的资源时,是否被允许访问。

from sklearn.model_selection import train_test_split
import catboost
import catboost.datasets
import matplotlib.pyplot as plt

# 加载数据
train_df, test_df = catboost.datasets.amazon()

# 训练
y = train_df["ACTION"]
X = train_df.drop("ACTION", axis=1)
X_test = test_df

categorical_columns = X.columns
categorical_columns_indices = list(range(len(X.columns)))

X_train, x_test, y_train, y_test = train_test_split(X, y, 
train_size=0.7, random_state=2045)

cb = catboost.CatBoostClassifier(n_estimators=4000,
                         learning_rate= 0.01,
                         one_hot_max_size=2,
                         loss_function='Logloss',
                         eval_metric='AUC',
                         boosting_type='Ordered',
                         random_seed=2405,
                         use_best_model=True,
                         silent=True)

cb.fit(X_train, y_train,cat_features=categorical_columns_indices,eval_set=(x_test, 
y_test),plot=True)

# 显示重要特征
fea_ = cb.feature_importances_
fea_name = cb.feature_names_
plt.figure(figsize=(10, 10))
plt.barh(fea_name,fea_,height =0.5)
plt.show()

参考文献

Catboost介绍
CatBoost:比XGBoost更优秀的GBDT算法
catboost 论文笔记
Mastering The New Generation of Gradient Boosting

你可能感兴趣的:(机器学习)