如何用scikit-learn实现单最终估计器的多输出堆叠回归?
我尝试过sklearn.ensemble.StackingRegressor,但根据其文档,该工具仅支持最终估计器输出形状为(n_samples,)的单变量场景,而我需要输出形状为(n_samples, n_features)的多变量结果。
作为替代方案,我试过sklearn.multioutput.MultiOutputRegressor,但它会为每个输出特征单独训练模型,在高维数据上训练速度慢且参数冗余,不符合我的需求。我希望用单个最终估计器(比如随机森林)来接收多变量输入并输出多变量结果,让预测流水线更简洁、训练更快。
我期望的流程如下:
+-----------------------+----+--------------+-------------------------------------------+----+-------------+----+------------------+ | Set of observations 1 | -> | Base Model 1 | | | | | | | (nsmpls, nfeats) | | | | | | | | +-----------------------+----+--------------+-------------------------------------------+----+-------------+----+------------------+ | | Concatenated predictions from base models | -> | Final model | -> | Final prediction | | | (nsmpls, 2 * nfeats) | | | | (nsmpls, nfeats) | +-----------------------+----+--------------+-------------------------------------------+----+-------------+----+------------------+ | Set of observations 2 | -> | Base Model 2 | | | | | | | (nsmpls, nfeats) | | | | | | | | +-----------------------+----+--------------+-------------------------------------------+----+-------------+----+------------------+
注:示例中基础模型的输入输出特征数相同,逻辑也适用于其他情况;每个基础模型使用不同输入特征集的问题我已经解决。我也可以直接在拼接输入上训练最终模型,但希望同时训练两个基础模型(它们本身有研究价值),实现一举两得。
解决方案:手动实现多输出堆叠逻辑
scikit-learn官方的StackingRegressor暂不支持多输出的最终估计器,你可以手动实现堆叠流程,既保留基础模型的独立训练,又能使用单个多输出最终估计器:
1. 训练基础模型并生成预测特征
先分别训练两个基础模型,再用它们对训练集生成预测结果,作为最终模型的输入特征:
import numpy as np from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split # 假设X1、X2是两个基础模型的输入特征,y是多输出目标 X1, X2, y = ... # 替换为你的数据集 X1_train, X1_test, X2_train, X2_test, y_train, y_test = train_test_split(X1, X2, y, test_size=0.2) # 训练基础模型 base_model1 = RandomForestRegressor() base_model1.fit(X1_train, y_train) base_model2 = RandomForestRegressor() base_model2.fit(X2_train, y_train) # 生成训练集的预测结果并拼接 train_preds1 = base_model1.predict(X1_train) train_preds2 = base_model2.predict(X2_train) X_final_train = np.hstack([train_preds1, train_preds2]) # 形状为(nsmpls, 2*nfeats) # 生成测试集的预测结果并拼接 test_preds1 = base_model1.predict(X1_test) test_preds2 = base_model2.predict(X2_test) X_final_test = np.hstack([test_preds1, test_preds2])
2. 训练多输出最终估计器
直接用原生支持多输出的模型(比如随机森林)作为最终估计器,在拼接后的特征上训练:
# 训练最终多输出模型 final_model = RandomForestRegressor() final_model.fit(X_final_train, y_train) # 生成多输出预测 y_pred = final_model.predict(X_final_test) # y_pred形状为(nsmpls, nfeats),满足需求
3. 封装为可复用类(可选)
如果需要像scikit-learn内置模型一样调用fit和predict,可以封装一个自定义类:
from sklearn.base import BaseEstimator, RegressorMixin from sklearn.base import clone class MultiOutputStackingRegressor(BaseEstimator, RegressorMixin): def __init__(self, base_models, final_model): self.base_models = base_models self.final_model = final_model def fit(self, X_list, y): # X_list是基础模型的输入列表,例如[X1, X2] self.base_models_ = [] train_preds = [] for idx, X in enumerate(X_list): model = clone(self.base_models[idx]) model.fit(X, y) self.base_models_.append(model) train_preds.append(model.predict(X)) # 拼接所有基础模型的预测结果 X_final = np.hstack(train_preds) self.final_model.fit(X_final, y) return self def predict(self, X_list): test_preds = [] for idx, X in enumerate(X_list): test_preds.append(self.base_models_[idx].predict(X)) X_final = np.hstack(test_preds) return self.final_model.predict(X_final) # 使用示例 stacking_reg = MultiOutputStackingRegressor( base_models=[RandomForestRegressor(), RandomForestRegressor()], final_model=RandomForestRegressor() ) stacking_reg.fit([X1_train, X2_train], y_train) y_pred = stacking_reg.predict([X1_test, X2_test])
这个自定义类完全匹配你的需求:既保留了可独立研究的基础模型,又通过单个多输出最终模型完成堆叠预测,避免了MultiOutputRegressor的参数冗余问题。
内容的提问来源于stack exchange,提问作者majpark

