You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在独立CatBoost中复现mljar-supervised的缩放预处理逻辑

mljar-supervised CatBoost模型复现问题解答

目标变量y的处理逻辑

你的判断完全正确。
配置中scale_method: "scale_normal"对应StandardScaler标准化操作:框架仅在训练集上拟合y的标准化参数,按y_scaled = (y - mean)/scale变换后送入回归器训练;预测阶段模型输出缩放尺度的预测值后,会执行pred_original = pred_scaled * scale + mean的逆变换,还原到原始目标值尺度。
你贴出的配置中n_samples_seen: 75000刚好对应10w总样本的75%训练集占比,也印证了scaler是仅在训练集上拟合的,没有接触验证/测试集数据。

特征X的"scale"处理逻辑

columns_info里标注的"scale"不是对所有模型生效的通用StandardScaler变换:

  • 该标记是mljar预处理管道的通用标识,仅对线性模型、神经网络这类对特征尺度敏感的模型启用StandardScaler;
  • 对于CatBoost、XGBoost、LightGBM这类树模型,框架默认跳过特征缩放步骤——因为树模型基于特征分裂阈值训练,特征缩放完全不影响分裂结果,反而会增加不必要的计算。给树模型输入的特征仅会经过缺失值填充、分类特征编码、极端离群值截断处理,保留原始数值尺度。

复现结果差异大的核心原因与修正方案

你之前的复现代码存在3个关键偏差,直接导致结果差异:

  1. 预处理拟合范围错误:你在全量10w样本上拟合y和X的scaler,但框架的所有预处理参数仅在7.5w训练集样本上拟合,全量拟合得到的mean、scale参数和框架保存的参数存在偏差。
  2. 错误添加特征标准化步骤:你对所有X特征做了StandardScaler变换,但框架训练CatBoost时完全跳过这一步,喂入模型的特征分布和你处理后的分布完全不一致。
  3. 拆分逻辑与超参数不匹配:你按位置顺序切分训练/验证集,且手动设置CatBoost超参数,和框架默认的随机分层拆分、自动调优得到的超参不匹配。

正确复现步骤

  1. 直接使用框架保存的y缩放参数:不需要自己在数据上拟合scaler,直接用framework.json里存储的mean、scale值做y的变换和逆变换即可。
  2. 移除X的StandardScaler步骤:仅对X做和框架一致的基础预处理:数值列用训练集中位数填充缺失值,分类列用<MISSING>填充缺失值并转为字符串类型,可选做1%/99%分位数的离群值截断。
  3. 对齐数据拆分逻辑:使用和框架一致的拆分规则:固定随机种子1234,shuffle后拆分,75%训练集、10%验证集、15%测试集,不要按位置顺序切分。
  4. 对齐模型超参数:不要手动设置CatBoost参数,直接从mljar输出模型目录下的params.json中加载所有训练超参,同时固定CatBoost的随机种子和框架一致。

参考修正代码

import pandas as pd
import numpy as np
from catboost import CatBoostRegressor, Pool
from sklearn.model_selection import train_test_split

# 直接加载framework.json中保存的y缩放参数,无需自行拟合
Y_MEAN = 0.994522478250971
Y_SCALE = 0.025919186407451625

# 加载原始数据,不对X做StandardScaler
df = pd.read_csv("your_raw_data.csv")  # 替换为原始数据路径
X = df.drop("target", axis=1)
y = df["target"]
y_scaled = (y - Y_MEAN) / Y_SCALE

# 对齐mljar默认拆分逻辑:固定随机种子1234,shuffle拆分
X_train_val, X_test, y_train_val, y_test = train_test_split(
    X, y_scaled, test_size=0.15, random_state=1234, shuffle=True
)
X_train, X_val, y_train, y_val = train_test_split(
    X_train_val, y_train_val, test_size=0.1/0.85, random_state=1234, shuffle=True
)

# 基础预处理:缺失值填充
cat_features = X.select_dtypes(include=["object", "category"]).columns.tolist()
for col in X.columns:
    if col in cat_features:
        fill_val = "<MISSING>"
        X_train[col] = X_train[col].fillna(fill_val).astype(str)
        X_val[col] = X_val[col].fillna(fill_val).astype(str)
    else:
        fill_val = X_train[col].median()
        X_train[col] = X_train[col].fillna(fill_val)
        X_val[col] = X_val[col].fillna(fill_val)

# 加载框架保存的CatBoost超参,不要手动设置
model_params = {
    "iterations": 10000,
    "early_stopping_rounds": 50,
    "random_seed": 1234,
    "verbose": False
    # 其余参数从mljar生成的params.json中补全
}

# 训练模型
train_pool = Pool(X_train, y_train, cat_features=cat_features)
val_pool = Pool(X_val, y_val, cat_features=cat_features)
model = CatBoostRegressor(**model_params)
model.fit(train_pool, eval_set=val_pool)

# 预测时逆变换回原始尺度
pred_scaled = model.predict(X_val)
pred_original = pred_scaled * Y_SCALE + Y_MEAN

如果对齐以上步骤后仍有微小差异,可检查framework.json中是否开启了额外的特征选择、目标编码等预处理步骤,逐一对应配置即可,最终结果差异会控制在浮点误差范围内。


内容的提问来源于stack exchange,提问作者Paul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 19:57:17