一个模型怎样预测两个数值目标?用 MultiOutputRegressor 对齐输出并逐列验收

用 MultiOutputRegressor 为两个连续目标分别训练回归器,固定输出顺序、保留样本编号,并按各自单位验收预测误差。

同一条样本要同时预测两个连续数值时,可以把目标写成两列表,再用MultiOutputRegressor扩展单目标回归器。最需要防止的是输出列错位和单位混用:程序能返回两列数,不等于两项业务指标都已经验收。

固定每条样本和每个目标的关系

MultiOutputRegressor 为每个目标单独拟合一个回归器,预测返回形状为(样本数,目标数)的矩阵;本例两列依次是duration_min和energy_kwh。

一个模型怎样预测两个数值目标?用 MultiOutputRegressor 对齐输出并逐列验收

duration_min表示一个虚构过程的耗时分钟数,energy_kwh表示能耗千瓦时;两列共享同一条样本的两个输入特征。数据完全由公式和随机噪声生成,没有来自真实设备。这里的“一个模型”是一个封装对象,内部实际有两个独立估计器。

本文示例已在 Python 3.11、scikit-learn 1.7.2、NumPy 2.4.6、pandas 2.3.3、SciPy 1.17.1 的本地 CPU 环境运行;输入是人为生成的教学数据,不是客户案例。

python -m venv .venv
# Windows PowerShell
.\.venv\Scripts\Activate.ps1
python -m pip install scikit-learn==1.7.2 pandas==2.3.3 numpy==2.4.6 scipy==1.17.1

同一次划分保留两列标签,训练并导出预测

将下面代码保存为 multioutput_demo.py 并运行 python multioutput_demo.py,查看输出顺序、(100,2)预测形状及两列MAE,再打开multioutput-review.csv逐行核对。

不要对两个目标分别随机切分再拼接。下面将X与整个Y一起交给train_test_split,保留每行配对关系;target_names在训练前固定,之后按该顺序命名预测列。

import numpy as np
import pandas as pd
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import train_test_split
from sklearn.multioutput import MultiOutputRegressor

rng = np.random.default_rng(42)
X = rng.uniform(0, 1, size=(400, 2))
Y = pd.DataFrame({
    "duration_min": 10 + 15 * X[:, 0] + 5 * X[:, 1] + rng.normal(0, 0.5, 400),
    "energy_kwh": 2 + 4 * X[:, 0]**2 + 2 * X[:, 1] + rng.normal(0, 0.1, 400),
})
target_names = Y.columns.tolist()
X_train, X_test, y_train, y_test = train_test_split(
    X, Y, test_size=0.25, random_state=42
)
model = MultiOutputRegressor(GradientBoostingRegressor(
    n_estimators=80, max_depth=2, random_state=42
), n_jobs=1)
model.fit(X_train, y_train)
pred = model.predict(X_test)
assert pred.shape == (len(y_test), len(target_names))
assert len(model.estimators_) == len(target_names)
assert np.isfinite(pred).all()
errors = mean_absolute_error(y_test, pred, multioutput="raw_values")
print("输出顺序:", target_names)
print("预测形状:", pred.shape)
for name, error in zip(target_names, errors):
    print(name, "MAE", round(float(error), 4))
result = pd.DataFrame(pred, columns=["pred_" + n for n in target_names], index=y_test.index)
result = y_test.join(result).rename_axis("sample_id")
result.to_csv("multioutput-review.csv", encoding="utf-8-sig")
print(result.head(3).round(3).to_string())

底层GradientBoostingRegressor每次学习一列连续目标,包装器创建两个估计器。n_jobs=1使本例按顺序训练;目标少且单次训练很快时,增加并行度可能因为调度开销而更慢,不应未经计时就改成全部CPU并行。

逐目标验收,保持原始编号

本例100条合成测试记录的duration_min MAE为0.4743,energy_kwh MAE为0.1095;它们分别以分钟和千瓦时解释,不能直接求平均后称作一个统一业务误差。

检查 本例值 为什么要看
target_names duration_min, energy_kwh 模型输出顺序的固定约定
pred.shape (100,2) 每条测试样本对应两项预测
estimators_数量 2 确认每个目标都训练了估计器
multioutput=raw_values 两个MAE 按原单位分开解释

CSV包含原样本编号sample_id、两列真值和两列预测。例如sample_id=209的耗时真值约17.748、预测17.117,能耗真值约4.126、预测3.960;逐行表能帮助定位哪一个目标在哪些输入上误差较大。该编号只是合成数据的原始行索引,正式数据应换成稳定业务样本ID。

为耗时和能耗分别设定可接受误差和明显非法范围;不能用耗时预测表现不错抵消能耗错误。计算整表平均误差之前先确定单位变换和业务权重,否则数值较大的目标会主导解释。

什么时候不能只套这个包装器

这个包装器独立训练各个目标,不会利用两个目标之间的相关关系,也不会自动保证总量约束、非负性或目标之间的物理一致性。

如果两个输出存在必须满足的约束,例如各分项之和必须等于总数,要在预测后明确验证,或选择能表达该关系的建模方案。遇到缺失目标时,也不能把NaN当作已知0填入;先确认对应标签能否用于当前训练。

许多回归器原生支持多输出,此时不一定需要这个包装器。选择它通常是因为底层算法只接收单列目标,或希望逐目标检查拟合器。MultiOutputRegressor统一应用同一份参数配置,不会自动给不同目标挑选最优参数。

用于真实任务前的下一步

定义两项连续标签在预测时的可用性与合法范围,核对样本连接关系,用同一划分分别评估。部署时保存target_names、输入列顺序和单位;先用几个已知样本验证列名与数值含义,再开放给下游调用。这里两个输出的MAE只属于教学数据,不是现场效果。

官方资料与适用版本

本文于2026年10月1日核对下列官方资料,接口说明对应 scikit-learn 1.7;运行示例使用1.7.2。

Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/30728.html

赞 (0)
AI小管家的头像AI小管家
回归目标怎么做对数变换?用 TransformedTargetRegressor 还原原尺度预测
上一篇 6小时前
AI 语料库怎么建立?给文本保存来源、许可和稳定编号
下一篇 6小时前

相关推荐

联系我们

联系我们

1

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
关注微信
分享本页
返回顶部