Statsmodels GLM拟合报错:权重含NaN/inf 默认估计方法失效
问题描述
使用Statsmodels构建泊松分布广义线性模型时触发如下报错:ValueError: NaN, inf or invalid value detected in weights, estimation infeasible.
触发报错的实现代码:
frequency_poisson_model_var_weights = sm.GLM( endog=train_labels, exog=train_features.astype(float), family=sm.families.Poisson(), var_weights=train_exposures ) frequency_poisson_results_var_weights = frequency_poisson_model_var_weights.fit()
已完成的测试:
- 将
fit()方法的求解器改为'lbfgs'时模型可正常拟合,但业务要求必须使用默认求解器 - 移除
var_weights参数后问题仍然存在
报错核心回溯信息:
1209 self.weights = (self.iweights * self.n_trials *
1210 self.family.weights(mu))
1211 wlsendog = (lin_pred + self.family.link.deriv(mu) * (self.endog-mu)
1212 - self._offset_exposure)
-> 1213 wls_mod = reg_tools._MinimalWLS(wlsendog, wlsexog,
1214 self.weights, check_endog=True,
1215 check_weights=True)
1216 wls_results = wls_mod.fit(method=wls_method)
1217 lin_pred = np.dot(self.exog, wls_results.params)File ~/wd/venv/lib/python3.8/site-packages/statsmodels/regression/_tools.py:48, in _MinimalWLS.init(self, endog, exog, weights, check_endog, check_weights)
46 if check_weights:
47 if not np.all(np.isfinite(w_half)):
---> 48 raise ValueError(self.msg.format('weights'))
50 if check_endog:
51 if not np.all(np.isfinite(endog)):ValueError: NaN, inf or invalid value detected in weights, estimation infeasible.
排查与解决方法
GLM默认求解器是IRLS(迭代重加权最小二乘),和lbfgs这类带步长回溯的梯度求解器不同,IRLS每步迭代默认走全步长,只要迭代过程中计算出的WLS权重出现非有限值就会直接中断,按以下优先级排查即可:
- 第一步先校验输入数据合法性
不要只检查原始输入有没有空值,重点确认三类约束:- 泊松分布要求因变量
train_labels必须是非负数值,不能存在负数、无穷值,执行print((train_labels < 0).sum(), np.isinf(train_labels).sum(), train_labels.isna().sum())校验 - 自变量不能存在严重多重共线性(比如独热编码未丢弃参考列导致虚拟变量陷阱、两个特征完全线性相关)、不能存在全0/全常数列,这类问题会直接导致迭代过程参数估计异常
- 若使用
var_weights,权重列必须全部为严格大于0的有限值,不能出现0或负数,否则会触发权重计算除零错误
- 泊松分布要求因变量
- 第二步手动指定合理初始参数,避免初始步越界
IRLS默认初始值在特征尺度差异大时,很容易在第一步算出超出泊松分布有效域的mu值,手动传入基于因变量均值生成的初始参数即可:# 基于因变量均值生成泊松log链接下的初始参数 init_mu = np.clip(train_labels.mean(), 1e-6, None) init_params = np.zeros(train_features.shape[1]) init_params[0] = np.log(init_mu) # 传入初始参数拟合 frequency_poisson_results_var_weights = frequency_poisson_model_var_weights.fit(start_params=init_params) - 第三步调整迭代控制参数,解决发散问题
打开迭代日志观察偏差变化,如果迭代到某一步偏差突然飙升,说明步长过大导致发散,调整步长与迭代上限即可:frequency_poisson_results_var_weights = frequency_poisson_model_var_weights.fit( maxiter=200, tol=1e-8, disp=True, # 打印每步迭代偏差,定位发散节点 step_factor=0.5 # 将单步步长砍半,避免迭代跑出有效域 ) - 第四步做特征尺度标准化
如果连续特征值域差异超过3个数量级(比如一个特征值域0-1,另一个0-10000),先对连续特征做Z-score标准化再拟合,避免尺度差异导致的迭代不稳定。 - 第五步处理完美分离问题
如果存在某个分类特征的某个水平对应的因变量全为0、或全为极大值,会出现完美分离问题,导致迭代中参数趋向无穷大、mu变为inf触发报错。这类情况先将样本量低于总样本1%的分类水平合并,若仍存在问题可改用带L2正则的拟合方法:# L2正则化拟合,解决完美分离导致的参数发散 frequency_poisson_results_var_weights = frequency_poisson_model_var_weights.fit_regularized(alpha=0.01, L1_wt=0)
内容的提问来源于stack exchange,提问作者Tal Zig

