Sklearn逻辑回归全预测0问题:车贷违约预测异常求助
解决Logistic Regression测试集全预测0的问题
这种情况我之前碰到过好多次——明明训练集里有12%的违约样本(标记为1),但模型在测试集上却全输出0,核心原因大概率是类别不平衡加上模型默认阈值的限制,不过咱们先从数据层面排查起,再逐步解决模型问题。
一、先排查数据层面的潜在问题
- 检查测试集的类别分布:先确认测试集里是不是真的有正样本(1)?会不会是划分训练/测试集的时候,正样本几乎全被分到了训练集里?跑一行代码看看:
如果测试集里1的占比极低(比如不到1%),那模型全预测0也不奇怪,这时候得重新划分数据集(比如用print(y_test.value_counts(normalize=True))stratify=y参数保证分层抽样)。 - 验证特征一致性:训练集和测试集的特征分布有没有漂移?比如某个关键特征(比如月还款额/收入比)在测试集里的取值和训练集完全脱节?可以用直方图对比,或者用KS检验来量化差异:
如果p值小于0.05,说明该特征在两个数据集里分布显著不同,得先处理这个问题(比如重新清洗数据)。from scipy.stats import ks_2samp for col in X_train.columns: stat, p_val = ks_2samp(X_train[col], X_test[col]) print(f"特征{col}: KS统计量={stat:.3f}, p值={p_val:.3f}") - 确认预处理流程:Logistic Regression对特征尺度敏感,你是不是在训练集上做了标准化/归一化,却忘了用同样的转换器处理测试集?比如:
如果测试集单独fit了scaler,特征尺度会和训练集不一致,模型预测就会出错。# 正确做法:训练集fit,测试集transform scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # 这里不要fit!
二、核心解决方案:处理类别不平衡与调整阈值
训练集12%的正样本属于轻度类别不平衡,而Sklearn的Logistic Regression默认用0.5作为分类阈值——只有当模型预测的违约概率大于0.5时,才会输出1。但不平衡数据下,模型为了追求整体准确率,会偏向预测多数类(0),因为错判少数类的代价被默认忽略了。
这里有几个有效的解决办法:
- 手动调整分类阈值:先拿到模型对测试集的预测概率,然后降低阈值来捕捉更多正样本。比如:
你可以画个概率直方图,找一个能平衡精准率和召回率的阈值。# 获取所有样本的违约概率(第二列是正类概率) y_proba = model.predict_proba(X_test)[:, 1] # 把阈值从0.5降到0.2,你可以根据实际情况调整 y_pred = (y_proba > 0.2).astype(int) # 用混淆矩阵看看效果 from sklearn.metrics import confusion_matrix print(confusion_matrix(y_test, y_pred)) - 给模型加类别权重:初始化模型时加上
class_weight='balanced',让模型自动给少数类更高的权重,减少对多数类的偏向:
这个参数会让模型更关注少数类的错判,而不是只盯着整体准确率。from sklearn.linear_model import LogisticRegression model = LogisticRegression(class_weight='balanced', max_iter=1000) model.fit(X_train_scaled, y_train) - 训练集重采样:对训练集的少数类(1)做过采样,或者对多数类(0)做欠采样,甚至用SMOTE合成少数类样本。注意:重采样只在训练集上做,绝对不能碰测试集,否则会导致评估结果失真。
三、模型本身的微调
- 调整正则化强度:Logistic Regression默认用L2正则化,如果
C值太小(正则化太强),模型会过于保守,倾向于输出0。可以尝试调大C值(比如C=10或C=100),减少正则化的约束:model = LogisticRegression(class_weight='balanced', C=10, max_iter=1000) - 分析特征重要性:看看模型认为哪些特征是关键的,有没有可能和违约相关的特征在测试集里没有区分度?可以用
model.coef_查看特征系数,或者用排列重要性来量化:
如果所有和违约相关的特征重要性都极低,那可能得重新筛选特征了。from sklearn.inspection import permutation_importance result = permutation_importance(model, X_test_scaled, y_test, n_repeats=10, random_state=42) for i in result.importances_mean.argsort()[::-1]: print(f"{X_train.columns[i]}: {result.importances_mean[i]:.3f}")
内容的提问来源于stack exchange,提问作者Sebastian
相关产品推荐
相关产品推荐

