基于LightGBM的集成学习算法

目录

  • 一、LightGBM基本原理
    • 1.1 基于直方图的决策树算法
      • 1.1.1 连续变量分箱
    • 1.2 互斥特征捆绑
      • 1.2.1 互斥特征捆绑计算流程
      • 1.2.2 互斥特征捆绑算法基本原理
        • 1.2.2.1 冲突比例(conflict_rate)
        • 1.2.2.2 图着色
        • 1.2.2.3 特征捆绑
    • 1.3 基于梯度的单边采样(Gradient-based One-Side Sampling,GOSS)
      • 1.3.1 GOSS计算基本原理
        • 1.3.1.1 GOSS 的核心思想
        • 1.3.1.2 GOSS计算实例
  • 二、LightGBM的Sklearn实现
    • 2.1 LGBMClassifier超参数概览
      • 2.1.1 决策树剪枝超参数
      • 2.1.2 Boosting过程控制超参数
        • 2.1.2.1 借助验证曲线进行验证
      • 2.1.3 特征和数据处理类超参数
      • 2.1.4 其他超参数
    • 2.2 LGBMRegressor超参数概览
  • 三、LightGBM超参数优化
    • 3.1 基于贝叶斯优化器的超参数优化
      • 3.1.1 核心思想
      • 3.1.2 优势
      • 3.1.3 超参数优化案例
      • 3.1.4 优化案例
        • 3.1.4.1 1.HyperOPT搜索基本流程
    • 3.2 基于网格搜索的超参数优化
      • 3.2.1 网格搜索注意事项
      • 3.2.2 优化案例

常见的机器学习算法:
机器学习算法(一)—决策树
机器学习算法(二)—支持向量机SVM
机器学习算法(三)—K近邻
机器学习算法(四)—集成算法
基于LightGBM的集成学习算法
机器学习算法(五)—聚类
机器学习算法(六)—逻辑回归
机器学习算法(七)—Apriori 关联分析
机器学习算法(八)—朴素贝叶斯
九种降维方法汇总

一、LightGBM基本原理

  LightGBM 是一种高效的梯度提升(Gradient Boosting)算法。如果说 XGBoost 在提升 GBDT 类算法的计算精度上实现了里程碑式的突破,那么 LightGBM 则在计算效率内存优化方面提出了开创性的解决方案。通过引入基于直方图的决策树算法互斥特征捆绑单边梯度采样 等技术,LightGBM 显著提升了计算效率,相比传统方法提速近 20 倍,同时将内存占用减少了 80%。这一突破使得 GBDT 类算法(作为机器学习领域精度最高的预测算法之一)能够真正应用于海量数据的建模与预测任务,极大地拓展了其在实际场景中的应用范围。
  尽管 LightGBM 在计算精度上存在“选择性的牺牲”,但其实际建模效果仍能接近 XGBoost 的水平。更重要的是,这种“选择性的牺牲”从另一个角度来看,实际上起到了抑制模型过拟合的作用。因此,在许多实际场景中,LightGBM 的算法表现甚至优于 XGBoost,尤其是在数据规模较大或特征维度较高的场景下,LightGBM 的高效性和鲁棒性使其成为更优的选择。

1.1 基于直方图的决策树算法

  传统的GBDT算法在训练过程中需要对每个特征进行遍历和排序,以便找到最佳的分裂点。这种方式在数据集非常大时,计算开销和内存占用都非常高。LightGBM 引入了直方图方法,在构建决策树时,将连续的特征值离散化为多个区间(连续变量分箱)。这样,算法不再遍历每个原始的特征值,而是只需要考虑几个离散化后的区间,极大提高了计算效率,尤其是在数据量非常大的时候。

1.1.1 连续变量分箱

  LightGBM 采用的连续变量分箱方法是一种基于等宽分箱的简单策略,这与特征工程中常见的等宽分箱方法类似。具体来说,首先计算连续变量的取值范围,然后根据用户设定的超参数 max_bin,将取值范围划分为数量为 max_bin 的等宽区间,并将连续变量的值映射到对应的箱体中。例如,假设某连续变量的取值范围为 [0, 10],且 max_bin=2,则会将区间划分为 bin0=[0, 5)bin1=[5, 10]。此时,若某连续变量的取值为 1,则会被映射到 bin0(或标记为 0);若取值为 10,则会被映射到 bin1(或标记为 1)。通过这种方式,连续变量被转化为离散变量,从而简化了模型的计算复杂度,同时保留了数据的主要分布特征。
  这种分箱方法虽然简单,但在实际应用中非常高效,尤其是在处理大规模数据时,能够显著降低计算开销。此外,等宽分箱的离散化过程也为后续的直方图加速算法奠定了基础,进一步提升了 LightGBM 的训练效率。(XGB也会对连续变量进行分箱,但XGB的分箱是分位数分箱,而不是等宽分箱。)

import numpy as np
import pandas as pd
np.random.seed(22)
x1 = np.array([1.2, 2.9, 2.6, 3.3, 2.0, 2.5, 1.4, 2.1, 1.7, 3.0])
x2 = np.array([4.7, 5.5, 3.9, 6.2, 3.5, 4.5, 5.1, 2.7, 4.1, 3.8])
x3 = np.random.randint(0, 2, 10)
x4 = np.random.randint(0, 2, 10)
y = np.array([1, 0, 1, 0, 1, 1, 0, 0, 1, 1])
data = pd.DataFrame({'x1':x1, 'x2':x2, 'x3':x3, 'x4':x4, 'y':y})
data

在这里插入图片描述

  数据集中x1和x2是连续特征,x3和x4是离散特征,y是标签,对连续变量进行分箱,设置max_bin=2,即进行两个箱体的等宽分箱。

from sklearn.preprocessing import KBinsDiscretizer # 初始化 KBinsDiscretizern_bins = 2
strategy = 'uniform'
kbins = KBinsDiscretizer(n_bins=n_bins, encode='ordinal', strategy=strategy)# 对 x1 和 x2 进行分箱处理
data['x1_binned'] = kbins.fit_transform(data[['x1']])
data['x2_binned'] = kbins.fit_transform(data[['x2']])# 输出结果
print(data)

在这里插入图片描述

1.2 互斥特征捆绑

  原始的 GBDT 在每棵树的训练过程中,需要遍历全部数据来计算信息增益,从而确定决策树的最佳切分点。尽管这种方法能够保证切分点的精确性,但其计算复杂度非常高(与特征数量和样本数量成正比),在面对海量数据时,会消耗大量的计算资源和时间。因此,为了高效处理大规模数据的模型训练,样本采样特征降维成为了必要的优化手段。然而,传统方法在这方面往往存在明显缺陷:例如,简单的欠采样(如随机抽样)可能导致模型训练过程不稳定,而 PCA 降维仅适用于处理冗余特征,当每个特征都包含重要信息时,强行降维会导致大量信息丢失。
  为了解决这些问题,LightGBM 提出了两项开创性的技术:基于梯度的单边采样方法(GOSS)互斥特征捆绑方法(EFB)。GOSS 通过对样本进行智能采样,优先保留梯度较大的样本(即对模型训练贡献更大的样本),同时随机抽取部分梯度较小的样本,从而在减少数据量的同时,最大限度地保留信息增益的准确性。EFB 则通过将互斥特征(即很少同时取非零值的特征)捆绑在一起,有效减少特征数量,从而降低计算复杂度。与传统的采样和降维方法不同,GOSS 和 EFB 在显著提升计算效率的同时,能够很好地兼顾模型的预测精度,为海量数据的建模提供了高效且可靠的解决方案。
  这两项技术的引入,使得 LightGBM 在处理大规模数据时,不仅能够大幅减少计算时间和内存占用,还能保持甚至提升模型的性能,从而成为工业界和学术界广泛应用的强大工具。

1.2.1 互斥特征捆绑计算流程

  互斥特征捆绑算法,其实是受到独热编码启发,设计的类似于独热编码逆向过程的一种算法。例如一组数据情况如下,独热编码是从左往右的计算过程,把一列展开为多列,而互斥特征捆绑则是从右往左进行计算,将多列压缩为一列:
