计算倾向得分时LogisticRegression完全拟分离及模型指标差的解决方法
解决Logistic回归完全拟分离与模型表现不佳问题
问题描述
为计算倾向得分,计划用statsmodels的Logistic回归逐年估计截面二元响应模型,解释变量为企业特征(总资产、增长率、市净率、总负债/普通股权益),被解释变量为处理组标识(是否入选)。但估计结果出现完全拟分离(complete quasi-separation),且模型评估指标(McFadden's R²、AUC-ROC等)表现不佳。
已尝试logit_model.fit(method='bfgs')和FirthLogisticRegression,均未解决问题。
代码示例
import pandas as pd import statsmodels.api as sm from sklearn.metrics import roc_auc_score df = pd.read_excel("Posthoc/PSM_firms_combined.xlsx") X_year = df[df['Year'] == 2015][['Total Assets', 'Growth', 'Price to Book Value per Share', 'Total Debt to Common Equity']] y_year = df[df['Year'] == 2015]['Treatment'] logit_model = sm.Logit(y_year, X_year) results = logit_model.fit() print(results.summary()) # 计算卡方统计量 chi_squared = results.llr print("卡方统计量:", chi_squared) # 计算McFadden's R-squared log_likelihood_model = results.llf # 模型对数似然值 log_likelihood_null = results.llnull # 空模型对数似然值 mcfadden_r2 = 1 - (log_likelihood_model / log_likelihood_null) print("McFadden's R-squared:", mcfadden_r2) # 计算AUC-ROC y_pred_prob = results.predict(X_year) auc_roc = roc_auc_score(y_year, y_pred_prob) print("AUC-ROC:", auc_roc)
回归结果

解决方法
1. 定位数据分离根源
完全拟分离的核心是某个/多个解释变量能完美区分处理组和控制组,先排查:
- 对每个解释变量,按处理组分组统计分位数(最小值、中位数、最大值),看是否存在某变量在两组中完全无重叠区间。
- 若有分类变量,用交叉表分析其与处理组的关系,若某类别仅出现在单一组,就是分离来源。
2. 修正模型与变量处理
- 补加常数项:你的代码里没加截距项!Logistic回归必须包含常数项,否则模型设定错误,修改代码:
X_year = sm.add_constant(X_year) # 添加常数项 logit_model = sm.Logit(y_year, X_year) - 压缩极端值:对总资产这类规模变量取对数(
np.log(X_year['Total Assets']));对增长率、负债率用Winsorize截断上下1%的极端值(借助scipy.stats.mstats.winsorize)。 - 合并/删除极端样本:如果某变量存在极小样本分组(比如某资产规模区间只有处理组样本),合并到相邻组或直接删除该极端样本(注意避免样本偏差)。
3. 更换鲁棒性估计方法
- 正则化Logistic回归:给模型加L1/L2正则,解决分离问题同时防过拟合:
from statsmodels.discrete.discrete_model import Logit model = Logit(y_year, X_year) results = model.fit_regularized(method='l1', alpha=0.1) # alpha为正则强度,可调整 print(results.summary()) - 精确Logistic回归:完全拟分离场景下的可靠选择,用
lifelines库实现:from lifelines import ExactLogisticRegression model = ExactLogisticRegression() model.fit(X_year, y_year) print(model.summary()) - 调整Firth回归实现:用statsmodels官方的Firth回归模块(需确保版本足够新):
from statsmodels.discrete.firth_logit import FirthLogit model = FirthLogit(y_year, X_year) results = model.fit() print(results.summary())
4. 样本与模型替换
- 平衡样本权重:如果处理组和控制组样本量差距极大,给小样本组加权重,或先做粗匹配缩小样本范围。
- 改用机器学习模型:若Logistic回归始终表现差,试试XGBoost/LightGBM这类模型,对非线性关系和分离问题鲁棒性更强:
from xgboost import XGBClassifier xgb_model = XGBClassifier(objective='binary:logistic', use_label_encoder=False, eval_metric='logloss') xgb_model.fit(X_year, y_year) propensity_scores = xgb_model.predict_proba(X_year)[:, 1]
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

