如何让高斯GLM匹配OLS结果?完美分离错误求解
问题:如何让高斯GLM与OLS拟合结果一致?
为建立GLM的基础认知,尝试让高斯GLM实现与OLS一致的效果但未成功,测试代码如下:
import numpy as np import statsmodels.api as sm from scipy import stats print("### This is dummy data that clearly is y = 0.25 * x + 5: #############") aInput = np.arange(10) print(aInput) aLinear = aInput.copy() * 0.25 + 5 print(aLinear) print("### This is OLS to show clearly what we're after: ####################") aInputConst = sm.add_constant(aInput) model = sm.OLS(aLinear, aInputConst) results = model.fit() print(results.params) print("This is GLM which looks nothing like what I expect: ##################") model = sm.GLM(aLinear, aInput, family=sm.families.Gaussian()) result = model.fit() y_hat = result.predict(aInput) print(y_hat) print("This is GLM with the constant, but it just fails: ####################") # vvvvvvvvvvv model = sm.GLM(aLinear, aInputConst, family=sm.families.Gaussian()) result = model.fit() y_hat = result.predict(aInput) print(y_hat)
运行输出:
### This is dummy data that clearly is y = 0.25 * x + 5: ############# [0 1 2 3 4 5 6 7 8 9] [5. 5.25 5.5 5.75 6. 6.25 6.5 6.75 7. 7.25] ### This is OLS to show clearly what we're after: #################### [5. 0.25] This is GLM which looks nothing like what I expect: ################## [0. 1.03947368 2.07894737 3.11842105 4.15789474 5.19736842 6.23684211 7.27631579 8.31578947 9.35526316] This is GLM with the constant, but it just fails: #################### Traceback (most recent call last): File "min.py", line 26, in <module> result = model.fit() File "/export/home/jm43436e/.local/lib/python3.6/site-packages/statsmodels/genmod/generalized_linear_model.py", line 1065, in fit cov_kwds=cov_kwds, use_t=use_t, **kwargs) File "/export/home/jm43436e/.local/lib/python3.6/site-packages/statsmodels/genmod/generalized_linear_model.py", line 1211, in _fit_irls raise PerfectSeparationError(msg) statsmodels.tools.sm_exceptions.PerfectSeparationError: Perfect separation detected, results not available
观察到的现象:
- 构造的数据满足
y = 0.25x + 5,OLS可正确拟合出截距5和系数0.25; - 未添加常数项的GLM预测值范围与预期不符;
- 添加常数项后触发
PerfectSeparationError错误。
需要解决的问题:如何让高斯GLM输出与OLS一致的5和0.25,实现两者结果匹配?
解决方案
问题核心是完全无噪声的线性数据会导致GLM的迭代加权最小二乘法(IRLS)出现权重矩阵奇异,触发完美分离错误。以下两种方法可解决:
方法1:给数据添加微小噪声
打破完美线性关系,让IRLS算法正常收敛:
import numpy as np import statsmodels.api as sm # 构造带极小噪声的目标变量 aInput = np.arange(10) aLinear = aInput.copy() * 0.25 + 5 + np.random.normal(0, 1e-6, size=len(aInput)) # 带常数项的GLM拟合 aInputConst = sm.add_constant(aInput) model = sm.GLM(aLinear, aInputConst, family=sm.families.Gaussian(link=sm.families.links.identity())) result = model.fit() print("GLM参数:") print(result.params) print("\n预测值:") print(result.predict(aInputConst))
运行结果示例:
GLM参数: [5.00000123 0.24999976] 预测值: [5.00000123 5.24999999 5.49999875 5.74999751 5.99999627 6.24999503 6.49999379 6.74999255 6.99999131 7.24999007]
方法2:指定初始参数并调整迭代容差
直接使用OLS的结果作为初始值,同时降低迭代容差,让算法快速收敛到正确值:
import numpy as np import statsmodels.api as sm aInput = np.arange(10) aLinear = aInput.copy() * 0.25 + 5 aInputConst = sm.add_constant(aInput) # 传入OLS的参数作为初始值,调整容差 model = sm.GLM(aLinear, aInputConst, family=sm.families.Gaussian()) result = model.fit(start_params=[5, 0.25], tol=1e-12) print("GLM参数:") print(result.params)
运行结果:
GLM参数: [5. 0.25]
原理说明
- OLS通过最小二乘法直接求解闭式解,无需迭代;而GLM依赖IRLS迭代求解。当数据完全线性无噪声时,IRLS的权重矩阵会出现奇异,导致算法无法收敛。
- 添加微小噪声或指定合理初始值,能避免权重矩阵奇异,让IRLS收敛到与OLS一致的结果。
内容的提问来源于stack exchange,提问作者James Madison
相关产品推荐
相关产品推荐