在这里插入图片描述
  在实际计算过程中,互斥特征捆绑是找到那些原始状态下就存在类似上图中x1和x2这种关系的特征,来将其合成为一个特征。上图中x1和x2两个特征存在一种这样的关系——任何一条样本都不会同时在x1和x2上取值非0,这种关系的特征被称作互斥特征,而互斥特征其实是可以合成一个特征的,比如上图中的x,这个合成的过程并不会有任何的信息损失,而合成的过程又被称作特征捆绑。这也就是所谓的互斥特征捆绑算法

1.2.2 互斥特征捆绑算法基本原理

1.2.2.1 冲突比例(conflict_rate)

  在实际应用中,互斥特征捆绑的计算过程相对复杂,尤其是在定义特征之间的“互斥”关系时。互斥特征捆绑并不局限于完全互斥的特征,而是通过引入一个灵活的冲突比例(也称为非互斥比例)来衡量特征之间的互斥程度。冲突比例表示两个特征在数据集中同时取非零值的比例,冲突比例越高,说明特征的互斥程度越低;反之,冲突比例越低,说明特征的互斥程度越高
例如,假设有以下数据集,共包含四条数据:

特征A特征B
01
10
00
11

  只有第四条数据中特征A和特征B同时取非零值(即发生了冲突),而其他三条数据都是互斥的。因此,冲突比例为 1/4 = 0.25。这个比例可以用来量化特征A和特征B之间的互斥程度。而如果数据集如下,此时两个特征非同时为0的(非全零样本)数量为3,则冲突比例为1/3:

样本情况特征A特征B
非全零样本01
非全零样本10
全零样本00
非全零样本11

  LightGBM 提供了一个名为 max_conflict_rate 的超参数,用于控制特征捆绑的灵活性。该参数表示允许的最大冲突比例,即两个特征在数据集中同时取非零值的比例。如果两个特征的冲突比例小于设定的 max_conflict_rate,则认为它们是互斥的,可以进行捆绑;反之,则认为它们是冲突的,不能进行捆绑。例如,假设我们设置 max_conflict_rate=0.3,特征A和特征B的冲突比例为 1/4 = 0.25,小于 max_conflict_rate=0.3,因此它们被认为是互斥的,可以进行捆绑。然而,如果我们将 max_conflict_rate 设置为 0.2,由于冲突比例 0.25 超过了阈值,这两个特征将被视为冲突的,无法进行捆绑。

1.2.2.2 图着色

  通过引入 最大冲突比例(max_conflict_rate) 的概念,LightGBM 放宽了对特征互斥性的严格限制,为是否互斥提供了一个可量化的阈值。这一机制使得特征捆绑更加灵活,能够适应更多实际场景的需求。然而,真正的特征捆绑过程并不仅仅是简单的阈值判断,而是将问题转化为一个经典的组合优化问题——图着色问题
  图着色问题是一种经典的组合优化问题,其核心目标是:给定一个无向图,用尽可能少的颜色对图中的每个顶点进行着色,并确保相邻的顶点颜色不同。这里的“颜色”可以是任意符号或编号,只要满足相邻顶点颜色不同的条件即可。在 LightGBM 的 互斥特征捆绑过程中,特征捆绑问题被巧妙地转化为图着色问题。
(1)计算冲突比例
  首先,计算每对特征之间的冲突比例(即同时取非零值的比例)。如果冲突比例小于 max_conflict_rate,则认为这两个特征是互斥的;否则,认为它们是冲突的。

import numpy as np
import pandas as pddef conflict_ratio_matrix(data):"""计算特征之间的冲突比例矩阵:param data: 输入数据,可以是 pandas.DataFrame 或 numpy.ndarray,形状为 (n_samples, n_features):return: 冲突比例矩阵,形状为 (n_features, n_features)"""# 检查输入类型,确保为 numpy.ndarrayif isinstance(data, pd.DataFrame):data = data.valueselif not isinstance(data, np.ndarray):raise ValueError("输入数据必须是 pandas.DataFrame 或 numpy.ndarray 类型")num_features = data.shape[1]# 初始化冲突比例矩阵conflict_matrix = np.zeros((num_features, num_features))# 遍历所有特征对for i in range(num_features):for j in range(i + 1, num_features):# 计算同时非零的样本数(冲突数)conflict_count = np.sum(np.logical_and(data[:, i] != 0, data[:, j] != 0))# 计算至少一个特征非零的样本数total_count = np.sum(np.logical_or(data[:, i] != 0, data[:, j] != 0))# 计算冲突比例conflict_ratio = conflict_count / total_count if total_count != 0 else 0# 填充冲突比例矩阵conflict_matrix[i, j] = conflict_ratioconflict_matrix[j, i] = conflict_ratioreturn conflict_matrix
conflict_ratio_matrix(data[['x1_binned', 'x2_binned', 'x3', 'x4']])

在这里插入图片描述
(2)图的构建
  将每个特征视为图中的一个顶点。如果两个特征之间存在冲突(即冲突比例大于 0),则用一条无向边连接这两个顶点,边的权重即为冲突比例。如果两个特征互斥(即冲突比例为 0),则它们之间没有边相连。
在这里插入图片描述
(3)图着色
  在图着色过程中,目标是用尽可能少的颜色对图中的顶点进行着色,并确保相邻顶点颜色不同。由于相互冲突的特征之间有边相连,因此它们会被赋予不同的颜色。相同颜色的顶点则代表互斥的特征,因为它们之间没有边相连。
在这里插入图片描述

1.2.2.3 特征捆绑

  完成图着色后,相同颜色的特征会被合并为一个捆绑特征。这些捆绑特征在后续的模型训练中被视为一个整体,从而显著减少特征数量,降低计算复杂度。

arr = np.array(data['x4'])
arr[arr != 0] += 1 #非零加1data['x2_binned&x4'] = arr + data['x2_binned']
data

在这里插入图片描述
  经过连续变量分箱和特征捆绑,实际上接下来带入进行模型训练的特征就只有x1_binned、x2_binned&x4和x3这三个特征。

1.3 基于梯度的单边采样(Gradient-based One-Side Sampling,GOSS)

1.3.1 GOSS计算基本原理

  GOSS是一种基于梯度分布的智能抽样方法,与简单的随机抽样不同,它能够更高效地利用样本信息,从而在保证模型精度的同时显著提升计算效率。

1.3.1.1 GOSS 的核心思想

  在梯度提升算法中,每个样本都有一个对应的梯度值,梯度绝对值的大小反映了样本对模型训练的贡献程度:

  • 梯度绝对值较小的样本:这些样本通常已经被模型正确分类或预测结果接近真实值,因此在后续的参数更新过程中,它们对模型改进的贡献较小。如果每次迭代都重新计算这些样本的梯度,会造成一定的计算资源浪费。
  • 梯度绝对值较大的样本:这些样本的预测误差较大,对模型训练有更大的贡献,因此在训练过程中需要重点关注。

基于这一观察,GOSS 提出了一种高效的采样策略:
1.样本排序:将所有样本按照梯度绝对值大小进行降序排序。
2.抽取大梯度样本:从排序后的样本中抽取梯度绝对值最大的前 a % a\% a%的样本,这里的 a % a\% a%可以换成更专业的超参数名称:top_rate
3.随机抽取小梯度样本:从剩余的小梯度样本中随机抽取 b % b\% b% 的样本, b % b\% b%更专业的名称则是other_rate
4.构建训练集:将抽取的大梯度样本和随机抽取的小梯度样本合并,构成新的训练集。

注意:尽管带入训练的数据是GOSS抽样后数据,但在后续决策树生长的过程中,小梯度样本的梯度(和损失函数二阶导数)会再乘以一个大于1的膨胀系数,再和大梯度样本的梯度(和损失函数二阶导数)进行相加,构成一个数据集的梯度(和损失函数二阶导数),来指导后续的迭代进行。让小梯度样本进一步膨胀再加入到样本数据梯度中,也是为了尽可能还原原始真实的数据集梯度。即GOSS抽样并不是想要改变数据集梯度,而是希望通过更小的计算量,来尽可能还原原始数据集完整梯度,以此来提升建模的精确度。

