前言
此篇文章为整个Boost(提升方法)集成算法模型的终章,前几篇文章依次结合详细项目案例讲解了AdaBoost、GBDT、XGBoost、LighGBM共四个常用的集成算法模型,每一篇文章都包含实战项目以及可运行代码。仅通过看一遍文章不去实践是很难掌握集成算法模型的,其中很多思想和优化参数的方法需要长期使用才能掌握,集成学习的方法在全球各大机器学习、数据挖掘竞赛中使用的非常广泛,其概念和思想也是风靡学术界和工业界,所以有此需求的朋友推荐细读实践。
之前我们已经详细描述了AdaBoost算法模型和GBDT原理以及实践。通过这两类算法就可以明白Boosting算法的核心思想以及基本的运行计算框架,余下几种Boosting算法都是在前者的算法之上改良得到,尤其是以GBDT算法为基础改进衍生出的三种Boosting算法:XGBoost、LightGBM、CatBoost。看过之前GBDT的读者应该对GBDT模型有了一个很清楚的认知,对于理解CatBoost算法有一定的基础。
作为一个从事数据建模五年的专业人士,我参与了许多数学建模项目,了解各种模型的原理、建模流程和题目分析方法。我希望通过这个专栏让你能够快速掌握各类数学模型、机器学习和深度学习知识,并掌握相应的代码实现。每篇文章都包含实际项目和可运行的代码。我会紧跟各类数模比赛,将最新的思路和代码分享给你,保证你能够高效地学习这些知识。
博主非常期待与你一同探索这个精心打造的专栏,里面充满了丰富的实战项目和可运行的代码,希望你不要错过:专栏链接
一、CatBoost
CatBoost(Categorical Boosting)是由俄罗斯搜索引擎巨头Yandex开发的一种梯度提升树算法。它可以与深度学习框架轻松集成。它可以处理多种数据类型,以帮助解决企业今天面临的各种问题。CatBoost 和 XGBoost、LightGBM 并称为 GBDT 的三大主流神器,都是在 GBDT 算法框架下的一种改进实现。XGBoost 被广泛的应用于工业界,LightGBM 有效的提升了 GBDT 的计算效率,而 Yandex 的 CatBoost 号称是比 XGBoost 和 LightGBM 在算法准确率等方面表现更为优秀的算法。
CatBoost相比与其他GBDT算法系列,其特点以下表可以清楚区别:
算法差异点 | GBDT | XGBoost | LightGBM | CatBoost |
弱学习器 | CART回归树 | 1.CART回归树 2.线性学习器 3.Dart树 | Leaf-wise树 | 对称树 |
寻找分裂点 | 贪心算法 | 近似算法 | 直方图算法 | 预排序算法 |
稀疏值处理 | 无 | 稀疏感知算法 | EFB(互斥特征捆绑) | 无 |
类别特征 | 不直接支持,可自行编码后输入模型 | 同GBDT | 直接支持,GS编码 | 直接支持,Ordered TS编码 |
并行支持 | 不可以 | 可以 | 可以 | 可以 |
CatBoost最大的特点是能够直接处理类别型特征,而不需要进行独热编码或其他转换,这点和LightGBM算法相同,但是二者采取编码的算法不同,CatBoost比LightGBM处理类别特征也更加直接。
CatBoost 是一种基于 对称决策树(oblivious trees)为基学习器实现的参数较少、支持类别型变量和高准确性的GBDT框架:GBDT,主要解决的痛点是高效合理地处理类别型特征,这一点从它的名字中可以看出来,CatBoost 是由 Categorical 和 Boosting 组成。此外,CatBoost 还解决了梯度偏差(Gradient Bias)以及预测偏移(Prediction shift)的问题,从而减少过拟合的发生,进而提高算法的准确性和泛化能力。
此外,CatBoost 梯度提升算法库中的学习算法基于 GPU 实现,打分算法基于 CPU 实现。
1.CatBoost算法特点
1.1自动处理分类特征
CatBoost 能够直接处理分类特征,无需进行独热编码或其他预处理。这使得它在处理实际数据时更为方便。
import catboost
from catboost import CatBoostClassifier, Pool# 假设我们有一个包含分类特征的数据集
X = [[1, 'a', 0.1], [2, 'b', 0.2], [3, 'a', 0.3], [4, 'b', 0.4]]
y = [0, 1, 0, 1]# 创建一个 Pool 对象,它会自动识别分类特征
dataset = Pool(data=X, label=y, cat_features=[1])# 初始化并训练一个 CatBoost 分类器
model = CatBoostClassifier(iterations=100, depth=6, learning_rate=0.1, loss_function='Logloss', verbose=200)
model.fit(dataset)# 进行预测
preds = model.predict(dataset)# 输出预测结果
print(preds)
在这个示例中,我们使用了一个简单的数据集 X
,其中包含了一个整数特征、一个字符串特征和一个浮点数特征。我们将分类特征的索引传递给 cat_features
参数,CatBoost 将会自动识别并处理这些特征。我们创建了一个 Pool
对象,它会自动将分类特征编码为数字。接着,我们初始化了一个 CatBoost 分类器,并对其进行训练。
最后,我们使用训练好的模型进行预测。CatBoost 可以自动处理分类特征,无需进行额外的独热编码等预处理步骤。
1.2自动处理缺失值
数据存在缺失值是很正常的,一般来说我们会采取很多方法去填充这些空值,可以使用均值或者统计指标,也可以使用机器学习算法去学习再填充,而CatBoost会在训练过程中学习如何处理缺失值。它会自动将缺失值的处理纳入模型中,而无需进行显式的填充或处理。CatBoost会将缺失值视为一个特定的数值,这个数值在内部被用作缺失值的标识符。
对分类特征的处理:对于分类特征,CatBoost会将缺失值作为一个额外的类别,不需要对其进行特殊处理。
对数值特征的处理:对于数值特征,CatBoost会将缺失值视为一个额外的分支,因此不会影响其他分支的计算。
对目标变量的处理:在目标变量中也可以包含缺失值。CatBoost会自动处理这些缺失值,并在训练过程中进行适当的计算。
1.3特征重要性评估
CatBoost可以通过内置的get_feature_importance()
方法来获取特征重要性评估。这个方法返回一个包含特征重要性得分的数组,可以用来衡量每个特征对于模型预测的贡献程度。这大大增加了模型的可解释性,帮助理解模型。
1.4可交互模型过程可视化
CatBoost自带的可交互模型过程可视化,查看模型的学习过程。
模型交叉验证
2.CatBoost算法计算原理
首先基础的流程还是和GBDT一致的:
相较于GBDT、XGBoost、LightGBM算法,CatBoost算法有很多特点,但最引人注目的还是这两个:
- 对分类型特征的处理。这使得我们在训练模型之前可以考虑不用再通过特征工程去处理分类型特征
- 预测偏移处理。这可以减少模型的过拟合,提升模型预测效果
2.1ordered TS编码
这是基于TS编码改进的一种编码方式。对于一些类别基数比较小的特征,例如2~3类,可以直接使用one-hot编码,但对于类别基数较大的特征,one-hot编码会产生特征维度问题,这种情况下TS编码会合适一些。
CatBoost算法中采用了ordered TS编码方法来解决Greedy TS编码的目标泄露问题。ordered TS编码是基于排序的,在CatBoost算法中,会对样本进行多次洗牌,每次得到不同排序状态的样本集。
排序的目的产生一种随机性,减少过拟合。每一轮迭代、构建一个树时,都会选择一种排序状态的样本集,这样在不同轮次迭代中,不同排序状态的样本集综合起来,会使模型的方差更小,越不容易过拟合。
主要有以下几个步骤:
- 产生一个随机排列顺序 并对数据集进行编号
- 对于训练样本:
- 对于测试样本:
- 根据带先验概率的Greedy TS计算
这样计算得到的 Ordered TS能够满足P1,同时也能够使用所有的训练样本。且比在线学习的划窗(sliding window)处理能够进一步减小 的方差。需要注意的是,CatBoost在不同的迭代上会采用不同的排列顺序。
下面是Ordered TS与其它各种TS在不同数据集上面在logloss/zero-one loss上面的效果比较:
2.2 特征组合
CatBoost的另一个重要实现是在构建决策树时,动态地考虑了不同类别型特征的组合,从而获取了高阶依赖关系。例如,在广告点击预测中,考虑了用户ID与广告话题之间的联合信息,或者在音乐推荐中,结合了用户ID和音乐流派的信息。
这一实现涉及到了对特征组合的动态考虑。在树的第一次分割时,不考虑任何特征的组合。然而,在下一个分割时,CatBoost会将当前树的所有组合特征、类别型特征与数据集中的所有类别型特征相结合。这种方法能够动态地将新的组合类别型特征转换为数值型特征,以便在树的构建过程中考虑到更多的信息。
具体来说,CatBoost会将树中选定的所有分割点都视为具有两个值的类别型特征,然后像对待普通的类别型特征一样,将它们进行组合考虑。这种策略能够在不引入过多特征组合的情况下,依然有效地捕获到特征之间的复杂关系,从而提升了模型的性能。
感兴趣的推荐阅读paper很有帮助:http://learningsys.org/nips17/assets/papers/paper_11.pdf
2.3 预测偏移处理
基础原理还是和GBDT一致:在梯度提升中,每个弱学习器的训练都是基于前一个弱学习器的预测误差,通过梯度下降的方式来最小化误差。具体来说,对于回归问题,我们可以选择平方损失函数作为损失函数。关于梯度提升算法我之前在Logistic原理详解和遗传算法里面也有详解讲过,此类最优算法最核心的一点就是对于残差的使用。而损失函数就是衡量调整每一次迭代模型算法的权重的参考功能。
这个技术的实现原理是通过在目标函数中引入PredictionValuesChange
,使得模型在训练时会在最小化损失的同时,尽量保持预测值的稳定性。这样,在测试时,即使输入的数据分布与训练集有所不同,模型也能够更好地适应新的数据分布,保证了模型的泛化性能。
CatBoost的预测偏移处理通过反复对样本进行重新排序来减小预测方差。在这个过程中,模型会根据当前迭代的样本排序计算梯度,以获取一个无偏估计。然而,对于排名靠前的样本,由于它们是由较少的样本训练的,因此估计结果可能会有一定的不准确性和较大的方差。
为了解决这个问题,CatBoost在每轮迭代中都会重新对样本进行排序,然后基于新的排序计算梯度。这样做的好处是,在多轮迭代的过程中,模型可以逐步获取更为准确的梯度估计,从而降低了预测的方差。
二、实现贷款违约预测
上述的理论其实是比较复杂的,博主本人研究此算法也花了很大一部分工作去阅读原papar和其他解释文章。最重要的是我们能够使用catboost来进行一些实际案例运行,这点对我们来说更为重要。对于贷款违约预测这个比较经典的课题,我们很容易拿到现成的数据,对于建模来讲,我们最缺的就是数据,而阿里天池提供了一份开源贷款违约数据,大家直接下载即可,具体看博主资源免费下载:https://download.csdn.net/download/master_hunter/88434149
1.数据背景及描述
赛题以预测用户贷款是否违约为任务,数据集报名后可见并可下载,该数据来自某信贷平台的贷款记录,总数据量超过120w,包含47列变量信息,其中15列为匿名变量。为了保证比赛的公平性,将会从中抽取80万条作为训练集,20万条作为测试集A,20万条作为测试集B,同时会对employmentTitle、purpose、postCode和title等信息进行脱敏。
字段表
Field | Description |
---|---|
id | 为贷款清单分配的唯一信用证标识 |
loanAmnt | 贷款金额 |
term | 贷款期限(year) |
interestRate | 贷款利率 |
installment | 分期付款金额 |
grade | 贷款等级 |
subGrade | 贷款等级之子级 |
employmentTitle | 就业职称 |
employmentLength | 就业年限(年) |
homeOwnership | 借款人在登记时提供的房屋所有权状况 |
annualIncome | 年收入 |
verificationStatus | 验证状态 |
issueDate | 贷款发放的月份 |
purpose | 借款人在贷款申请时的贷款用途类别 |
postCode | 借款人在贷款申请中提供的邮政编码的前3位数字 |
regionCode | 地区编码 |
dti | 债务收入比 |
delinquency_2years | 借款人过去2年信用档案中逾期30天以上的违约事件数 |
ficoRangeLow | 借款人在贷款发放时的fico所属的下限范围 |
ficoRangeHigh | 借款人在贷款发放时的fico所属的上限范围 |
openAcc | 借款人信用档案中未结信用额度的数量 |
pubRec | 贬损公共记录的数量 |
pubRecBankruptcies | 公开记录清除的数量 |
revolBal | 信贷周转余额合计 |
revolUtil | 循环额度利用率,或借款人使用的相对于所有可用循环信贷的信贷金额 |
totalAcc | 借款人信用档案中当前的信用额度总数 |
initialListStatus | 贷款的初始列表状态 |
applicationType | 表明贷款是个人申请还是与两个共同借款人的联合申请 |
earliesCreditLine | 借款人最早报告的信用额度开立的月份 |
title | 借款人提供的贷款名称 |
policyCode | 公开可用的策略_代码=1新产品不公开可用的策略_代码=2 |
n系列匿名特征 | 匿名特征n0-n14,为一些贷款人行为计数特征的处理 |
数据均被处理过,详细处理过程在我的另一篇文章上有具体代码和每一个步骤的数据可视化展示:
一文速学-XGBoost模型算法原理以及实现+Python项目实战
2.划分数据集
首先每天catboost库的需要安装:
pip installl catboost
导入sklearn帮助我们快速搭建模型和计算对应指标:
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import pandas as pd
train=pd.read_csv("df2.csv")
train=train.iloc[:10000,2:]
# 划分特征变量与目标变量
X=train.drop(columns='isDefault')
Y=train['isDefault']
# 划分训练及测试集
X_train,X_test,y_train,y_test=train_test_split(X,Y,test_size=0.2,random_state=0)
3.权重统计
首先我们可以尝试使用用CatBoost内置函数计算权重:
from catboost.utils import get_roc_curve
# 创建并训练一个CatBoost分类器
model = CatBoostClassifier(iterations=100, depth=6, learning_rate=0.1, loss_function='Logloss')
model.fit(X_train, y_train)
# 假设 df 是你的 Pandas DataFrame
train_data = catboost.Pool(data=X_train, label=y_train)
# 获取特征重要性评估
feature_importance = model.get_feature_importance(data=train_data, type='LossFunctionChange')# 打印特征重要性得分
for i, score in enumerate(feature_importance):print(f'Feature {i}: {score}')
4.构建分类器
from catboost.utils import get_roc_curve
# 创建并训练一个CatBoost分类器
model = CatBoostClassifier(iterations=100, depth=6, learning_rate=0.1, loss_function='Logloss')
model.fit(X_train, y_train,plot=True)
可以通过详细输出或使用漂亮的绘图来观察我们的模型学习,我们使用CatBoost自带的可交互模型过程可视化,查看模型的学习过程。只需要在fit函数加入参数plot就可展示:
5.模型验证
Catboost 做模型评估时,同一般模型少有区别,该模型在 model.fit()
时,传递给参数 eval_set
相应的验证子集,设置参数 plot
为 True
,即可在训练模型的同时,用验证集评估模型,并且输出过程可视化结果,可谓是非常方便与惊艳。
model = CatBoostClassifier(iterations=50,random_seed=63,learning_rate=0.5,custom_loss=['AUC', 'Accuracy']
)
model.fit(X_train, y_train,eval_set=(X_test, y_test),verbose=False,plot=True
)
6.模型参数比较
与模型评估一样,使用相同 CatBoostClassifier 分类器,仅仅设置不同的 learning_rate
,并设置train_dir
分别为 'learing_rate_0.7'
及 'learing_rate_0.01'
。
model1 = CatBoostClassifier(learning_rate=0.7,iterations=100,random_seed=0,train_dir='learing_rate_0.7'
)model2 = CatBoostClassifier(learning_rate=0.01,iterations=100,random_seed=0,train_dir='learing_rate_0.01'
)
model1.fit(X_train, y_train,eval_set=(X_test, y_test),verbose=False,plot=True
)
model2.fit(X_train, y_train,eval_set=(X_test, y_test),verbose=False,plot=True
)
然后使用catboost的MetricVisualizer
方法比较两个模型。该方法在单个图表上绘制有关训练、指标评估或交叉验证运行的信息。根据输入信息,一个图表可以包含有关一次或多次运行的信息。图表既可以在训练进行时实时绘制,也可以在训练结束后绘制。
7.模型交叉验证
相比sklearn的交叉验证方法,Catboost 模型自带的交叉验证方法简单、灵活,还可以直接显示可视化交叉验证过程及结果:
from catboost import cv
# 设置参数空间
params = {}
params['loss_function'] = 'Logloss'
params['iterations'] = 80
params['custom_loss'] = 'AUC'
params['random_seed'] = 63
params['learning_rate'] = 0.01
# 直接使用catboost中自带的cv参数。
cv_data = cv(params = params,pool = Pool(X_train, label=y_train), # 设置Pool类。fold_count=5,shuffle=True,partition_random_seed=0,plot=True, # 设置可视化过程stratified=False, verbose=False
)
Training on fold [0/5]bestTest = 0.4962901383 bestIteration = 79Training on fold [1/5]bestTest = 0.5072516938 bestIteration = 79Training on fold [2/5]bestTest = 0.4983888444 bestIteration = 79Training on fold [3/5]bestTest = 0.4938201036 bestIteration = 79Training on fold [4/5]bestTest = 0.4921619437 bestIteration = 79
可获取最佳得分:
import numpy as np
best_value = np.min(cv_data['test-Logloss-mean'])
best_iter = np.argmin(cv_data['test-Logloss-mean'])print('Best validation Logloss score, not stratified: {:.4f}±{:.4f} on step {}'.format(best_value,cv_data['test-Logloss-std'][best_iter],best_iter)
)
Best validation Logloss score, not stratified: 0.4976±0.0059 on step 79
8.过拟合检验
在创建CatBoostClassifier实例时,设置参数early_stopping_rounds=20(根据实际情况设置),模型可以在 early_stopping_rounds 所设置的迭代轮数内寻找模型效果最好的,这个模型效果评价指标可以通过eval_metric设置,默认 Logloss,也可以设置为"AUC"。还可以通过设置custom_metric参数,使用自定义评价指标函数。
model_with_early_stop = CatBoostClassifier(eval_metric='AUC',iterations=200,random_seed=63,learning_rate=0.5,early_stopping_rounds=20
)
model_with_early_stop.fit(X_train, y_train,eval_set=(X_test, y_test),verbose=False,plot=True
)
9.模型预测及指标检验
通过sklearn可以快速可视化模型预测结果:
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split
import xgboost as xgb
from sklearn.model_selection import KFold
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as pltresult = []
mean_score = 0
labels=[0,1]
y_pred=model.predict_proba(X_test)[:,1]
def classify_convert(x):if x >0.5:return 1else:return 0
list_predict=[]
for i in y_pred:list_predict.append(classify_convert(i))
cm= confusion_matrix(y_test.values, list_predict)
sns.heatmap(cm,annot=True ,fmt="d",xticklabels=labels,yticklabels=labels)
print('验证集auc:{}'.format(roc_auc_score(y_test, y_pred)))
mean_score += roc_auc_score(y_test, y_pred)
plt.title('confusion matrix') # 标题
plt.xlabel('Predict lable') # x轴
plt.ylabel('True lable') # y轴
plt.show()
# 模型评估
print('mean 验证集Auc:{}'.format(mean_score))
cat_pre=sum(result)
from sklearn.metrics import f1_score
print('F1_socre:{}'.format(f1_score(y_test.values, list_predict, average='weighted')))
from sklearn.metrics import recall_score
print('Recall_score:{}'.format(recall_score(y_test.values, list_predict, average='weighted')))
from sklearn.metrics import precision_score
print('Percosopn:{}'.format(precision_score(y_test.values, list_predict, average='weighted')))
模型效果比上期我们用XGBoost模型预测的效果还要优秀。
10.权重展示
对于数据集的每个特征权重,我们可以适当的丢掉一些影响准确的的特征,增加我们模型的计算速率和数据使用空间,通过get_feature_names可以或得权重数值,通过数据可视化可以轻松获取需要的特征:
# 获取特征名称
feature_names = train_data.get_feature_names()
# 将特征重要性和特征名称结合起来,创建一个字典
feature_importance_dict = dict(zip(feature_names, feature_importance))# 将特征重要性排序
sorted_feature_importance = sorted(feature_importance_dict.items(), key=lambda x: x[1], reverse=True)# 提取排序后的特征名称和重要性
sorted_feature_names, sorted_feature_importance = zip(*sorted_feature_importance)plt.figure(figsize=(10, 6))
plt.barh(sorted_feature_names[:10], sorted_feature_importance[:10])
plt.xlabel('Feature Importance')
plt.title('Top 10 Important Features')
plt.gca().invert_yaxis() # 反转y轴以显示重要性高的特征在顶部
plt.show()
11.获取最优参数
要在指定的数据集上获取CatBoost算法模型的最优训练参数,可以使用交叉验证(Cross Validation)和网格搜索(Grid Search)的方法。CatBoost支持使用GPU进行加速,可以加快我们训练速度:
from catboost import CatBoostClassifier, Pool, cv
from sklearn.model_selection import GridSearchCV
train=pd.read_csv("df2.csv")
train=train.iloc[:40000,2:]
# 划分特征变量与目标变量
X=train.drop(columns='isDefault')
Y=train['isDefault']
# 划分训练及测试集
X_train,X_test,y_train,y_test=train_test_split(X,Y,test_size=0.2,random_state=0)
train_data = Pool(X_train, label=y_train)param_grid = {'depth': [4, 6, 8],'learning_rate': [0.1, 0.05, 0.01,0.001]
}
model = CatBoostClassifier(task_type="GPU")grid_search = GridSearchCV(estimator=model, param_grid=param_grid, scoring='accuracy', cv=3, verbose=2, n_jobs=-1)grid_search.fit(X_train,y_train)
best_params = grid_search.best_params_
best_model = CatBoostClassifier(depth=best_params['depth'], learning_rate=best_params['learning_rate'])
best_model.fit(train_data)