前几天参加了一个国外的比赛AgentDS Benchmark,内容是寻常的金融风控主题,最后取得了第五名的好成绩哈哈,虽说参加的人数并不多。一开始两个任务都设置了阈值,但是后来因为其中一个比赛超过阈值的人数太少了(只有我,比阈值高一点),官方就把阈值限制取消了。不然只有我能拿奖金。今天就来聊一聊在这个比赛中我学到了什么。
首先,这两个场景各自有侧重点:反欺诈是一个数据高度不平衡的场景,欺诈事件极为罕见,导致模型难以学习有意义的模式。而信用违约预测在需要复杂的模型来提升预测性能的同时,监管机构又要求高度的可解释性——必须能解释为什么某位客户被判定为高风险。
其次,这个比赛鼓励与AI进行协作,我主要是用了传统的机器学习方法进行建模,同时使用了大模型提供了一些新特征生成建议和调参建议。
建模步骤包括:数据整合,特征工程,模型训练和集成优化。
欺诈检测的主要目标是克服极端的数据不平衡。我们通过以下方式实现:
第一,数据缩放:我们选择了 RobustScaler 而非 StandardScaler,因为欺诈数据中充满了异常值——例如,欺诈交易的金额往往极高。RobustScaler 对异常值具有鲁棒性,因此不会让这些极端值扭曲我们的训练过程,而 StandardScaler 对此非常敏感。
第二,SMOTE合成采样:SMOTE(Synthetic Minority Over-sampling Technique,合成少数类过采样技术)是处理不平衡数据的经典解决方案。它不是简单地复制少数类样本(这会导致过拟合),而是通过在邻近的少数类样本点之间进行插值来生成新的合成样本。例如,我们会取一个欺诈样本,找到它的k个最近邻,随机选择其中一个,并在它们之间的连线上创建一个新样本。我们也尝试过在模型中调整类别权重,但SMOTE的效果要好得多。
第三,堆叠集成(stacking model):我们采用了堆叠方法,以逻辑回归作为元模型(meta-model),并为其设置了平衡的类别权重。尽管我们的基模型使用了SMOTE,但元模型的输入(即基模型的输出)仍然是不平衡的。这一步确保了元模型不会偏向多数类(合法交易),从而在保持精确率的同时提高了对欺诈案例的召回率。
对于信用违约预测,可解释性是重中之重——监管机构需要理解我们是如何得出风险评分的。
因此,我们专注于设计透明的特征,每个特征都具有清晰的金融含义。这些特征捕捉了三个关键维度:稳定性、恶化趋势和风险信号——这些都是预测未来一周内违约的关键。让我们看一些例子:
- balance_slope:我们对客户每周的账户余额随时间变化进行线性回归。如果斜率显著小于0,意味着其余额在稳步下降——这是一个强烈的未来违约信号。
- balance_last_minus_mean:该指标衡量客户当前余额与其历史平均值的偏差程度。一个很大的负数表明其当前账户状况远差于平常水平。
- Balance_to_amount:平均余额与平均交易金额的比率。如果该比率过低,意味着客户很可能透支。
- Negative_balance_ratio:客户在过去几周内账户余额为负的比例。频繁透支是未来违约的明确警示信号。
所有这些特征都很容易向监管机构解释,并且仍然能让模型表现极为出色——这证明了可解释性不必以牺牲性能为代价。
模型选择方面采用了常见了逻辑回归,xgboost和catboost,对于树模型,使用gridsearchCV进行调参,调参还是有一些技巧的,下面以反欺诈为例进行说明:
catboost调参:
总体策略:分阶段调优 (Sequential Tuning)
- 第一阶段 ( param_test1 ): 首先调整对模型性能影响最大、且相互关联最紧密的两个核心参数: iterations (树的数量) 和 learning_rate (学习率)。
- 第二阶段 ( param_test2 ): 在固定了第一阶段找到的最佳 iterations 和 learning_rate 后,调整控制单棵树复杂度的参数: depth (深度) 和 l2_leaf_reg (L2正则化)。
- 第三阶段 ( param_test3 ): 在固定了前两阶段的最佳参数后,调整与随机性和 bagging 相关的参数: random_strength 和 bagging_temperature 。
- 第四阶段 ( param_test4 ): 最后,微调一个影响计算精度和速度的参数: border_count 。
这种顺序是合理的,因为前两个参数(迭代次数和学习率)奠定了模型的基础性能,而后续参数更多是在此基础上进行微调和正则化。
各阶段参数组合选择原因详解
阶段 1: param_test1 - 调整基础学习动力
param_test1 = {
'iterations': [100, 200, 300],
'learning_rate': [0.03, 0.1, 0.2]
}
- 核心目标: 找到模型学习的“节奏”和“步长”的最佳平衡点。
- iterations [100, 200, 300] :
- 100 : 作为保守的起点,训练速度快,用于快速评估模型基线。
- 200 : 一个常用的中间值,平衡了性能和计算成本。
- 300 : 测试更高复杂度的模型是否能带来显著收益,但也增加了过拟合和计算时间的风险。
- learning_rate [0.03, 0.1, 0.2] :
- 0.03 : 小学习率,需要更多 iterations 来收敛,但通常能得到更鲁棒、泛化能力更强的模型。
- 0.1 : 经典默认值,学习速度适中。
- 0.2 : 较大的学习率,学习速度快,但可能不稳定或错过最优解,容易过拟合。
- 组合逻辑: 这个网格旨在探索从“慢而稳”(低学习率+高迭代)到“快而糙”(高学习率+低迭代)的各种组合,以找到最适合该数据集的基础配置。
阶段 2: param_test2 - 调整模型复杂度与正则化
param_test2 = {
'depth': [4, 6, 8, 10],
'l2_leaf_reg': [1, 3, 5, 7, 9]
}
- 核心目标: 在已确定的学习节奏下,控制单棵树的复杂度并施加正则化以防止过拟合。
- depth [4, 6, 8, 10] :
- 这是一个从浅到深的范围。CatBoost 通常在 depth 为 3-10 时表现良好。
- 4 : 浅树,强正则化,抗过拟合能力强。
- 6/8 : 中等深度,允许模型捕捉更复杂的特征交互,是实践中最常见的选择。
- 10 : 深树,模型容量大,但极易过拟合,尤其是在数据量不大或噪声多的情况下。
- l2_leaf_reg [1, 3, 5, 7, 9] :
- 这是应用于叶子节点值的 L2 正则化系数。它通过惩罚过大的叶子值来平滑模型预测,是防止过拟合的关键手段。
- 1 : 弱正则化,允许模型更自由地拟合数据。
- 3/5 : 中等强度的正则化,通常是很好的起点。
- 7/9 : 强正则化,会显著约束模型,可能导致欠拟合,但在数据噪声很大时很有用。
- 组合逻辑: 深度越深,模型越复杂,就越需要更强的正则化(更高的 l2_leaf_reg )来平衡。这个网格系统地测试了不同复杂度与不同正则化强度的组合。
阶段 3: param_test3 - 调整随机性
param_test3 = {
'random_strength': [0.5, 1, 2, 3],
'bagging_temperature': [0.8, 1.0, 1.2, 1.5]
}
- 核心目标: 通过引入受控的随机性来进一步提升模型的泛化能力和鲁棒性,减少过拟合。
- random_strength [0.5, 1, 2, 3] :
- 这个参数在分数计算时添加随机噪声。值越大,随机性越强。
- 0.5/1 : 轻微的随机性,主要用于打破特征选择中的平局。
- 2/3 : 更强的随机性,可以作为一种正则化形式,使模型对训练数据的微小变化不那么敏感,从而提升泛化能力。
- bagging_temperature [0.8, 1.0, 1.2, 1.5] :
- 这个参数控制在 Bagging(自助采样)过程中选择观测值的概率分布的形状。
- 1.0 : 标准的 Bagging 行为。
- <1.0 (0.8) : 使采样更均匀,每个样本被选中的概率更接近。
- >1.0 (1.2, 1.5) : 使采样更偏向于某些样本,增加了多样性。
- 组合逻辑: 这两个参数都是为了增加模型的随机性和多样性。它们的作用相对微妙,通常在核心参数调优后进行微调,以榨取最后一点性能提升。
阶段 4: param_test4 - 调整计算精度
param_test4 = {
'border_count': [32, 64, 128]
}
- 核心目标: 微调数值特征的分桶数量,这会影响模型的精度和训练速度。
- border_count [32, 64, 128] :
- CatBoost 会对连续特征进行分桶(离散化), border_count 决定了桶的数量。
- 32 : 默认值,提供了良好的速度和精度平衡。
- 64/128 : 更多的桶意味着对连续特征的划分更精细,理论上可以捕捉到更细微的模式,从而可能略微提升精度。但代价是训练时间会增加,并且在数据量不足时可能导致过拟合。
- 组合逻辑: 这是一个典型的精度与速度的权衡。在其他所有重要参数都已优化后,可以尝试增加 border_count 看是否能获得微小的性能增益。
总结
这种分阶段的调参方法 ( param_test1 -> param_test4 ) 是一种高度结构化和高效的策略:
- 由主到次: 先优化对性能影响最大的参数(学习率、迭代次数),再逐步处理影响较小的参数(随机性、计算精度)。
- 利用已有信息: 每个新阶段都固定了前一阶段找到的最佳参数,大大缩小了搜索空间。
- 逻辑清晰: 每个阶段都有明确的目标(如控制复杂度、增加随机性),使得调参过程更有目的性,而非盲目搜索。
通过这种方式,可以在有限的计算资源下,系统地逼近全局最优或接近最优的超参数组合。
xgboost调参:
总体策略:分阶段调优 (Sequential Tuning)
- 第一阶段 ( param_test1 ): 调整最核心的学习率 ( learning_rate ) 和树的数量 ( n_estimators )。
- 第二阶段 ( param_test2 ): 在固定了学习率和树的数量后,调整控制单棵树结构和复杂度的参数:最大深度 ( max_depth ) 和子节点最小样本权重和 ( min_child_weight )。
- 第三阶段 ( param_test3 ): 调整用于控制叶子节点分裂的正则化参数:伽马 ( gamma )。
- 第四阶段 ( param_test4 ): 调整L1和L2正则化参数 ( reg_alpha , reg_lambda ) 以进一步防止过拟合。
- 第五阶段 ( param_test5 ): 最后,调整随机采样比例参数 ( subsample , colsample_bytree ) 以增加模型的随机性和鲁棒性。
这种顺序遵循了XGBoost调参的经典最佳实践,从宏观到微观,从基础到细节。
各阶段参数组合选择原因详解
阶段 1: param_test1 - 确定基础学习框架
param_test1 = {
'n_estimators': [100, 200, 300],
'learning_rate': [0.05, 0.1, 0.2]
}
- 核心目标: 找到模型学习的“步长”和“步数”的最佳平衡。
- n_estimators [100, 200, 300] : 测试从小型(100棵树)到中等规模(300棵树)的集成模型,以评估模型容量对性能的影响。
- learning_rate [0.05, 0.1, 0.2] :
- 0.05 : 小学习率,通常需要更多树,但能产生更稳健的模型。
- 0.1 : 经典默认值,是很好的起点。
- 0.2 : 较大学习率,收敛快,但可能不稳定。
- 逻辑: 这两个参数高度耦合。此阶段旨在为整个调优过程奠定一个坚实的基础。
阶段 2: param_test2 - 控制树的复杂度
param_test2 = {
'max_depth': range(3, 10, 2), # [3,5,7,9]
'min_child_weight': range(1, 6, 2) # [1,3,5]
}
- 核心目标: 在已确定的学习框架下,控制单棵树的复杂度以管理偏差-方差权衡。
- max_depth [3, 5, 7, 9] :
- 3 : 非常浅的树,强正则化,抗过拟合。
- 5/7 : 中等深度,XGBoost的常用范围,能捕捉复杂的特征交互。
- 9 : 深树,模型容量大,但极易过拟合。
- min_child_weight [1, 3, 5] :
- 定义了叶子节点所需包含的最小样本权重和。它作为预剪枝(pre-pruning)机制,防止模型学习过于具体的模式(即过拟合)。
- 值越大,算法越保守,生成的树越简单。
- 逻辑: 更深的树(高 max_depth )通常需要更高的 min_child_weight 来平衡其复杂性,防止过拟合。
阶段 3: param_test3 - 调整分裂正则化
param_test3 = {
'gamma': [i/10.0 for i in range(0, 5)] # [0, 0.1, 0.2, 0.3, 0.4]
}
- 核心目标: 微调叶子节点分裂的门槛。
- gamma [0, 0.1, ..., 0.4] :
- gamma 是一个后剪枝(post-pruning)参数。它指定了一个分裂必须带来的最小损失减少量,否则该分裂将被阻止。
- 0 : 不施加任何额外的分裂惩罚。
- >0 : 值越大,算法越保守,生成的树越简单、越不容易过拟合。
- 逻辑: 在树的结构( max_depth )和基本复杂度( min_child_weight )确定后, gamma 提供了一种更精细的方式来控制模型的最终复杂度。
阶段 4: param_test4 - 应用L1/L2正则化
param_test4 = {
'reg_alpha': [0, 0.001, 0.01, 0.1, 1],
'reg_lambda': [0, 0.001, 0.01, 0.1, 1]
}
- 核心目标: 对叶子权重直接施加L1(Lasso)和L2(Ridge)正则化,这是防止过拟合的最后防线。
- reg_alpha & reg_lambda :
- 这些参数直接在目标函数中添加惩罚项。
- 测试从 0 (无正则化)到 1 (强正则化)的对数尺度值,以全面探索正则化强度的影响。
- L1 ( reg_alpha ) 可以促使部分叶子权重变为0,起到特征选择的作用;L2 ( reg_lambda ) 则倾向于让所有权重都变小。
- 逻辑: 在树的结构和分裂规则都已优化后,通过直接约束叶子权重的大小来进行最终的平滑和泛化能力提升。
阶段 5: param_test5 - 引入随机性 (Subsampling)
param_test5 = {
'subsample': [0.6, 0.7, 0.8, 0.9, 1.0],
'colsample_bytree': [0.6, 0.7, 0.8, 0.9, 1.0]
}
- 核心目标: 通过随机采样增加模型的多样性,降低方差,提高鲁棒性。
- subsample : 控制每次构建树时使用的样本比例。小于1.0可以有效防止过拟合(类似Bagging)。
- colsample_bytree : 控制每次构建树时使用的特征比例。这不仅能加速训练,还能通过引入随机性来提升模型性能,并减少对少数强特征的依赖。
- 逻辑: 这是调优的最后一步。在模型的所有确定性部分都已优化后,通过引入受控的随机性来进一步提升其在未知数据上的表现。
总结
这种五阶段的调参方法 ( param_test1 -> param_test5 ) 是XGBoost调优的黄金标准:
- 逻辑清晰: 遵循从基础学习参数 -> 树结构 -> 分裂规则 -> 权重正则化 -> 随机采样的清晰路径。
- 高效经济: 每个阶段只关注少数几个相关参数,大大减少了总的计算量。
- 效果显著: 通过系统地优化模型的各个层面,能够有效地逼近最优性能,同时很好地控制过拟合风险。
虽说参加这个比赛拿到了名次,还是觉得自己水水的,可能是因为现在AI越来越智能了,很多基础的内容AI都能替我做,所以感觉基本功不扎实。这确实是一个需要好好锻炼的地方,希望读到这里的你也一起加油吧!
5169

被折叠的 条评论
为什么被折叠?



