【问题标题】:Lightgbm splits differently on the same dataset (one hot encoded vs one-vs-other split algorithm)Lightgbm 在同一个数据集上进行不同的分割(一种热编码与一对一分割算法)
【发布时间】:2025-11-26 11:55:02
【问题描述】:

在lightgbm上做小测试的时候,发现了一个看不懂的案例。

我创建了一个带有分类列的小数据集:

import pandas as pd

X = pd.DataFrame(
    [
        [0, 1, 1],
        [2, 2, 0],
        [3, 3, 2],
        [2, 3, 2],
        [0, -3, 0],
        [0, 0, 1],
        [0, 3, 0],
        [1, 2.5, 1],
        [2, 5, 0],
        [3, -1.5, 2],
     ],
     columns=["col1", "col2", "col3"],
)
X["col1"] = X["col1"].astype("category")
X["col3"] = X["col3"].astype("category")
y = pd.Series([0, 1, 1, 0, 0, 0, 0, 1, 0, 1])

及其相关的一个热编码版本:

from sklearn.preprocessing import OneHotEncoder

feats_to_encode = ["col1", "col3"]
enc = OneHotEncoder()
enc.fit(X[feats_to_encode])
X_one_hot_encoded = pd.DataFrame(
    enc.transform(X[feats_to_encode]).toarray(),
    columns=[
        feats_to_encode[feat_id] + str(cat)
        for feat_id in range(len(enc.categories_))
        for cat in enc.categories_[feat_id]
    ],
)
X_one_hot_encoded["col2"] = X["col2"]

然后,我使用之前的数据集训练了 2 个 lightgbm 模型。我知道 lightgbm 使用特殊算法管理分类列。 “当一个特征的类别数小于或等于 max_cat_to_onehot 时,将使用 one-vs-other 拆分算法”(参见max_cat_to_onehot)。然后我会天真地期望,因为我的分类列的类别(4 和 3)比参数 max_cat_to_onehot 少,所以我会在两个数据集上得到相同的结果,除非“one-vs-other split algorithm”不等效到一个热编码分类列。我假设这种行为是因为参数名称“max_cat_to_onehot”和算法“one-vs-other split algorithm”。

from lightgbm import LGBMRegressor

params = {
    "n_estimators": 1,
    "max_depth": 2,
    "min_child_samples": 1,
    "importance_type": "gain",
    "max_cat_to_onehot": 10,
}

model = LGBMRegressor(**params)
model.fit(X, y)
print(model._Booster.dump_model()["tree_info"][0]["tree_structure"]["split_gain"]) # 0.30476200580596924

model = LGBMRegressor(**params)
model.fit(X_one_hot_encoded, y)
print(model._Booster.dump_model()["tree_info"][0]["tree_structure"]["split_gain"]) # 1.0666699409484863

两个模型之间的第一次拆分是不同的。第二个模型选择了可能的最佳拆分,但第一个模型并非如此。

有人知道这是什么原因吗?我假设我对“one-vs-other split algorithm”行为的猜测是错误的。

【问题讨论】:

    标签: python algorithm lightgbm


    【解决方案1】:

    我将 lightgbm 版本从 2.3.1 更新到 3.1.1。有了新版本,我得到了预期的结果。

    【讨论】:

      最近更新 更多