在这里插入图片描述

  膨胀系数就是 1 − a b \frac{1-a}{b} b1a,或者说是 1 − t o p _ r a t e o t h e r _ r a t e \frac{1-top\_rate}{other\_rate} other_rate1top_rate。例如当top_rate=0.1,other_rate=0.2时,小样本梯度膨胀系数为: 1 − t o p _ r a t e o t h e r _ r a t e = 1 − 0.1 0.2 = 4.5 \frac{1-top\_rate}{other\_rate}=\frac{1-0.1}{0.2}=4.5 other_rate1top_rate=0.210.1=4.5。最终样本梯度=大样本梯度+小样本梯度*4.5算得。

GOSS 的特点:

  • 单边采样:GOSS 只对小梯度样本进行随机抽样,而保留全部大梯度样本,这也是“单边采样”名称的由来。
  • 高效性:通过减少对小梯度样本的计算,GOSS 能够显著降低计算开销,同时保留对模型训练贡献较大的样本。
  • 精度保障:由于大梯度样本被全部保留,且小梯度样本通过随机抽样部分保留,GOSS 能够在保证模型精度的前提下提升计算效率。

示例:假设有一个包含 1000 个样本的数据集:
排序:将所有样本按照梯度绝对值从大到小排序。
抽取大梯度样本:抽取梯度绝对值最大的前 10% 的样本(即 100 个样本)。
随机抽取小梯度样本:从剩余的 900 个小梯度样本中随机抽取 20% 的样本(即 180 个样本,对抽取的 180 个小梯度样本的梯度乘以膨胀系数)。
构建训练集:将 100 个大梯度样本和 180 4.5个小梯度样本合并,构成新的训练集(共 100+1804.5=910个样本)。

1.3.1.2 GOSS计算实例
  • 损失函数、梯度与Hessian

  由于GOSS采样计算过程会涉及样本梯度计算,我们知道样本梯度损失函数在各参数方向上求导得到的结果,因此梯度实际上和损失函数相关。data数据集是二分类数据集,损失函数是二分类交叉熵损失函数:
L = − 1 n ∑ i = 1 n [ y i log ⁡ p i + ( 1 − y i ) log ⁡ ( 1 − p i ) ] \mathcal{L}=-\frac{1}{n} \sum_{i=1}^{n}\left[y_{i} \log p_{i}+\left(1-y_{i}\right) \log \left(1-p_{i}\right)\right] L=n1i=1n[yilogpi+(1yi)log(1pi)]
i i i条样本的梯度就是损失函数对预测样本的一阶偏导数:
∂ L ∂ p i = 1 − y i 1 − p i − y i p i \frac{\partial \mathcal{L}}{\partial p_{i}}=\frac{1-y_{i}}{1-p_{i}}-\frac{y_{i}}{p_{i}} piL=1pi1yipiyi
二阶偏导数,也就是所谓的Hessian矩阵(值),也被称作黑塞矩阵、海森矩阵等。对于第 i i i条样本,损失函数的二阶偏导数:
∂ 2 L ∂ p i 2 = y i p i 2 + 1 − y i ( 1 − p i ) 2 \frac{\partial^{2} \mathcal{L}}{\partial p_{i}^{2}}=\frac{y_{i}}{p_{i}^{2}}+\frac{1-y_{i}}{\left(1-p_{i}\right)^{2}} pi22L=pi2yi+(1pi)21yi


def binary_cross_entropy(y_true, y_pred):"""计算二分类交叉熵损失函数:param y_true: 真实标签,一个 Numpy 数组,形状为 (n_samples,):param y_pred: 预测标签,一个 Numpy 数组,形状为 (n_samples,):return:二分类交叉熵损失值,一个标量"""# 确保输入的标签为 0 或 1y_true = np.clip(y_true, 1e-7, 1-1e-7) #np.clip函数是用于将输出结果限制在一个范围内,避免出现零值相除的情况y_pred = np.clip(y_pred, 1e-7, 1-1e-7)# 计算二分类交叉熵损失loss = -(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred)).mean()return lossdef binary_cross_entropy_grad(y_true, y_pred):"""计算二分类交叉熵损失函数的一阶导数:param y_true: 真实标签,一个 Numpy 数组,形状为 (n_samples,):param y_pred: 预测标签,一个 Numpy 数组,形状为 (n_samples,):return:二分类交叉熵损失函数的一阶导数,一个 Numpy 数组,形状为 (n_samples,)"""# 确保输入的标签为 0 或 1y_true = np.clip(y_true, 1e-7, 1-1e-7)y_pred = np.clip(y_pred, 1e-7, 1-1e-7)# 计算二分类交叉熵损失函数的一阶导数grad = (1 - y_true) / (1 - y_pred) - y_true / y_predreturn graddef binary_cross_entropy_hess(y_true, y_pred):"""计算二分类交叉熵损失函数的二阶导数:param y_true: 真实标签,一个 Numpy 数组,形状为 (n_samples,):param y_pred: 预测标签,一个 Numpy 数组,形状为 (n_samples,):return: 生成的特征张和标签张量:二分类交叉熵损失函数的二阶导数,一个 Numpy 数组,形状为 (n_samples,)"""# 确保输入的标签为 0 或 1y_true = np.clip(y_true, 1e-7, 1 - 1e-7)y_pred = np.clip(y_pred, 1e-7, 1 - 1e-7)# 计算二分类交叉熵损失函数的二阶导数hess = y_true / (y_pred ** 2) + (1 - y_true) / ((1 - y_pred) ** 2)return hess
  • LightGBM初始预测值

  首次进行GOSS抽样时梯度计算依据是LightGBM算法的初始预测值,如果是交叉熵损失函数,则初始预测值为1类样本占比(或者1类样本总数)的对数几率(log odds)计算结果,并且每条样本初始预测值都相同,计算公式如下:
y ^ = l n p 1 − p \hat y = ln\frac{p}{1-p} y^=ln1pp
其中 p p p为1类的占比(或者1类总数,计算结果都相同)。例如对于data数据集来说,初始预测值可以按照如下方式进行计算:

# 计算每个类别的频率
class_freq = data['y'].value_counts(normalize=True)
# 计算初始预测值
initial_prediction = np.log(class_freq[1] / class_freq[0])
print("初始预测值:", initial_prediction)  #初始预测值: 0.4054651081081642

因此所有样本的初始预测结果为0.4,将其添加到data的最后一列中:

y_pred = np.array([0.4054]*10)
data['y_pred'] = y_pred

在这里插入图片描述
接下来我们即可依据y_pred来计算每条样本的梯度。

data['grad'] = binary_cross_entropy_grad(data['y'], data['y_pred'])
data

在这里插入图片描述
然后再计算样本的hes值:

data['hess'] = binary_cross_entropy_hess(data['y'], data['y_pred'])
data

在这里插入图片描述

  • GOSS抽样

  假设top_rate=0.2,other_rate=0.5,由于我们样本量较少,因此这里设置的比例偏大。此时GOSS抽样过程如下,首先计算样本梯度绝对值:

abs_gradients = np.abs(data['grad'])
abs_gradients

在这里插入图片描述
  然后进行从大到小的索引排序:

sorted_index = np.argsort(-abs_gradients)
sorted_index

在这里插入图片描述
  此时top_rate=0.2,other_rate=0.5,即从10条数据中挑选出梯度最大的2条数据,然后从剩下的8条数据中抽取50%,即抽取4条数据,共同构成本次GOSS抽样得到的训练数据集。借助布尔索引先挑选出梯度最大的2条数据:

topn_index = sorted_index[:2]
topn_data = data.iloc[topn_index.values, :]
topn_data

