点击获取AI摘要

LightGBM内容补充

1. LightGBM (Light Gradient Boosting Machine)

LightGBM (Light Gradient Boosting Machine) 是微软亚洲研究院开发的一个开源梯度提升框架。它设计的目标是提供一个快速、分布式、高性能的梯度提升框架,特别适用于处理大规模数据。LightGBM 在许多方面对传统的 GBDT(包括 XGBoost)进行了优化,使其在训练速度和内存消耗上具有显著优势。

  • 核心思想: 与 XGBoost 类似,LightGBM 也基于梯度提升框架,通过迭代地添加决策树来优化目标函数。其主要创新在于引入了一系列高效的算法来加速训练过程和降低内存消耗,同时保持较高的精度。
  • 与 XGBoost 的主要区别和改进 (重点内容):
    1. 决策树生长策略 (Tree Growth Strategy): XGBoost 默认采用按层生长 (Level-wise / Depth-wise) 策略,而 LightGBM 默认采用按叶生长 (Leaf-wise / Best-first) 策略。Leaf-wise 可以在找到最佳分裂点后,在当前层或更深层生长,可能生成不对称的树,但通常能更快地降低损失函数,达到更高的精度,代价是可能更容易过拟合。
    2. 分裂点查找算法 (Split Finding Algorithm): LightGBM 使用基于直方图 (Histogram-based) 的决策树算法,而不是 XGBoost 默认的精确贪婪算法。直方图算法将连续特征离散化到多个桶中,然后基于桶的离散值寻找分裂点。这大大减少了计算量和内存消耗。
    3. 特征采样 (Feature Sampling): LightGBM 提出了 Exclusive Feature Bundling (EFB) 算法,用于处理高维稀疏特征。EFB 可以将一些互斥(或很少同时出现)的特征捆绑成一个,减少特征数量。
    4. 样本采样 (Sample Sampling): LightGBM 提出了 Gradient-based One-Side Sampling (GOSS) 算法,用于处理样本。GOSS 会保留所有梯度较大的样本(错误分类的样本),并随机采样部分梯度较小的样本,以此减少样本数量,加速训练,同时保持模型的准确性。
    5. 对类别特征的处理 (Categorical Feature Handling): LightGBM 对类别特征有内置优化,可以直接处理类别特征,无需进行 One-Hot 编码,这对于具有大量类别特征的数据集非常有效。
    6. 并行化优化 (Parallelism): LightGBM 在数据并行、特征并行和模型并行方面都进行了优化,特别是在特征并行和数据并行方面,其直方图算法带来了额外的效率提升。

1.1 LightGBM 的核心算法

LightGBM 引入了两个主要的创新算法来提高效率:GOSS 和 EFB。

1.1.1 Gradient-based One-Side Sampling (GOSS)

  • 问题: GBDT 在训练时,每个样本的权重或重要性是不同的,梯度大的样本对模型训练的贡献更大(因为它们是当前模型未很好预测的样本)。如果简单地随机下采样,可能会丢失一些重要样本的信息。
  • 思想: GOSS 算法保留所有梯度较大的样本("大梯度"样本),并对梯度较小的样本("小梯度"样本)进行随机采样。为了补偿小梯度样本被采样丢弃的信息,它会将采样到的小梯度样本乘以一个常数因子进行放大。
  • 步骤:
    1. 根据样本的梯度大小将样本排序。
    2. 选择 Top a×100%a \times 100\% 的样本作为大梯度样本 (aa 是一个超参数,如 top_rate)。
    3. 从剩下 (1a)×100%(1-a) \times 100\% 的小梯度样本中,随机采样 b×100%b \times 100\% 的样本作为采样到的小梯度样本 (bb 是一个超参数,如 other_rate)。
    4. 在计算增益时,对于采样到的小梯度样本,将其梯度乘以一个缩放因子 1ab\frac{1-a}{b}。大梯度样本的梯度保持不变。
  • 效果: 在减少样本数量的同时,保留了更多重要的信息,从而在保证精度的情况下加速训练。

1.1.2 Exclusive Feature Bundling (EFB)

  • 问题: 在高维稀疏数据集中,许多特征是稀疏的,并且许多特征在同一行样本中是互斥的(例如,One-Hot 编码后的特征,不同类别的 One-Hot 特征在同一行只有一个是 1)。基于直方图的算法仍然需要遍历每个特征来构建直方图。
  • 思想: EFB 算法可以识别出那些互斥的特征集合,并将它们捆绑 (Bundle) 成一个单一的特征。通过捆绑,减少了特征数量,从而降低了构建直方图和计算增益的计算复杂度。
  • 机制: 通过构建特征之间的关系图(非零值是否同时出现)或使用贪婪算法,将互斥特征或冲突很少(冲突在可接受范围内,通过参数控制)的特征合并。
  • 效果: 显著减少了特征数量,特别适用于 One-Hot 编码或具有大量稀疏特征的数据集,提高了训练速度。

