零膨胀泊松/负二项回归MAE计算报错及模型不收敛问题解决
零膨胀回归:维度不匹配与模型收敛问题解决方案
一、维度不匹配问题的根本解决方法
直接拆分原始数据集后用dmatrices分别处理训练/测试集,容易出现特征维度不一致(比如训练集有某类别哑变量,测试集没有),导致维度不匹配错误。正确流程是先统一生成全量设计矩阵,再拆分训练测试集:
import statsmodels.api as sm import pandas as pd from sklearn.model_selection import train_test_split # 定义模型公式 formula = "目标变量 ~ 特征1 + 特征2 + 特征3" # 先对全量数据生成设计矩阵和目标向量,确保特征维度统一 y_full, X_full = sm.dmatrices(formula, data=你的数据集, return_type='dataframe') # 再拆分训练测试集 X_train, X_test, y_train, y_test = train_test_split(X_full, y_full, test_size=0.2, random_state=42)
二、模型不收敛的排查与解决策略
模型不收敛通常和数据特性、模型设置、特征质量有关,按以下步骤逐一排查:
1. 验证数据是否适合零膨胀模型
零膨胀模型只适用于**零值占比高(通常>15%)+ 过度离散(方差远大于均值)**的数据,先做基础统计:
# 统计零值占比 zero_ratio = len(你的数据集[你的数据集['目标变量'] == 0]) / len(你的数据集) print(f"零值占比: {zero_ratio:.2f}") # 统计均值和方差 mean_y = 你的数据集['目标变量'].mean() var_y = 你的数据集['目标变量'].var() print(f"目标变量均值: {mean_y:.2f}, 方差: {var_y:.2f}")
- 如果方差接近均值:改用普通泊松回归即可,零膨胀模型没必要
- 如果零值占比<10%:零膨胀模型的结构会导致参数估计不稳定,建议放弃或合并稀疏类别
2. 手动指定模型初始参数
statsmodels默认的初始参数可能无法引导模型收敛,先拟合普通模型获取合理初始值:
import numpy as np # 先拟合普通泊松回归,用其参数作为ZIP模型计数部分的初始值 poisson_base = sm.Poisson(y_train, X_train).fit() # 拟合ZIP模型,指定初始参数(计数部分参数+膨胀部分初始值0) zip_model = sm.ZeroInflatedPoisson( y_train, X_train, inflation='logit' ).fit(start_params=np.append(poisson_base.params, 0)) # 零膨胀负二项回归同理,先用普通负二项回归获取初始值 nb_base = sm.NegativeBinomial(y_train, X_train).fit() zinb_model = sm.ZeroInflatedNegativeBinomialP( y_train, X_train, inflation='logit' ).fit(start_params=np.append(nb_base.params, 0))
3. 优化特征质量
- 消除多重共线性:用相关系数矩阵检查高度相关的特征(相关系数>0.7),删除其中一个
corr_matrix = 你的数据集.corr() # 筛选高度相关特征 high_corr = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(bool)) high_corr_features = [column for column in high_corr.columns if any(high_corr[column].abs() > 0.7)] # 删除高相关特征 你的数据集 = 你的数据集.drop(high_corr_features, axis=1) - 标准化数值特征:当特征尺度差异过大时,会影响优化器收敛,对数值特征做标准化:
from sklearn.preprocessing import StandardScaler # 只对数值特征标准化 num_features = 你的数据集.select_dtypes(include=['int64', 'float64']).columns.drop('目标变量') scaler = StandardScaler() 你的数据集[num_features] = scaler.fit_transform(你的数据集[num_features])
4. 调整优化器参数
默认优化器可能无法处理复杂数据,尝试更换优化器或增加迭代次数:
# 更换为牛顿共轭梯度法,增加迭代次数 zip_model = sm.ZeroInflatedPoisson( y_train, X_train, inflation='logit' ).fit(method='ncg', maxiter=1000, disp=True)
可选优化器:'bfgs'、'powell'、'lbfgs',disp=True可以查看迭代过程,帮助判断收敛情况。
5. 处理异常值
目标变量或特征中的极端值会干扰参数估计,用箱线图识别并处理:
import matplotlib.pyplot as plt # 查看目标变量箱线图 plt.boxplot(你的数据集['目标变量']) plt.show() # 删除超过3倍标准差的异常值 y_mean = 你的数据集['目标变量'].mean() y_std = 你的数据集['目标变量'].std() 你的数据集 = 你的数据集[np.abs(你的数据集['目标变量'] - y_mean) <= 3 * y_std]
三、正确计算MAE的注意事项
零膨胀模型的预测值是零值概率与计数均值的加权结果,直接用predict()方法指定which='mean'即可得到最终预测值,再计算MAE:
from sklearn.metrics import mean_absolute_error # ZIP模型预测 zip_pred = zip_model.predict(X_test, which='mean') # 计算MAE zip_mae = mean_absolute_error(y_test, zip_pred) # 零膨胀负二项回归同理 zinb_pred = zinb_model.predict(X_test, which='mean') zinb_mae = mean_absolute_error(y_test, zinb_pred)
内容的提问来源于stack exchange,提问作者Student coding
相关产品推荐
相关产品推荐

