提问人:riccio777 提问时间:10/21/2023 最后编辑:riccio777 更新时间:10/23/2023 访问量:91
lgb.cv 和 cross_val_score 之间的差异导致使用 LightGBM 进行多类分类
Discrepancy between lgb.cv and cross_val_score results in multiclass classification with LightGBM
问:
我希望在使用 和 时获得类似的交叉验证结果,但它们差异很大:lgb.cv
cross_val_score
import lightgbm as lgb
import pandas as pd
from sklearn import datasets
from sklearn.metrics import log_loss
from sklearn.model_selection import cross_val_score
from typing import Any, Dict, List
def log_loss_scorer(clf, X, y):
y_pred = clf.predict_proba(X)
return log_loss(y, y_pred)
iris = datasets.load_iris()
features = pd.DataFrame(columns=["f1", "f2", "f3", "f4"], data=iris.data)
target = pd.Series(iris.target, name="target")
# 1) Native API
dataset = lgb.Dataset(features, target, feature_name=list(features.columns), free_raw_data=False)
native_params: Dict[str, Any] = {
"objective": "multiclass", "boosting_type": "gbdt", "learning_rate": 0.05, "num_class": 3, "seed": 41
}
cv_logloss_native: float = lgb.cv(
native_params, dataset, num_boost_round=1000, nfold=5, metrics="multi_logloss", seed=41, stratified=False,
shuffle=False
)['valid multi_logloss-mean'][-1]
# 2) ScikitLearn API
model_scikit = lgb.LGBMClassifier(
objective="multiclass", boosting_type="gbdt", learning_rate=0.05, n_estimators=1000, random_state=41
)
cv_logloss_scikit_list: List[float] = cross_val_score(
model_scikit, features, target, scoring=log_loss_scorer
)
cv_logloss_scikit: float = sum(cv_logloss_scikit_list) / len(cv_logloss_scikit_list)
print(f"Native logloss CV {cv_logloss_native}; Scikit logloss CV train {cv_logloss_scikit}")
我使用本机 API 获得分数,使用 API 获得分数。我尝试了不同的指标,但两种方法之间的结果仍然非常不同。
这种差异是否有具体原因,我怎样才能使两种方法之间的结果保持一致?0.8803800291063604
0.37528027519836027
scikit-learn
编辑: 正如 @DataJanitor 所建议的那样,我从本机 API 中禁用了 multi_logloss 指标,并实现了自己的指标:
def log_loss_custom_metric(y_pred, data: lgb.Dataset):
y_true = data.get_label()
loss_value = log_loss(y_true, y_pred)
return "custom_logloss", loss_value, True
我通过参数将其传递给本机 api:feval
cv_logloss_native: float = lgb.cv(native_params, dataset, num_boost_round=1000, nfold=5, feval=log_loss_custom_metric, shuffle=True)["valid custom_logloss-mean"][-1]
但是,结果仍然相差很大(本机 API 为 0.58,scikit API 为 0.37)。
我报告的代码是 100% 可重现的,因为我使用的是鸢尾花数据集。如果有人能设法匹配分数并实际告诉我哪个是差异的根源,那就太好了。
答:
我看到了多个潜在的差异来源:
您的原生 LGBM API 代码集 .这可能会导致褶皱不平衡。自动对分类任务的折叠进行分层,确保每个类的均衡表示。stratified=False
scikit-learn
cross_val_score
Shuffle:您已在本机 API 中设置,保持数据顺序。相反,除非另有说明,否则将在折叠前对数据进行随机排序。shuffle=False
cross_val_score
自定义评分器:你使用了自定义评分器,用于计算多类对数丢失。尽管您已将本机 API 指标设置为 multi_logloss,但由于实现不同,计算可能会存在细微差异。scikit-learn
评论