1.2 基于直方图的树分裂 (Histogram-based Tree Splitting)

  • 思想: LightGBM 不像精确贪婪算法那样遍历所有可能的连续分裂点,而是将连续特征离散化到固定的 kk 个桶中。在分裂时,只考虑这 kk 个桶边界作为分裂点。
  • 过程:
    1. 训练前,对每个特征,构建一个具有 kk 个桶的直方图。每个桶存储落入该范围内的样本的一阶和二阶梯度和。
    2. 在树节点分裂时,遍历特征,不再需要对样本排序。而是直接遍历这 kk 个桶,计算每个桶边界作为分裂点的增益。
    3. 选择最佳桶边界作为分裂点。
  • 优点:
    • 计算效率: 构建直方图的复杂度是 O(data×features)O(\text{data} \times \text{features}),寻找最佳分裂点的复杂度是 O(k×features)O(k \times \text{features})。远小于精确算法的 O(datalogdata)O(\text{data} \log \text{data})O(data×features)O(\text{data} \times \text{features})
    • 内存消耗: 只需存储直方图而不是所有样本的排序特征值。
  • 缺点: 是一种近似算法,找到的分裂点不是最优的,可能损失微小精度(在实际应用中通常可以忽略)。

1.3 按叶生长策略 (Leaf-wise / Best-first Tree Growth)

  • 对比:
    • Level-wise (XGBoost 默认): 每次分裂扩展同一层的所有叶子节点。树结构是对称的,易于并行化。
    • Leaf-wise (LightGBM 默认): 每次分裂只选择当前具有最大分裂增益的叶子节点进行分裂。
  • 优点:
    • 在分裂次数相同的情况下,Leaf-wise 可以比 Level-wise 降低更多的损失,因为它总是优先分裂那些最具“增益潜力”的节点。这通常意味着可以用更少的迭代次数或分裂次数达到目标精度。
  • 缺点:
    • 可能生成不对称的树结构,在同一层深度上的节点数差异较大。
    • 由于每次只扩展一个叶子,如果不对最大深度进行限制 (max_depth 参数),Leaf-wise 可能会生成很深的树,导致过拟合。因此,在使用 Leaf-wise 时,通常需要配合限制最大深度或叶子节点数 (num_leaves) 来控制模型复杂度。

1.4 LightGBM 的目标函数

LightGBM 基于 GBDT 框架,其目标函数与 XGBoost 非常相似,也是在每一步迭代中找到一棵树 ht(x)h_t(x) 来优化损失函数和正则化项。使用二阶泰勒展开近似损失函数后,其目标函数形式与 XGBoost 基本一致:

Obj(t)i=1n[giht(xi)+12hiht(xi)2]+Ω(ht)\text{Obj}^{(t)} \approx \sum_{i=1}^n \left[ g_i h_t(x_i) + \frac{1}{2} h_i h_t(x_i)^2 \right] + \Omega(h_t)

其中 gig_ihih_i 是一阶和二阶导数,Ω(ht)\Omega(h_t) 是正则化项(形式与 XGBoost 类似)。

主要的区别在于,在基于直方图的分裂过程中,这些 gig_ihih_i 会被累加到对应的桶中,分裂增益的计算也基于这些桶的统计信息。

1.5 LightGBM 参数解释 (部分关键参数)

LightGBM 的参数也很多,许多参数与 XGBoost 含义类似,但也有一些独特参数或常用值范围不同。