在这里插入图片描述
  然后再从剩下的数据集中随机抽取4条数据,首先是找到剩余数据集索引,进行无放回抽样:

raten_index = np.random.choice(sorted_index[2:].values, size=4, replace=False)
raten_data = data.iloc[raten_index, :]
raten_data

在这里插入图片描述
  至此,我们就完成了一次GOSS抽样全过程,接下来我们就将带入我们抽样得到的topn_data和raten_data带入进行模型训练。

二、LightGBM的Sklearn实现

#!pip install lightgbm -i https://pypi.tuna.tsinghua.edu.cn/simple #cpu版本安装
# 科学计算模块
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler,PolynomialFeatures 
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
from lightgbm import LGBMClassifier# 读取数据
iris = load_iris()
data = pd.DataFrame(data= np.c_[iris['data'], iris['target']], columns= iris['feature_names'] + ['target'])
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(data.drop("target", axis=1), data["target"], test_size=0.2)
#模型实例化
gbm = LGBMClassifier()
# 训练模型
gbm.fit(X_train, y_train)
gbm.predict(X_test)
#gbm.predict_proba(X_test)
#np.argmax(gbm.predict_proba(X_test), 1) #将概率预测结果转化为类别
accuracy_score(y_train, gbm.predict(X_train)), accuracy_score(y_test, gbm.predict(X_test)) #输出(1.0, 0.96)

2.1 LGBMClassifier超参数概览

  LGBMClassifier的超参数分为决策树剪枝超参数Boosting过程控制超参数特征和数据处理类超参数其他超参数四类。其中决策树剪枝超参数包括max_depth(树的最大深度)、num_leaves(叶子节点数)、min_child_samples(子节点的最小样本数)等;Boosting过程控制超参数和XGB的booster类似,包含boosting_type(提升类型,如gbdt、dart、goss、rf),n_estimators(迭代次数)、learning_rate(学习率)和reg_alpha(L1正则化系数)、reg_lambda(L2正则化系数);而特征和数据处理类超参数则主要与数据采样有关,包含subsample(样本子集的比例)、subsample_freq(进行子采样的频率)、colsample_bytree(列采样的比例)等;而其他参数则是一些对建模效果并没有重要影响的超参数,例如random_state(随机数种子)、n_jobs(并行计算所用的CPU核心数)、class_weight(类别权重)等。

2.1.1 决策树剪枝超参数

NameDescription
num_leaves一棵树上的叶子节点数,默认为 31
max_depth树的最大深度,默认值为 -1,表示无限制
min_split_gain相当于min_impurity_decrease,再分裂所需最小增益。默认值为 0,表示无限制
min_child_weight子节点的最小权重和。默认值为 1e-3。较大的 min_child_weight 可以防止过拟合
min_child_samples相当于min_samples_leaf,单个叶子节点上的最小样本数量。默认值为 20。较大的 min_child_samples 可以防止过拟合

2.1.2 Boosting过程控制超参数

  boosting_type 是 LightGBM 中用于指定梯度提升算法类型的参数,默认值为 ‘gbdt’。以下是各选项的详细说明及其适用场景:

  1. gbdt(Gradient Boosting Decision Tree)
    描述:gbdt 是传统的梯度提升决策树算法,也是 LightGBM 的默认选项。它通过迭代地构建决策树来最小化损失函数,每次迭代都会基于前一次迭代的残差构建新的树。
    特点
    性能稳定,适用于大多数场景。
    计算效率较高,精度通常较好。
    适用场景
    通用场景,尤其是对模型精度要求较高的任务。
    中小规模数据集或计算资源充足的情况。
  2. dart(Dropouts meet Multiple Additive Regression Trees)
    描述:dart 是一种结合了 Dropout 和多重加性回归树的算法。它在每次迭代中随机丢弃一部分已经构建的树(类似于神经网络中的 Dropout 技术),从而增加模型的随机性。
    特点
    通过随机丢弃树,减少过拟合风险。
    训练过程较慢,因为需要重新构建被丢弃的树。
    适用场景
    数据集中存在较多噪声,需要减少过拟合风险。
    数据集相对简单,模型容易过拟合的情况。
  3. goss(Gradient-based One-Side Sampling)
    描述:goss 是一种基于梯度的单边采样方法。它在每次迭代中优先选择梯度绝对值较大的样本进行训练,同时对梯度较小的样本进行随机采样,从而减少计算量。
    特点
    显著提升训练速度,尤其适用于大规模数据集。
    在保持较高精度的同时,减少计算复杂度。
    有时精度可能略低于 gbdt,但计算效率更高。
    适用场景
    大规模数据集,计算资源有限的情况。
    对训练速度要求较高的任务。
  4. rf(Random Forest)
    描述:rf 使用随机森林算法替代了传统的 Boosting 过程。它通过 Bagging 的方式构建多棵独立的决策树,并对结果进行平均或投票。
    特点
    不再是 Boosting,而是 Bagging 方法。
    每棵树独立构建,增加了模型的多样性。
    训练速度较快,但精度通常不如 Boosting 方法。
    适用场景
    需要快速训练模型的场景。
    对模型精度要求不高,但需要稳定性和抗过拟合能力的任务。

参数选择建议
默认选择:如果没有特殊需求,建议使用默认的 gbdt,它在大多数场景下表现稳定且精度较高。
大规模数据:如果数据集较大且对训练速度有较高要求,可以选择 goss。
抗过拟合:如果数据集噪声较多或模型容易过拟合,可以尝试 dart。
快速训练:如果需要快速训练模型且对精度要求不高,可以选择 rf。

  subsample_for_bin 是 LightGBM 中用于控制连续变量分箱时抽样样本数量的参数。它的默认值为 200000,表示在对连续变量进行分箱(直方图优化过程)时,最多会从训练数据中抽取 200,000 个样本用于计算分箱点。如果实际数据量小于 subsample_for_bin 的值,则会使用全部样本进行计算。
  与 boosting_type 的关系:当 boosting_type 设置为 ‘goss’ 时,subsample_for_bin 参数会失效。这是因为 goss 在直方图优化过程中会自动完成抽样,其抽样策略如下:
保留所有小梯度样本:这些样本已经被模型较好地拟合,保留它们可以有效防止过拟合。
对大梯度样本进行采样:这些样本对模型训练贡献较大,采样后可以加速训练过程。
因此,goss 的抽样策略已经兼顾了训练效率和防止过拟合的需求,subsample_for_bin 的设置不再影响最终结果。

如果需要控制goss过程,则需要借助top_rate 和 other_rate 这两个参数,但是这两个参数只存在于LGBM原生API中,在sklearn中并没有,因此在使用 LightGBM 的 sklearn API 时,GOSS 采样方法会自动进行调整。

其他参数和GBDT及XGBoost类似,具体解释如下:

