【机器学习实战】Python逻辑回归模型优化:贷款违约预测的精准度提升策略
1. 为什么选择逻辑回归做贷款违约预测
在金融风控领域,预测贷款违约是个典型的二分类问题。你可能要问:为什么不用更复杂的模型?我刚开始做风控模型时也有这个疑问,直到踩过几次坑才明白逻辑回归的独特优势。
逻辑回归最大的特点是可解释性强。银行需要向监管部门和客户解释为什么拒绝贷款申请,而逻辑回归的系数可以直接解释每个特征对违约概率的影响程度。比如我们常看到"收入每增加1万元,违约概率降低2.3%"这样的结论,就是来自逻辑回归的输出。
另一个优势是训练速度快。相比随机森林、XGBoost等算法,逻辑回归在特征工程完成后,训练时间通常只需几秒钟。这在需要频繁更新模型的线上风控系统中特别重要。
不过逻辑回归也有软肋。它对特征工程的要求极高,数据中的非线性关系和特征交互需要手动处理。我在某次项目中发现,经过精心调优的逻辑回归,准确率可以接近XGBoost的90%,但特征工程花费的时间却是后者的3倍。
2. 数据预处理的关键步骤
2.1 处理缺失值的实战技巧
银行数据最常见的坑就是缺失值。我见过一个真实案例,某客户的"月收入"字段为空,但"职业"显示是退休人员。这时如果简单用平均值填充,就会严重失真。
更合理的做法是:
# 根据职业分组填充
def fill_income(df):
retirees = df[df['occupation'] == '退休']
df.loc[retirees.index, 'income'] = retirees['income'].fillna(pension_amount)
others = df[df['occupation'] != '退休']
df.loc[others.index, 'income'] = others['income'].fillna(others['income'].median())
return df
2.2 特征分箱的艺术
连续变量分箱能显著提升模型稳定性。我曾对比过等宽分箱和最优分箱的效果:
| 分箱方法 | KS值 | AUC |
|---|---|---|
| 等宽分箱 | 0.32 | 0.72 |
| 最优分箱 | 0.41 | 0.78 |
最优分箱的Python实现:
from scipy.stats import stats
def optimal_binning(df, col, target, n_bins=5):
df[col+'_bin'] = pd.qcut(df[col], q=n_bins, duplicates='drop')
return df
3. 解决样本不平衡的三种武器
银行数据通常违约样本不足5%,直接训练会导致模型偏向正常样本。我常用的解决方案有:
- 调整类别权重(适合中小数据集)
model = LogisticRegression(class_weight='balanced')
- SMOTE过采样(效果最好但可能过拟合)
from imblearn.over_sampling import SMOTE
sm = SMOTE(random_state=42)
X_res, y_res = sm.fit_resample(X_train, y_train)
- 欠采样+集成(适合超大数据集)
from imblearn.ensemble import BalancedRandomForestClassifier
brf = BalancedRandomForestClassifier(n_estimators=100)
实测效果对比:
| 方法 | 召回率 | 精确率 | 训练时间 |
|---|---|---|---|
| 原始数据 | 0.12 | 0.45 | 1.2s |
| 类别权重 | 0.63 | 0.38 | 1.5s |
| SMOTE | 0.71 | 0.41 | 3.8s |
| 欠采样集成 | 0.68 | 0.52 | 15.2s |
4. 特征工程的进阶技巧
4.1 构建业务特征
好的风控模型需要结合金融常识。这几个特征在我项目中屡试不爽:
# 负债收入比
df['debt_ratio'] = df['total_debt'] / (df['income'] + 1e-6)
# 信用卡利用率
df['card_util'] = df['card_balance'] / df['card_limit']
# 近期查询次数
df['recent_inquiries'] = df['inq_last_6mths'] / 6
4.2 交互特征挖掘
逻辑回归无法自动捕捉特征交互,需要手动创建:
# 年龄与收入的交互
df['age_income'] = df['age'] * df['income']
# 使用PolynomialFeatures
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, interaction_only=True)
X_poly = poly.fit_transform(X[['age', 'income']])
5. 超参数调优实战
5.1 正则化策略选择
L1正则化能自动做特征选择,但可能丢失重要特征。我的经验法则是:
- 当特征>100时用L1
- 特征<100时用L2
- 重要特征已知时用ElasticNet
# L1正则化示例
model = LogisticRegression(penalty='l1', solver='liblinear', C=0.1)
5.2 网格搜索的加速技巧
传统网格搜索耗时太长,我推荐这两种优化方法:
- 随机搜索:在更大范围采样
from sklearn.model_selection import RandomizedSearchCV
param_dist = {'C': stats.uniform(0.01, 10)}
search = RandomizedSearchCV(model, param_dist, n_iter=50)
- 贝叶斯优化:更智能的参数搜索
from skopt import BayesSearchCV
search = BayesSearchCV(
model,
{'C': (0.01, 10.0, 'log-uniform')},
n_iter=32
)
6. 模型评估的常见误区
准确率在风控场景几乎没用。我主要看这三个指标:
- KS统计量:衡量模型区分度,>0.3才算合格
from sklearn.metrics import roc_curve
fpr, tpr, _ = roc_curve(y_test, y_pred)
ks = max(tpr - fpr)
- PSI:监控模型稳定性,<0.1说明稳定
def calculate_psi(expected, actual):
# PSI计算实现
...
- Lift值:前10%客户的坏样本捕获率
在实际项目中,我还会做拒绝推断(Reject Inference),用模型预测被拒客户的潜在违约率,这对缓解样本偏差特别重要。
7. 模型部署的注意事项
将模型部署到生产环境时,这几个坑我几乎每次都遇到:
-
特征一致性:训练和线上特征必须完全一致。有次因为线上环境少做了一个分箱转换,导致预测结果完全错误。
-
实时性要求:在线风控通常要在200ms内返回结果,需要用C++重写预测逻辑。
-
模型监控:建立完善的监控看板,我通常会跟踪:
- 每日预测分布变化
- 特征PSI波动
- 实时预测耗时
-
灰度发布:新模型先放5%流量,观察一周没问题再全量。
在银行实际业务中,模型效果提升0.5%的AUC,可能就意味着每年减少数百万坏账损失。记得有次通过优化分箱边界,让KS值从0.38提升到0.42,直接帮风控团队多拦截了23%的高风险客户。
更多推荐
所有评论(0)