参数/属性 描述 默认值 类型/选项 重要性级别 与XGBoost对比
objective 定义学习任务及损失函数。类似 XGBoost。 'regression' string 类似
metric 评估指标。类似 XGBoost 的 eval_metric 根据 objective string or list of strings 高 (用于评估) 类似
boosting_type Boosting 类型。'gbdt' (标准梯度提升),'dart' (Dropout),'goss' (Gradient-based One-Side Sampling)。重要! 控制是否使用 GOSS。 'gbdt' 'gbdt', 'dart', 'goss' XGBoost 无此直接控制 GOSS 的参数
num_leaves 每棵树的最大叶子节点数。 这是控制树模型复杂度的主要参数,优先于 max_depth。 Leaf-wise 策略下,节点数越多,树越复杂。通常设置为 2k2^k (其中 kk 是期望的深度)。常见值在 32-128 之间。 31 int LightGBM Leaf-wise 策略下的关键参数,XGBoost 主要是 max_depth
max_depth 树的最大深度。在 Leaf-wise 模式下,这不是严格的限制,但可以用来防止树长得太深过拟合。 -1 表示无限制。在 Level-wise 模式下,与 XGBoost 含义相同。 -1 int 高 (防过拟合) LightGBM 优先 num_leaves,XGBoost 优先 max_depth
learning_rate 学习率 (Learning Rate)。 等同于 XGBoost 的 eta。缩放每棵树的贡献。 0.1 float 类似
n_estimators Boosting 迭代次数,即树的数量。 100 int 类似
subsample 训练每棵树时,随机采样的训练样本比例 (行采样)。与 XGBoost 含义相同。 1.0 float 类似
colsample_bytree 训练每棵树时,随机采样的特征比例 (列采样)。与 XGBoost 含义相同。 1.0 float 类似
min_child_samples 子节点中所需的最小样本数。 类似于 XGBoost 的 min_child_weight,但基于样本数量。值越大,模型越保守。 20 int 类似于 XGBoost 的 min_child_weight 但更直接基于样本数
min_child_weight 子节点中所需的最小样本权重和。与 XGBoost 含义类似。 0.001 float 类似
gamma (min_split_gain) 在节点分裂时,只有分裂后损失函数的减少量(增益)大于等于 min_split_gain 时,才会进行分裂。 与 XGBoost 的 gamma 含义相同。 0.0 float 类似
reg_alpha L1 正则化系数。与 XGBoost 含义相同。 0.0 float 类似
reg_lambda L2 正则化系数。与 XGBoost 的 reg_lambda 含义相同。 0.0 float 类似
colsample_bynode 在树的每个节点分裂时,随机采样的特征比例。与 XGBoost 含义相同。 1.0 float 类似
subsample_freq subsample 参数进行采样的频率。每隔 subsample_freq 次迭代执行一次 subsample 1 int XGBoost 无此参数
top_rate [GOSS 参数] GOSS 算法中保留的大梯度样本比例。 0.1 float 高 (使用 GOSS时) LightGBM 独有 (GOSS)
other_rate [GOSS 参数] GOSS 算法中随机采样的小梯度样本比例。 0.07 float 高 (使用 GOSS时) LightGBM 独有 (GOSS)
bin_construct_sample_cnt [直方图参数] 用于构建特征直方图的样本数。 通过采样部分样本来构建直方图可以加速,尤其在数据量巨大时。 200000 int 实用 XGBoost 无此参数
num_iterations Boosting 迭代次数。与 n_estimators 相同,但更推荐使用 n_estimators 以兼容 scikit-learn API。 100 int 类似
n_jobs 并行计算使用的CPU数量。-1 表示使用所有可用的处理器。 -1 int 实用 类似
random_state 随机种子。控制随机性,确保结果可复现。 None int 实用 类似
categorical_feature 指定哪些特征是类别特征。可以是特征索引列表或特征名称列表。 'auto' 表示自动检测。 重要! LightGBM 内置优化类别特征处理。 'auto' list of int, list of str, or 'auto' 高 (处理类别特征时) XGBoost 需要手动处理 (如 One-Hot)
early_stopping_rounds [fit 方法参数] 早期停止轮数。fit 方法中指定。如果在验证集上经过 early_stopping_rounds 轮迭代后,评估指标没有提升,训练就会停止。需要同时提供验证集和 metric非常重要! N/A int 高 (用于早期停止) 类似
callbacks [fit 方法参数] 回调函数列表。 可以用来实现早停、日志记录等功能。EarlyStopping 回调函数提供了早期停止功能。 None list of callback objects 实用 (用于早期停止) 类似
feature_importances_ [属性] 特征重要性。 拟合后可用。LightGBM 默认是基于分裂次数 (split) 或增益 (gain)。 N/A array N/A 类似,但 LightGBM 默认是 splitgain,XGBoost 默认是 gain

1.6 Scikit-learn API 示例 (LightGBM)

LightGBM 也提供了与 scikit-learn 兼容的 API (LGBMClassifierLGBMRegressor)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# 导入 LightGBM 的 Scikit-learn API
import lightgbm as lgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
from sklearn.datasets import load_iris # 假设使用 Iris 数据集
import pandas as pd # LightGBM 对 Pandas DataFrame 支持更好

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target
feature_names = iris.feature_names
target_names = iris.target_names

# 转换为 Pandas DataFrame (LightGBM 对 Pandas 支持很好)
X_df = pd.DataFrame(X, columns=feature_names)
y_series = pd.Series(y) # Target can also be a Series

# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(X_df, y_series, test_size=0.3, random_state=42, stratify=y_series)

print("\n--- LightGBM Classifier 示例 ---")