NameDescription
learning_rate学习率,即每次迭代中梯度提升的步长,默认值为 0.1
n_estimators迭代次数,即生成的基学习器的数量,默认值为 100
reg_alphaL1 正则化系数,默认值为 0
reg_lambdaL2 正则化系数。默认值为 0
2.1.2.1 借助验证曲线进行验证
  • 评估器个数
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import validation_curve
from lightgbm import LGBMClassifier
from sklearn.datasets import make_classificationdef plot_validation_curve(model, param_name, param_range, X, y, cv=5, scoring="accuracy", n_jobs=-1):"""绘制验证曲线:param model: 机器学习模型:param param_name: 参数名称:param param_range: 参数范围:param X: 特征数据:param y: 标签数据:param cv: 交叉验证折数:param scoring: 评估指标:param n_jobs: 并行计算数"""# 计算验证曲线train_scores, val_scores = validation_curve(model, X, y, param_name=param_name, param_range=param_range,cv=cv, scoring=scoring, n_jobs=n_jobs)# 计算训练和验证分数的均值与标准差train_mean = np.mean(train_scores, axis=1)train_std = np.std(train_scores, axis=1)val_mean = np.mean(val_scores, axis=1)val_std = np.std(val_scores, axis=1)# 绘制验证曲线plt.figure(figsize=(10, 6))plt.title(f"Validation Curve with {model.__class__.__name__} ({param_name})", fontsize=14)plt.xlabel(param_name, fontsize=12)plt.ylabel("Score", fontsize=12)plt.ylim(0.8, 1.02)  # 设置 y 轴范围plt.grid(True, linestyle='--', alpha=0.6)  # 添加网格线# 绘制训练分数曲线plt.plot(param_range, train_mean, label="Training Score", color="darkorange", lw=2)plt.fill_between(param_range, train_mean - train_std, train_mean + train_std, alpha=0.2, color="darkorange")# 绘制验证分数曲线plt.plot(param_range, val_mean, label="Cross-Validation Score", color="navy", lw=2)plt.fill_between(param_range, val_mean - val_std, val_mean + val_std, alpha=0.2, color="navy")# 添加图例plt.legend(loc="best", fontsize=12)# 显示图形plt.show()# 生成分类数据集
X, y = make_classification(n_samples=1000, n_features=20, n_informative=2, n_redundant=10, random_state=42)# 初始化 LightGBM 分类器
model = LGBMClassifier(random_state=22)# 定义参数范围:树的数量 (n_estimators)
param_range = np.arange(1, 100, 2)# 调用函数绘制验证曲线
plot_validation_curve(model, "n_estimators", param_range, X, y)

在这里插入图片描述

  • 学习率
# 创建一个LightGBM分类器
model = LGBMClassifier()# 要计算验证曲线的参数范围
param_range = np.linspace(0.01, 0.1, 100)# 调用函数
plot_validation_curve(model, "learning_rate", param_range, X, y)

在这里插入图片描述

  • max_depth最大树深度
# 创建一个LightGBM分类器
model = LGBMClassifier()# 要计算验证曲线的参数范围
param_range = np.arange(1, 20, 1)# 调用函数
plot_validation_curve(model, "max_depth", param_range, X, y)

在这里插入图片描述

  • reg_alpha:L1正则化项
# 创建一个LightGBM分类器
model = LGBMClassifier(n_estimators=45)# 要计算验证曲线的参数范围
param_range = np.linspace(0.00, 0.5, 100)# 调用函数
plot_validation_curve(model, "reg_alpha", param_range, X, y)

在这里插入图片描述

  • reg_lambda:L2正则化项
# 创建一个LightGBM分类器
model = LGBMClassifier(n_estimators=45)# 要计算验证曲线的参数范围
param_range = np.linspace(0.00, 0.5, 100)# 调用函数
plot_validation_curve(model, "reg_lambda", param_range, X, y)

在这里插入图片描述

2.1.3 特征和数据处理类超参数

NameDescription
subsample模型训练时抽取的样本数量,取值范围为 (0, 1],表示抽样比例,默认为1.0
subsample_freq抽样频率,表示每隔几轮进行一次抽样,默认取值为0,表示不进行随机抽样
colsample_bytree在每次迭代(树的构建)时,随机选择特征的比例,取值范围为 (0, 1],默认为1.0
  • subsample和subsample_for_bin之间的关系
      这两个参数尽管从字面理解都是抽样比例,但实际上这两个参数是完全独立的,彼此之间并不影响。其中subsample_for_bin抽样结果用于直方图构建,而subsample抽样结果则是用于模型训练,这两个抽样过程彼此独立,互不影响;

  • subsample和subsample_freq之间的关系
      更加关键的是subsample_freq参数,如果subsample_freq=0,则无论subsample取值为多少,模型训练时都不会进行随机抽样;换而言之,只有subsample_freq不等于0,且subsample不等于1.0时,才会进行抽样;

  • subsample_freq和colsample_bytree之间的关系
      不同于subsample是样本抽样,colsample_bytree是每次迭代(每次构建一颗树时)进行的特征抽样,并且colsample_bytree不受subsample_freq影响,即无论subsample_freq取值为多少,每次建树时都会根据colsample_bytree设置的比例进行列抽样。

  LightGBM和RF的不同特征抽样规则:随机森林是每棵树的每次分裂时都随机分配特征,而LightGBM是每次构建一颗树时随机分配一个特征子集,这颗树在成长过程中每次分裂都是依据这个特征子集进行生长。

2.1.4 其他超参数

NameDescription
objective指定目标函数,默认为None,会自动判断是二分类还是多分类问题,这里我们也可以手动设置 ‘binary’(用于二分类问题)或’multiclass’(用于多分类问题)
class_weight样本权重设置参数
importance_type特征重要性计算方式,默认为 ‘split’,表示使用特征在模型中被选中作为分裂特征的次数,可选 ‘gain’,表示使用特征在模型中的分裂收益之和作为重要性评估指标
random_state随机数种子
n_jobs并行的线程数,默认为-1,调用全部可用线程
silent是否沉默(不输出日志),默认为’warn’,仅显示警告和报错,可选’info’,用于打印全部信息

  关于目标函数的设置,对于LGBM的sklearn API来说,objective参数较为简单,只有’binary’和’multiclass’两种,其中’binary’表示逻辑回归损失,也就是二分类交叉熵损失,而’multiclass’则代表多分类交叉熵损失。

2.2 LGBMRegressor超参数概览

  LGBMRegressor和LGBMClassifier只有两点不同,其一是LGBMRegressor没有class_weight参数,其二则是LGBMRegressor的损失函数和LGBMClassifier完全不同。接下来我们就LGBMRegressor的损失函数选取进行解释。

均方误差(MSE, Mean Squared Error):最常用的的损失函数,此时objective='regression' 或 objective='regression_l2';
平均绝对误差(MAE, Mean Absolute Error):通常用于标签存在异常值情况,此时objective='regression_l1';
Huber损失(Huber Loss):适用于目标值存在大量异常值或者噪声时。Huber损失在预测误差较小时表现为均方误差,在预测误差较大时表现为平均绝对误差,这使得它对异常值具有更好的鲁棒性。此时objective='quantile';
Quantile损失(Quantile Loss):用于分位数回归,最小化预测值与真实值之间的分位数损失,适用于需要对预测分布进行精细控制的场景(例如围绕某种分布进行预测)。此时objective='quantile';
Poisson损失(Poisson Loss): 适用于计数问题,即目标值是非负整数且服从泊松分布。此时objective='poisson'
Gamma损失(Gamma Loss):适用于预测非负实数且服从伽马分布的目标值。此时objective='gamma'
Tweedie损失(Tweedie Loss):适用于广义线性模型(Generalized Linear Models, GLMs)中的 Tweedie 分布(非对称分布)的数据集。此时objective='tweedie'

三、LightGBM超参数优化

3.1 基于贝叶斯优化器的超参数优化

  贝叶斯优化是当前超参数优化领域的 SOTA(State of the Art) 方法,被广泛认为是最先进的优化框架。它不仅适用于超参数优化,还可以应用于神经网络架构搜索元学习 等 AutoML 的核心领域。现代几乎所有在效率和效果上取得显著成果的超参数优化方法,都是基于贝叶斯优化的基本理念发展而来的。

3.1.1 核心思想

  贝叶斯优化通过构建一个 代理模型(Surrogate Model) 来近似目标函数(如模型性能),并利用 采集函数(Acquisition Function) 指导下一步的搜索方向。其核心步骤包括:
代理模型:通常使用高斯过程(Gaussian Process)来建模目标函数,预测未知点的性能。
采集函数:基于代理模型的预测结果,选择下一个最有潜力的超参数组合进行评估。
迭代优化:通过不断迭代,逐步逼近最优解。

3.1.2 优势

1.高效性
通过代理模型和采集函数,贝叶斯优化能够在较少的评估次数内找到接近最优的超参数组合。特别适合目标函数计算成本高(如深度学习模型训练)的场景。
2.自适应性:
贝叶斯优化能够根据历史评估结果动态调整搜索策略,适应不同的目标函数。
3.广泛适用性:
不仅适用于超参数优化,还可用于神经网络架构搜索、元学习等复杂任务。
4.理论基础强:
基于贝叶斯统计理论,具有坚实的数学基础。

