如何在Python中对sm.GLM广义线性回归模型执行交叉验证
报错根源
你传给cross_val_score的glm_model是调用fit()后返回的GLMResultsWrapper训练结果对象,不是可重复训练的模型实例,且statsmodels原生模型不符合sklearn的estimator接口规范,因此触发类型错误。
另外你现有代码还存在两个可修复问题:
- 拆分数据集时调用的
X、Y未提前赋值,你之前定义的特征和标签变量为exog、endog - 评估指标参数写法错误,负均方误差的正确参数值为
neg_mean_squared_error,中间为下划线而非空格
解决方案1:手动实现K折交叉验证(最灵活,无额外适配成本)
直接通过KFold拆分循环训练验证,代码示例如下:
import pandas as pd import statsmodels.api as sm import numpy as np from sklearn.model_selection import train_test_split, KFold from sklearn.metrics import mean_squared_error Test = pd.read_csv(r'D:\myfile.csv') y = Test['Y'] X = Test[['log_X1', 'log_A', 'log_B']] # 拆分训练测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30, random_state=1) # 10折交叉验证 crossvalidation = KFold(n_splits=10, shuffle=True, random_state=1) scores = [] for train_idx, val_idx in crossvalidation.split(X_train): # 取当前折的训练/验证数据 X_tr, X_val = X_train.iloc[train_idx], X_train.iloc[val_idx] y_tr, y_val = y_train.iloc[train_idx], y_train.iloc[val_idx] # 初始化并训练模型,family可根据需求替换为Gamma等分布 glm = sm.GLM(y_tr, X_tr, family=sm.families.Gaussian(link=sm.families.links.log())) glm_res = glm.fit() # 验证集预测并计算负均方误差,和sklearn的scoring逻辑对齐 y_pred = glm_res.predict(X_val) neg_mse = -mean_squared_error(y_val, y_pred) scores.append(neg_mse) # 输出交叉验证结果 print(f"各折负均方误差: {scores}") print(f"平均负均方误差: {np.mean(scores)}")
解决方案2:封装为sklearn兼容接口(可直接调用cross_val_score)
如果希望复用sklearn的交叉验证、网格搜索等工具,可以将sm.GLM封装为符合sklearn estimator规范的类:
import pandas as pd import statsmodels.api as sm from sklearn.base import BaseEstimator, RegressorMixin from sklearn.model_selection import train_test_split, cross_val_score, KFold # 自定义封装类 class SMGLMRegressor(BaseEstimator, RegressorMixin): def __init__(self, family): self.family = family self._model = None self._fit_res = None def fit(self, X, y): self._model = sm.GLM(y, X, family=self.family) self._fit_res = self._model.fit() return self def predict(self, X): return self._fit_res.predict(X) # 数据读取与拆分 Test = pd.read_csv(r'D:\myfile.csv') y = Test['Y'] X = Test[['log_X1', 'log_A', 'log_B']] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30, random_state=1) # 初始化包装后的模型,family可替换为Gamma等 glm_est = SMGLMRegressor(family=sm.families.Gaussian(link=sm.families.links.log())) crossvalidation = KFold(n_splits=10, shuffle=True, random_state=1) # 直接调用cross_val_score scores = cross_val_score(glm_est, X_train, y_train, scoring="neg_mean_squared_error", cv=crossvalidation) print(f"交叉验证得分: {scores}") print(f"平均得分: {scores.mean()}")
内容的提问来源于stack exchange,提问作者g123456k
相关产品推荐
相关产品推荐

