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.320.72
最优分箱0.410.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%,直接训练会导致模型偏向正常样本。我常用的解决方案有:

  1. 调整类别权重(适合中小数据集)
model = LogisticRegression(class_weight='balanced')
  1. SMOTE过采样(效果最好但可能过拟合)
from imblearn.over_sampling import SMOTE
sm = SMOTE(random_state=42)
X_res, y_res = sm.fit_resample(X_train, y_train)
  1. 欠采样+集成(适合超大数据集)
from imblearn.ensemble import BalancedRandomForestClassifier
brf = BalancedRandomForestClassifier(n_estimators=100)

实测效果对比:

方法召回率精确率训练时间
原始数据0.120.451.2s
类别权重0.630.381.5s
SMOTE0.710.413.8s
欠采样集成0.680.5215.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 网格搜索的加速技巧

传统网格搜索耗时太长,我推荐这两种优化方法:

  1. 随机搜索:在更大范围采样
from sklearn.model_selection import RandomizedSearchCV
param_dist = {'C': stats.uniform(0.01, 10)}
search = RandomizedSearchCV(model, param_dist, n_iter=50)
  1. 贝叶斯优化:更智能的参数搜索
from skopt import BayesSearchCV
search = BayesSearchCV(
    model,
    {'C': (0.01, 10.0, 'log-uniform')},
    n_iter=32
)

6. 模型评估的常见误区

准确率在风控场景几乎没用。我主要看这三个指标:

  1. KS统计量:衡量模型区分度,>0.3才算合格
from sklearn.metrics import roc_curve
fpr, tpr, _ = roc_curve(y_test, y_pred)
ks = max(tpr - fpr)
  1. PSI:监控模型稳定性,<0.1说明稳定
def calculate_psi(expected, actual):
    # PSI计算实现
    ...
  1. Lift值:前10%客户的坏样本捕获率

在实际项目中,我还会做拒绝推断(Reject Inference),用模型预测被拒客户的潜在违约率,这对缓解样本偏差特别重要。

7. 模型部署的注意事项

将模型部署到生产环境时,这几个坑我几乎每次都遇到:

  1. 特征一致性:训练和线上特征必须完全一致。有次因为线上环境少做了一个分箱转换,导致预测结果完全错误。

  2. 实时性要求:在线风控通常要在200ms内返回结果,需要用C++重写预测逻辑。

  3. 模型监控:建立完善的监控看板,我通常会跟踪:

    • 每日预测分布变化
    • 特征PSI波动
    • 实时预测耗时
  4. 灰度发布:新模型先放5%流量,观察一周没问题再全量。

在银行实际业务中,模型效果提升0.5%的AUC,可能就意味着每年减少数百万坏账损失。记得有次通过优化分箱边界,让KS值从0.38提升到0.42,直接帮风控团队多拦截了23%的高风险客户。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