数据集 通过网盘分享的文件:WA_Fn-UseC_-Telco-Customer-Churn.csv
链接: https://pan.baidu.com/s/18Osmhz-dQ9ILsMAEX85prQ 提取码: xypm

3.1.3 超参数优化案例

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as pltfrom sklearn.preprocessing import OrdinalEncoder, OneHotEncoder
from sklearn.metrics import accuracy_score, recall_score, precision_score, f1_score, roc_auc_score
from sklearn.model_selection import train_test_split, GridSearchCV,cross_val_scorefrom sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifierfrom sklearn.base import BaseEstimator, TransformerMixin
from tqdm import tqdm
from lightgbm import LGBMClassifierimport warnings
warnings.filterwarnings('ignore') # 忽略警告# 读取数据
tcc = pd.read_csv('WA_Fn-UseC_-Telco-Customer-Churn.csv')# 标注连续/离散字段
# 离散字段
category_cols = ['gender', 'SeniorCitizen', 'Partner', 'Dependents','PhoneService', 'MultipleLines', 'InternetService', 'OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies', 'Contract', 'PaperlessBilling','PaymentMethod']# 连续字段
numeric_cols = ['tenure', 'MonthlyCharges', 'TotalCharges']# 标签
target = 'Churn'# ID列
ID_col = 'customerID'# 验证是否划分能完全
assert len(category_cols) + len(numeric_cols) + 2 == tcc.shape[1]# 连续字段转化
tcc['TotalCharges'] = tcc['TotalCharges'].apply(lambda x: x if x != ' ' else np.nan).astype(float)
tcc['MonthlyCharges'] = tcc['MonthlyCharges'].astype(float)# 缺失值填补
tcc['TotalCharges'] = tcc['TotalCharges'].fillna(0)# 标签值手动转化 
tcc['Churn'].replace(to_replace='Yes', value=1, inplace=True)
tcc['Churn'].replace(to_replace='No',  value=0, inplace=True)# 划分训练集和测试集
train, test = train_test_split(tcc, random_state=22)X_train = train.drop(columns=[ID_col, target]).copy()
X_test = test.drop(columns=[ID_col, target]).copy()y_train = train['Churn'].copy()
y_test = test['Churn'].copy()# 特征工程:时间衍生
def derive_time_features(df, tenure_col='tenure'):"""从tenure列衍生时间特征:param df: 输入数据框:param tenure_col: tenure列名:return: 衍生后的数据框"""df_seq = pd.DataFrame()df_seq['tenure_year'] = ((72 - df[tenure_col]) // 12) + 2014df_seq['tenure_month'] = (72 - df[tenure_col]) % 12 + 1df_seq['tenure_quarter'] = ((df_seq['tenure_month'] - 1) // 3) + 1return df_seq# 生成时间衍生特征
X_train_seq = derive_time_features(X_train)
X_test_seq = derive_time_features(X_test)# 独热编码
def one_hot_encode(df, cols, drop=None):"""对指定列进行独热编码:param df: 输入数据框:param cols: 需要编码的列:param drop: 是否删除某一类别(避免多重共线性):return: 编码后的数据框"""enc = OneHotEncoder(drop=drop)enc.fit(df[cols])encoded_df = pd.DataFrame(enc.transform(df[cols]).toarray(), columns=enc.get_feature_names_out(cols))encoded_df.index = df.indexreturn encoded_df# 对时间衍生特征进行独热编码
X_train_seq = one_hot_encode(X_train_seq, X_train_seq.columns)
X_test_seq = one_hot_encode(X_test_seq, X_test_seq.columns)# 对离散特征进行Ordinal编码
def ordinal_encode(df, cols):"""对指定列进行Ordinal编码:param df: 输入数据框:param cols: 需要编码的列:return: 编码后的数据框"""enc = OrdinalEncoder()enc.fit(df[cols])encoded_df = pd.DataFrame(enc.transform(df[cols]), columns=cols)encoded_df.index = df.indexreturn encoded_df# 对离散特征进行Ordinal编码
X_train_OE = ordinal_encode(X_train, category_cols)
X_test_OE = ordinal_encode(X_test, category_cols)# 合并编码后的离散特征和连续特征
X_train_OE = pd.concat([X_train_OE, X_train[numeric_cols]], axis=1)
X_test_OE = pd.concat([X_test_OE, X_test[numeric_cols]], axis=1)# 重置索引
X_train_OE = X_train_OE.reset_index(drop=True)
y_train = y_train.reset_index(drop=True)
X_test_OE = X_test_OE.reset_index(drop=True)
y_test = y_test.reset_index(drop=True)
gbm = LGBMClassifier() #实例化# 训练模型
gbm.fit(X_train_OE, y_train)
gbm.predict(X_test_OE)gbm.score(X_train_OE, y_train),gbm.score(X_test_OE, y_test) #不进行超参数优化时模型输出测试集:0.8906, 验证集:0.7871
  • 优化参数
NameDescription经验最优范围
num_leaves一棵树上的叶子节点数,默认为 31range(20, 51, 2)
max_depth树的最大深度,默认值为 -1,表示无限制range(5, 15, 2)
min_split_gain相当于min_impurity_decrease,再分裂所需最小增益。默认值为 0,表示无限制-
min_child_weight子节点的最小权重和。默认值为 1e-3。较大的 min_child_weight 可以防止过拟合-
min_child_samples相当于min_samples_leaf,单个叶子节点上的最小样本数量。默认值为 20。较大的 min_child_samples 可以防止过拟合-
boosting_type使用的梯度提升算法类型,默认为GBDT[‘gbdt’, ‘goss’]
subsample_for_bin该参数表示对连续变量进行分箱时(直方图优化过程)抽取样本的个数,默认取值为200000-
learning_rate学习率,即每次迭代中梯度提升的步长,默认值为 0.1np.linspace(0.01, 0.2, 5)
n_estimators迭代次数,即生成的基学习器的数量,默认值为 100range(10, 200, 50)
reg_alphaL1 正则化系数,默认值为 0np.linspace(0.01, 0.1, 2)
reg_lambdaL2 正则化系数。默认值为 0np.linspace(0.01, 0.1, 2)
subsample模型训练时抽取的样本数量,取值范围为 (0, 1],表示抽样比例,默认为1.0-
subsample_freq抽样频率,表示每隔几轮进行一次抽样,默认取值为0,表示不进行随机抽样-
colsample_bytree在每次迭代(树的构建)时,随机选择特征的比例,取值范围为 (0, 1],默认为1.0[0.6, 0.8, 1.0]

3.1.4 优化案例

3.1.4.1 1.HyperOPT搜索基本流程
  • 1、定义超参数搜索空间

  在hyperopt中,我们使用特殊的字典形式来定义参数空间,其中键值对上的键可以任意设置,只要与目标函数中索引参数的键一致即可,键值对的值则是hyperopt独有的hp函数,包括了:

hp.quniform(“参数名称”, 下界, 上界, 步长) - 适用于均匀分布的浮点数

hp.uniform(“参数名称”,下界, 上界) - 适用于随机分布的浮点数

hp.randint(“参数名称”,上界) - 适用于[0,上界)的整数,区间为前闭后开

hp.choice(“参数名称”,[“字符串1”,“字符串2”,…]) - 适用于字符串类型,最优参数由索引表示

hp.choice(“参数名称”,[*range(下界,上界,步长)]) - 适用于整数型,最优参数由索引表示

hp.choice(“参数名称”,[整数1,整数2,整数3,…]) - 适用于整数型,最优参数由索引表示

hp.choice(“参数名称”,[“字符串1”,整数1,…]) - 适用于字符与整数混合,最优参数由索引表示

  • 2、定义目标函数
  1. 目标函数的输入必须是符合hyperopt规定的字典,不能是类似于sklearn的参数空间字典、不能是参数本身,更不能是数据、算法等超参数以外的元素。因此在自定义目标函数时,我们需要让超参数空间字典作为目标函数的输入。
  2. Hyperopt只支持寻找 f ( x ) f(x) f(x)的最小值,不支持寻找最大值,因此当我们定义的目标函数是某种正面的评估指标时(如准确率auc),我们需要对该评估指标取负。如果我们定义的目标函数是负损失,也需要对负损失取绝对值。当且仅当我们定义的目标函数是普通损失时,我们才不需要改变输出。
import numpy as np
from hyperopt import hp, fmin, tpe, Trials
from hyperopt.early_stop import no_progress_loss
from lightgbm import LGBMClassifier
from sklearn.model_selection import cross_val_score# 1、定义超参数空间
LGBM_params_space = {'max_depth': hp.choice('max_depth', np.arange(3, 30).tolist()),'num_leaves': hp.choice('num_leaves', np.arange(10, 100).tolist()),'n_estimators': hp.choice('n_estimators', np.arange(50, 200).tolist()),'boosting_type': hp.choice('boosting_type', ['gbdt', 'goss']),'colsample_bytree': hp.uniform('colsample_bytree', 0.2, 1.0),'learning_rate': hp.uniform('learning_rate', 0.01, 0.1),'reg_alpha': hp.uniform('reg_alpha', 0.01, 0.5),'reg_lambda': hp.uniform('reg_lambda', 0.01, 0.5)
}# 2、定义目标函数
def hyperopt_lgbm(params):lgbm = LGBMClassifier(random_state=22, **params, verbose=-1)  # 禁用LightGBM输出res = -cross_val_score(lgbm, X_train_OE, y_train, scoring='roc_auc', cv=5).mean()return res# 3、调用贝叶斯优化
def param_hyperopt_lgbm(max_evals):trials = Trials()early_stop_fn = no_progress_loss(10)params_best = fmin(fn=hyperopt_lgbm,space=LGBM_params_space,algo=tpe.suggest,max_evals=max_evals,trials=trials,early_stop_fn=early_stop_fn,verbose=0  # 禁用Hyperopt输出)return params_best# 执行超参数优化
lgbm_params_best = param_hyperopt_lgbm(100)# 打印最佳结果
print("Best Parameters:", lgbm_params_best)

3d3eacf6.png)
对于离散变量,搜索结果实际上是索引值,而非真实值。

  • 带入原模型进行测试
lgbm = LGBMClassifier(random_state = 22, max_depth =  np.arange(3, 30).tolist()[11], num_leaves = np.arange(10, 100).tolist()[43], n_estimators = np.arange(50, 200).tolist()[99], boosting_type = ['gbdt', 'goss'][1], colsample_bytree = 0.4296491494550363, learning_rate = 0.013732013321709684, reg_alpha = 0.42344265953077664, reg_lambda = 0.43195063354217994).fit(X_train_OE, y_train)
lgbm.score(X_train_OE, y_train), lgbm.score(X_test_OE, y_test) #输出:测试集:0.8459, 验证集:0.7831
准确率训练集测试集
LGBM原始模型0.89060.7871
LGBM+TPE+1000.84590.7831
  • 修改目标函数

  在定义目标函数的时候,可以考虑区分目标函数的训练状态和测试状态,训练状态(train=True)是默认状态,作为超参数搜索时的目标函数时使用,而train=Fasle时则为测试状态,此时函数用于带入搜索出来的超参数,来直接输出最终的最优模型:

def hyperopt_lgbm(params, train=True):# 读取参数if train == True:max_depth = params['max_depth']num_leaves = params['num_leaves']n_estimators = params['n_estimators']boosting_type = params['boosting_type']colsample_bytree = params['colsample_bytree']learning_rate = params['learning_rate']reg_alpha = params['reg_alpha']        reg_lambda = params['reg_lambda']        else: max_depth = params['max_depth'] + 3num_leaves = params['num_leaves'] + 10n_estimators = params['n_estimators'] + 50boosting_type = ['gbdt', 'goss'][params['boosting_type']]colsample_bytree = params['colsample_bytree']learning_rate = params['learning_rate']reg_alpha = params['reg_alpha']        reg_lambda = params['reg_lambda']  # 实例化模型lgbm = LGBMClassifier(random_state = 22, max_depth = max_depth, num_leaves = num_leaves, n_estimators = n_estimators, boosting_type = boosting_type, colsample_bytree = colsample_bytree, learning_rate = learning_rate, reg_alpha = reg_alpha, reg_lambda = reg_lambda)if train == True:res = -cross_val_score(lgbm, X_train_OE, y_train).mean()else:res = lgbm.fit(X_train_OE, y_train)return res
lgbm_params_best = param_hyperopt_lgbm(200)
hyperopt_lgbm(lgbm_params_best, train=False)
clf = hyperopt_lgbm(lgbm_params_best, train=False)
clf.score(X_test_OE, y_test)
准确率训练集测试集
LGBM原始模型0.89060.7871
LGBM+TPE+1000.84590.7831
LGBM+TPE+2000.84060.7882
  • 测试更多次数迭代
lgbm_params_best = param_hyperopt_lgbm(1000)
clf = hyperopt_lgbm(lgbm_params_best, train=False)
clf.score(X_train_OE, y_train), clf.score(X_test_OE, y_test)
准确率训练集测试集
LGBM原始模型0.89060.7871
LGBM+TPE+1000.84590.7831
LGBM+TPE+2000.84060.7882
LGBM+TPE+10000.85310.7797

3.2 基于网格搜索的超参数优化

  在 sklearn 中,超参数优化器主要有四种:GridSearchCV(网格搜索)、RandomizedSearchCV(随机网格搜索)、HalvingSearchCV(对半网格搜索) 和 HalvingRandomizedSearchCV(对半随机网格搜索)。这些方法各有特点,适用于不同的场景。

方法搜索策略优点缺点适用场景
GridSearchCV枚举所有参数组合精度最高计算量大参数空间小,计算资源充足
RandomizedSearchCV随机抽取参数子空间计算量较小,灵活性高精度较低参数空间大,计算效率要求高
HalvingSearchCV多轮筛选,淘汰一半参数组合计算效率高,容错性强精度有限数据量大,计算效率要求高
HalvingRandomizedSearchCV随机子空间 + 多轮筛选计算效率最高精度最低数据量极大,计算效率要求极高

3.2.1 网格搜索注意事项

  • 小步前进,快速调整

  每次需要设置一个相对较小的参数搜索空间,然后快速执行一次超参数搜索,并根据超参数搜索结果来调整参数空间,并进行更进一步的超参数搜索,如此往复,直到参数空间内包含了全部参数的最优解为止。

  • 分批训练策略

  一般来说如果超参数个数较多,则可以分两批、甚至是分三批进行搜索,例如有A、B、C、D、E五个超参数时,可以先搜索A、B、C,在搜索出一组最优值后,再以此为中心创建搜索空间并加入新的D、E两个参数,设置各自对应的搜索空间,并进行第二批搜索。

params经验最优范围
num_leavesrange(20, 51, 2)
max_depthrange(5, 15, 2))
learning_ratenp.linspace(0.01, 0.2, 5)
n_estimatorsrange(10, 160, 70)
boosting_type[‘gbdt’, ‘goss’]
colsample_bytree[0.6, 0.8, 1.0]
(第一阶段)reg_alphanp.linspace(0.01, 0.1, 2)
(第二阶段)reg_lambdanp.linspace(0.01, 0.1, 2)

