Stacking回归估计器初始化异常:多城市模型预测性能问题
解决多城市分区建模中模型被覆盖的问题
问题诊断
你遇到的核心问题是模型组件共享导致的状态覆盖:
- 你的
regressor工厂函数中,scaler是全局变量(代码未在函数内定义),所有城市的模型共享同一个缩放器实例。后续城市拟合时会覆盖缩放器的拟合状态,之前城市的模型预测时会使用错误的缩放参数,导致结果极差。 - 若
prem_unit等其他转换器组件是全局实例,也会出现类似的状态共享问题。
修复方案
1. 确保所有转换器在工厂函数内实例化
修改regressor函数,将scaler和所有需要的转换器移到函数内部创建,保证每次调用工厂函数都生成全新的组件实例:
def regressor(btr_list, silly_amenities, numeric_cols, model='random_forest', one_model=False): from sklearn.preprocessing import FunctionTransformer, PolynomialFeatures, StandardScaler from sklearn.impute import SimpleImputer from sklearn.preprocessing import OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline from sklearn.model_selection import RandomizedSearchCV from sklearn.ensemble import RandomForestRegressor from sklearn.linear_model import Ridge import numpy as np zip_transformer = FunctionTransformer(zipcode_cleaner) # ... 其他函数转换器 # 每次调用工厂函数时创建新的scaler实例 scaler = StandardScaler() features = ColumnTransformer([ ('zip transformer', Pipeline([ ('fill gaps of Zip', SimpleImputer(strategy='most_frequent')), ('zipper', zip_transformer), ('ohe zip', OneHotEncoder(handle_unknown='ignore')) ]), ['Zip']), # 确保prem_unit中的转换器也为每次新建实例,替换为你的实际逻辑 ('prem_unit', Pipeline([('your_step', YourTransformer())]), ['your_cols']), # ... 其他ColumnTransformer步骤 ]) if model == 'random_forest': param_grid = {'max_depth': range(5, 300, 20), 'max_features': range(2, 20, 5), 'min_samples_leaf': range(1, 15)} gs = RandomizedSearchCV(RandomForestRegressor(n_estimators=100), param_grid, cv=5, n_jobs=-1, verbose=1, n_iter=20) elif model == 'ridge': param_grid_ridge = {'alpha': np.logspace(-3, 3, num=30)} gs = RandomizedSearchCV(Ridge(), param_grid_ridge, cv=5, n_jobs=-1, verbose=1, n_iter=20) else: print('Error. Model selected is not a defined model') return None est = Pipeline([ ('features', features), ('scaling', scaler), ('regressor', gs) ]) return est
2. 验证组件独立性
在Stacking回归器的fit循环中添加打印语句,确认每个模型的核心组件是独立实例:
def fit(self, X, y): cnt = 0 groups = X[self.grouper].unique() for subj in groups: cnt += 1 print(f'{subj} ({cnt} of {len(groups)})') ind = (X[self.grouper]==subj) X_subj = X[ind] y_subj = y[ind] self.estimators[subj] = self.estimator_factory() # 打印scaler的内存地址,确认每个模型的scaler实例不同 print(f"Scaler instance for {subj}: {id(self.estimators[subj].named_steps['scaling'])}") self.estimators[subj].fit(X_subj, y_subj) clear_output(wait=True) return self
额外检查点
- 确认
zipcode_cleaner等自定义函数无全局状态或副作用,避免干扰不同城市的数据处理。 - 检查
self.estimators字典的赋值逻辑,确保每个城市的模型条目独立存储,未被意外覆盖。
内容的提问来源于stack exchange,提问作者Jeffrey Ober
相关产品推荐
相关产品推荐