# 初始化 LightGBM 分类器
# objective='multiclass' 或 'softmax' 用于多分类
# num_class=3 指定类别数量
# metric='multi_logloss' 是多分类常用的评估指标
lgb_clf = lgb.LGBMClassifier(objective='multiclass',
num_class=3, # 多分类时需要指定类别数量
metric='multi_logloss', # 评估指标
n_estimators=500, # 初始设置多一些树,配合 early stopping
learning_rate=0.1,
num_leaves=31, # 默认值,或根据 max_depth 设置
max_depth=-1, # 无严格深度限制,主要靠 num_leaves 控制复杂度
min_child_samples=20, # 最小叶子样本数
subsample=0.8, # 行采样
colsample_bytree=0.8, # 列采样
reg_alpha=0.1, # L1 正则化
reg_lambda=0.1, # L2 正则化
n_jobs=-1, # 使用所有CPU
random_state=42,
boosting_type='gbdt' # 或者 'goss' 使用GOSS
# categorical_feature='auto' # 自动检测类别特征,或指定索引列表
)

# 使用 Early Stopping 进行训练
# 需要提供评估数据集和评估指标名称
eval_set = [(X_test, y_test)]
# early_stopping_rounds 参数直接在 fit 方法中使用
lgb_clf.fit(X_train, y_train,
eval_set=eval_set,
eval_metric='multi_logloss', # 需要在fit方法中再次指定评估指标
callbacks=[lgb.early_stopping(stopping_rounds=10, verbose=True)] # 新版本推荐使用 callbacks
# early_stopping_rounds=10 # 旧版本用法
)

# 预测
y_pred_lgb = lgb_clf.predict(X_test)
accuracy_lgb = accuracy_score(y_test, y_pred_lgb)
print(f"\n准确率: {accuracy_lgb:.4f}")
# print("分类报告:\n", classification_report(y_test, y_pred_lgb, target_names=target_names))

# 打印实际训练的树数量
# 在 callbacks 中使用 early_stopping 时,可以通过 .best_iteration_ 获取
if hasattr(lgb_clf, 'booster_'):
print(f"实际训练的树数量: {lgb_clf.booster_.current_iteration()}")
elif hasattr(lgb_clf, '_best_iteration'):
print(f"实际训练的树数量: {lgb_clf._best_iteration + 1}")
else:
print(f"实际训练的树数量: {lgb_clf.n_estimators}")

# 打印特征重要性 (默认是 'split')
print("特征重要性 (LightGBM - Split):")
for name, importance in zip(feature_names, lgb_clf.feature_importances_):
print(f" {name}: {importance}") # LightGBM split importances are integers

# 也可以获取基于增益的特征重要性
# print("\n特征重要性 (LightGBM - Gain):")
# feature_importances_gain = lgb_clf.booster_.feature_importance(importance_type='gain')
# for name, importance in zip(feature_names, feature_importances_gain):
# print(f" {name}: {importance:.4f}")

注意: LightGBM 的 early_stopping_rounds 参数在较新版本中被移除,推荐使用 callbacks 参数列表中的 lgb.early_stopping 函数。示例代码中展示了新版用法。

1.7 LightGBM 的优点和缺点

  • 优点:
    • 速度快: 基于直方图的算法、GOSS、EFB 等技术使其训练速度通常比 XGBoost 快很多。
    • 内存消耗低: 基于直方图的算法和 EFB 显著减少了内存占用。
    • 支持大规模数据: 高效的算法和内存优化使其能够轻松处理大规模数据集。
    • 支持类别特征: 内置优化处理,无需 One-Hot 编码。
    • 更高的精度 (有时): Leaf-wise 策略可能在相同迭代次数下达到更高精度。
  • 缺点:
    • 可能容易过拟合: Leaf-wise 策略容易生成深而不平衡的树,需要小心调整 num_leavesmax_depth 参数。
    • 对稀疏数据处理不如 XGBoost: 虽然有 EFB,但对于某些特定的稀疏数据,其效果可能不如 XGBoost 内置的稀疏分裂处理机制。
    • 需要仔细调参: 虽然参数比 XGBoost 少一些,但核心参数如 num_leaves 和 GOSS/EFB 参数需要仔细调整。

1.8 小结

LightGBM 是一个面向大规模数据的高效梯度提升框架。它通过采用基于直方图的决策树算法、独特的按叶生长策略、GOSS(梯度单边采样)和 EFB(互斥特征捆绑)等技术,显著提升了训练速度和降低了内存消耗。这些创新使其成为处理大规模数据集和进行快速模型训练的有力工具。与 XGBoost 相比,LightGBM 在速度和内存方面通常有优势,尤其是在 Leaf-wise 策略和直方图算法的加持下。然而,其 Leaf-wise 策略也带来了更容易过拟合的风险,需要通过 num_leaves 等参数进行额外控制。内置的类别特征处理也是其一大亮点。