3.2.2 优化案例

import time
import numpy as np
from sklearn.model_selection import GridSearchCV
from lightgbm import LGBMClassifierstart = time.time()# 设置超参数空间
parameter_space = {"num_leaves": range(20, 51, 2), "max_depth": range(5, 15, 2),"learning_rate": list(np.linspace(0.01, 0.2, 5)),"n_estimators": range(10, 160, 70), "boosting_type": ['gbdt', 'goss'], "colsample_bytree": [0.6, 0.8, 1.0]
}# 实例化模型与评估器
LGBM_0 = LGBMClassifier(random_state=22, verbose=-1)  # 禁用输出# 设置网格搜索
grid_LGBM_0 = GridSearchCV(LGBM_0, parameter_space, n_jobs=-1, cv=5, scoring='roc_auc')# 模型训练
grid_LGBM_0.fit(X_train_OE, y_train)print("Best Parameters:", grid_LGBM_0.best_params_)
print("Execution Time:", time.time() - start)grid_LGBM_0.best_score_ #0.84869
grid_LGBM_0.score(X_train_OE, y_train), grid_LGBM_0.score(X_test_OE, y_test) # 输出测试集:0.8768, 验证集:0.8371
grid_LGBM_0.best_params_

在这里插入图片描述

准确率训练集测试集
LGBM原始模型0.89060.7871
LGBM+TPE+1000.84590.7831
LGBM+TPE+2000.84060.7882
LGBM+TPE+10000.85310.7797
LGBM+grid0.87680.8371

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/502355.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

