statsmodels Logit模型get_margeff()返回全NA值问题求助
问题描述
使用statsmodels构建Logit模型,模型拟合结果正常,但调用get_margeff()获取边际效应时,返回结果中所有统计量(标准误、z值、P值等)均为NA。尝试为连续变量添加count=True、为哑变量添加dummy=True参数后,仅能得到dy/dx值,仍无法获取其他统计量,同时触发4条RuntimeWarning(包含指数溢出、无效值计算等)。
相关代码
Xtrain = df_3[["USGoal","videolink","min_USPledge","max_USPledge","npledges","nbackers","ProjectDuration","Staff_pick1" ,"art","comics","crafts","dance","design","fashion","film & video","food","games","journalism","music","photography","publishing" ,"theater","OC","EU","AS","SA","AF"]] ytrain = df_3[['Success']] Xtrain = Xtrain.astype(int) ytrain = ytrain.astype(int) Xtrain_with_constant = sm.add_constant(Xtrain) # 构建并拟合模型 log_reg = sm.Logit(ytrain, Xtrain_with_constant).fit(cov_type="hc0") # 计算边际效应 marginal_effects = log_reg.get_margeff() print(marginal_effects.summary())
边际效应输出(全NA)
Logit Marginal Effects ===================================== Dep. Variable: Success Method: dydx At: overall =================================================================================== dy/dx std err z P>|z| [0.025 0.975] ----------------------------------------------------------------------------------- USGoal nan nan nan nan nan nan videolink nan nan nan nan nan nan min_USPledge nan nan nan nan nan nan max_USPledge nan nan nan nan nan nan npledges nan nan nan nan nan nan nbackers nan nan nan nan nan nan ProjectDuration nan nan nan nan nan nan Staff_pick1 nan nan nan nan nan nan art nan nan nan nan nan nan comics nan nan nan nan nan nan crafts nan nan nan nan nan nan dance nan nan nan nan nan nan design nan nan nan nan nan nan fashion nan nan nan nan nan nan film & video nan nan nan nan nan nan food nan nan nan nan nan nan games nan nan nan nan nan nan journalism nan nan nan nan nan nan music nan nan nan nan nan nan photography nan nan nan nan nan nan publishing nan nan nan nan nan nan theater nan nan nan nan nan nan OC nan nan nan nan nan nan EU nan nan nan nan nan nan AS nan nan nan nan nan nan SA nan nan nan nan nan nan AF nan nan nan nan nan nan ===================================================================================
RuntimeWarning信息
RuntimeWarning: invalid value encountered in divide return np.exp(-X)/(1+np.exp(-X))**2 RuntimeWarning: invalid value encountered in square return np.exp(-X)/(1+np.exp(-X))**2 overflow encountered in exp return 1/(1+np.exp(-X)) RuntimeWarning: overflow encountered in exp return np.exp(-X)/(1+np.exp(-X))**2
原因分析
核心问题是数值溢出:当模型计算线性预测值Xβ的绝对值过大时,np.exp(-Xβ)会超出浮点数计算范围(比如Xβ极大时,-Xβ极小,exp后接近无穷大;反之则接近0),导致后续计算边际效应的导数项(np.exp(-X)/(1+np.exp(-X))**2)出现无效值,最终所有统计量变为NA。
你的自变量中存在取值范围极大的连续变量(如USGoal、min_USPledge、max_USPledge等金额类变量),是触发溢出的主要原因。
解决步骤
1. 标准化连续变量
对取值范围大的连续变量做Z-score标准化(减去均值除以标准差),缩小变量取值范围,避免线性预测值超出合理区间:
import pandas as pd from sklearn.preprocessing import StandardScaler import statsmodels.api as sm # 分离连续变量与分类变量 continuous_vars = ["USGoal", "min_USPledge", "max_USPledge", "npledges", "nbackers", "ProjectDuration"] categorical_vars = ["videolink", "Staff_pick1", "art", "comics", "crafts", "dance", "design", "fashion", "film & video", "food", "games", "journalism", "music", "photography", "publishing", "theater", "OC", "EU", "AS", "SA", "AF"] # 标准化连续变量 scaler = StandardScaler() X_cont_scaled = scaler.fit_transform(df_3[continuous_vars]) X_cont_scaled = pd.DataFrame(X_cont_scaled, columns=continuous_vars) # 合并分类变量(保持整数类型) X_categorical = df_3[categorical_vars].astype(int) X_processed = pd.concat([X_cont_scaled, X_categorical], axis=1) # 重构模型并拟合 X_with_const = sm.add_constant(X_processed) log_reg = sm.Logit(ytrain, X_with_const).fit(cov_type="hc0") # 计算边际效应 marginal_effects = log_reg.get_margeff() print(marginal_effects.summary())
2. 处理极端值
如果数据中存在异常大/小的极端值(比如某项目目标金额远超其他样本),可考虑剔除或截断这些值,进一步优化数值稳定性。
3. 调整边际效应计算参数
若标准化后仍有问题,可指定在自变量均值处计算边际效应(而非默认的全样本平均),减少极端样本的影响:
marginal_effects = log_reg.get_margeff(at='mean')
4. 验证线性预测值范围
手动检查线性预测值的范围,确认是否仍存在溢出风险:
linear_pred = log_reg.predict(X_with_const, linear=True) print(f"线性预测值范围:{linear_pred.min()} ~ {linear_pred.max()}")
若范围超过±20,说明仍需进一步调整变量缩放或剔除极端值。
预期效果
处理后RuntimeWarning会消失,边际效应的标准误、z值、P值等统计量将正常显示,dy/dx值也会保持合理的解释性。
内容的提问来源于stack exchange,提问作者Erdem