trendFinder - 利用 AI 掌握社交媒体上的热门话题

1600 Stars 177 Forks 7 Issues 2 贡献者 MIT License Javascript 语言 代码: https://github.com/ericciarla/trendFinder 更多AI开源软件:AI开源 - 小众AI Trend Finder 收集并分析来自关键影响者的帖子,然后在检测到新趋势或产品发布时发送 Slack 通知…

Level DB --- BloomFilterPolicy

BloomFilterPolicy是Level DB中重要的数据过滤模块,它主要用来先过滤在Block中不存在的key,减少Block的搜索计算量。 Bloom Filter 从原理上来讲Bloom FIlter相对来说原理还是比较简单的,将一个key经过一次(组合)ha…

ELK 使用教程采集系统日志 Elasticsearch、Logstash、Kibana

前言 你知道对于一个系统的上线考察,必备的几样东西是什么吗?其实这也是面试中考察求职者,是否真的做过系统开发和上线的必备问题。包括:服务治理(熔断/限流) (opens new window)、监控 (opens new window)和日志,如果…

【MySQL】九、表的内外连接

文章目录 前言Ⅰ. 内连接案例:显示SMITH的名字和部门名称 Ⅱ. 外连接1、左外连接案例:查询所有学生的成绩,如果这个学生没有成绩,也要将学生的个人信息显示出来 2、右外连接案例:对stu表和exam表联合查询,把…

机器学习周报-ModernTCN文献阅读

文章目录 摘要Abstract 0 提升有效感受野(ERF)1 相关知识1.1 标准卷积1.2 深度分离卷积(Depthwise Convolution,DWConv)1.3 逐点卷积(Pointwise Convolution,PWConv)1.4 组卷积(Grou…

计算机的错误计算(二百零二)

摘要 利用三个大模型化简计算 前面分式的分子为零,因此正确值是后面的数值300.09...321 . 让三个大模型计算,它们均没有看出分式的分子中被减数与减数是相等的。因此,均得出了错误结果。 例1. 化简计算摘要中算式的值。 下面是一个大模型的…

2025-01-04 Unity插件 YodaSheet1 —— 插件介绍

文章目录 1 介绍2 工作原理2.1 ScriptableObject -> YadeSheetData2.2 YadeDatabase 存储多个 YadeSheetData 3 用途4 缺点5 推荐 1 介绍 ​ Yade 提供类似于 Excel 或者 Google Sheets 的表格编辑器,可以轻松地在 Unity 编辑器中 编辑,搜索&#xf…

connect to host github.com port 22: Connection timed out 的解决方法

原因是 Github 被 GFW 屏蔽了。 Windows 系统,打开 C:\Windows\System32\drivers\etc,复制其中的 hosts 文件至桌面,用文本编辑器或者其他工具打开。 复制以下内容进去: 140.82.114.4 github.com 151.101.1.6 github.global.ss…

memcached的基本使用

memcached是一种基于键值对的内存数据库,一般应用于缓存数据,提高数据访问速度,减轻后端数据库压力。 安装 这里以Ubuntu为例,其他系统安装方法请看官方文档。 sudo apt-get update sudo apt-get install memcached启动 memca…

【操作系统不挂科】操作系统期末考试题库<2>(单选题&简答题&计算与分析题&程序分析题&应用题)

前言 大家好吖,欢迎来到 YY 滴 操作系统不挂科 系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 目录 一、单项选择题(每空2分,共40分)1.以下选项中,( )不是操…

ip属地的信息准确吗?ip归属地不准确怎么办

在数字化时代,IP属地信息成为了我们日常生活中不可或缺的一部分。在各大社交媒体平台上,IP属地信息都扮演着重要的角色。然而,随着技术的不断进步和网络的复杂性增加,IP属地信息的准确性问题也日益凸显。那么,IP属地信…

【GUI-pyqt5】QWidget类

1. 描述 所有可视空间的基类是一个最简单的空白控件控件是用户界面的最小元素 接收各种事件(鼠标、键盘)绘制在桌面上,显示给用户看 每个控件都是矩形的,它们按z轴顺序排序控件由其父控件和前面的控件剪切没有父控件的控件&#…

Linux(Centos 7.6)命令详解:ls

1.命令作用 列出目录内容(list directory contents) 2.命令语法 Usage: ls [OPTION]... [FILE]... 3.参数详解 OPTION: -l,long list 使用长列表格式-a,all 不忽略.开头的条目(打印所有条目,包括.开头的隐藏条目&#xff09…

unity学习6:unity的3D项目的基本界面和菜单

目录 1 unity界面的基本认识 1.1 file 文件 1.2 edit 编辑/操作 1.3 Assets 1.4 gameobject 游戏对象 1.5 组件 1.6 windows 2 这些部分之间的关系 2.1 关联1: Assets & Project 2.2 关联2:gameobject & component 2.3 关联3&#xf…

生成模型的现状2025年的新兴趋势

2024年对人工智能而言是极为出色的一年。在文本生成和图像生成这两方面,我们目睹了模型能力全方位出现了类似阶跃函数般的巨大提升。这一年起始时OpenAI占据主导地位,而到了年末,Anthropic的Claude成了我常用的大型语言模型,并且还…

PWN 的知识之如何利用栈溢出利用后门函数

PWN 的知识之如何利用栈溢出利用后门函数 利用栈溢出漏洞调用原本存在的后门函数(例如 get_flag 或system("/bin/sh"))是二进制漏洞利用中的一种常见技术,相信各位网安的师傅或多或少都听说过,那么如何利用栈溢出来利用后门函数呢…

基于YOLO11的道路缺陷检测系统

基于YOLO11的道路缺陷检测系统 (价格90) 包含 [cracks, potholes] [裂缝, 凹坑] 2个类 通过PYQT构建UI界面,包含图片检测,视频检测,摄像头实时检测。 (该系统可以根据数据训练出的yolo11的权重文件,运用在其他…

JAVA:Spring Boot 集成 Quartz 实现分布式任务的技术指南

1、简述 Quartz 是一个强大的任务调度框架,允许开发者在应用程序中定义和执行定时任务。在 Spring Boot 中集成 Quartz,可以轻松实现任务的调度、管理、暂停和恢复等功能。在分布式系统中,Quartz 也支持集群化的任务调度,确保任务…

数据分析-Excel

数据类型和函数初步 Excel中有文本类型和数值类型–但是无法用肉眼分辨出来isnumber来区分是否是数值类型text和value函数可以完成数值类型以及文本类型的转换单元格第一位输入’方式明确输入的是文本sum函数必须是数值类型 文本连接-and-or-not-if-mod-max函数 字符串的连接…

深入了解 SSL/TLS 协议及其工作原理

深入了解 SSL/TLS 协议及其工作原理 一. 什么是 SSL/TLS?二. SSL/TLS 握手过程三. SSL/TLS 数据加密与传输四. 总结 点个免费的赞和关注,有错误的地方请指出,看个人主页有惊喜。 作者:神的孩子都在歌唱 一. 什么是 SSL/TLS? 安全套接层&am…