前言:
如今你们对“逻辑回归的方程”大约比较讲究,同学们都想要学习一些“逻辑回归的方程”的相关文章。那么小编也在网络上汇集了一些关于“逻辑回归的方程””的相关内容,希望同学们能喜欢,各位老铁们快快来了解一下吧!1. 逻辑回归的评分映射逻辑
逻辑回归(Logistic Regression)是统计学习中的经典分类方法,是一种有监督的机器学习模型,属于广义线性模型的一种。主要用来解决二分类问题,也可以用来解决多分类问题。使用逻辑回归模型可以得到一个[0,1]区间的结果,在风控场景下可以理解为用户违约的概率,在进行评分卡建模时我们需要把违约的概率映射为用户的评分。业内主要采用一种比率缩放的评分映射方法。
比如:假设现在期望每个用户的基础分为650分,当这个用户非预期的概率是预期概率的两倍时,加50分,非预期概率是预期概率的4倍时加100分,反之则扣分。因此可以得出业内标准的评分映射逻辑:
其中score时映射后的评分输出,是样本非预期的概率,是样本预期的概率。接下来我们看看逻辑回归中,正负样本是怎么对应起来的。首先在二项逻辑回归模型中,正负样本的条件概率分布如下:
故我们可以得到如下的逻辑回归方程
由换地公式我们可知
因此我们可以最终得到我们的评分映射公式:
其中和可以由最终训练完的逻辑回归模型的coef_系数和intercept_得到。
2. 训练逻辑回归模型
我们以某互联网信贷平台的脱敏数据为例,简单展示基于逻辑回归模型构建评分卡的全过程。其数据字段信息如下:
字段名称
中文描述
obs_mth
申请日期所在月份的最后一天
bad_ind
好坏标识
uid
用户id
td_score
同盾分
jxl_score
聚信立分
mj_score
摩羯分
rh_score
人行征信分
zzc_score
中智诚分
zcx_score
中诚信分
person_info
个人信息
finance_info
金融信息
credit_info
信用信息
act_info
行为信息
通过观察这些字段我们可以知道,这个数据集是一部分依赖于该企业外部征信的评分,一部分是用户在平台上的基本信息的整合,因此这里简单跳过特征工程的环节,直接利用上述信息进行评分卡制作。
加载依赖包
# 依赖包加载import pandas as pdimport numpy as npfrom sklearn import metricsfrom sklearn.linear_model import LogisticRegressionimport math数据载入
# 数据导入data = pd.read_csv('Acard.txt')data.head()
数据预览结果如下图所示
数据基本信息探查
# 查看数据基本情况data.info()
<class 'pandas.core.frame.DataFrame'>RangeIndex: 95806 entries, 0 to 95805Data columns (total 13 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 obs_mth 95806 non-null object 1 bad_ind 95806 non-null float64 2 uid 95806 non-null object 3 td_score 95806 non-null float64 4 jxl_score 95806 non-null float64 5 mj_score 95806 non-null float64 6 rh_score 95806 non-null float64 7 zzc_score 95806 non-null float64 8 zcx_score 95806 non-null float64 9 person_info 95806 non-null float64 10 finance_info 95806 non-null float64 11 credit_info 95806 non-null float64 12 act_info 95806 non-null float64dtypes: float64(11), object(2)memory usage: 9.5+ MB查看数据特征项
# 申请日期所在月份的最后一天、# 好坏标识、用户id、同盾分、聚信立分、# mj_score, 人行征信分、中智诚分、中诚信分,# 个人信息、金融信息、信用信息、行为信息data.columns
Index(['obs_mth', 'bad_ind', 'uid', 'td_score', 'jxl_score', 'mj_score', 'rh_score', 'zzc_score', 'zcx_score', 'person_info', 'finance_info', 'credit_info', 'act_info'], dtype='object')数据特征变量汇总信息
# 查看离散变量的统计信息data.describe()
bad_ind td_score jxl_score mj_score rh_score zzc_score zcx_score person_info finance_info credit_info act_infocount 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000mean 0.018767 0.499739 0.499338 0.501640 0.498407 0.500627 0.499672 -0.078229 0.036763 0.063626 0.236197std 0.135702 0.288349 0.288850 0.288679 0.287797 0.289067 0.289137 0.156859 0.039687 0.143098 0.157132min 0.000000 0.000005 0.000013 0.000007 0.000005 0.000012 0.000010 -0.322581 0.023810 0.000000 0.07692325% 0.000000 0.250104 0.249045 0.250517 0.250115 0.249501 0.248318 -0.261014 0.023810 0.000000 0.07692350% 0.000000 0.500719 0.499795 0.503048 0.497466 0.501688 0.499130 -0.053718 0.023810 0.000000 0.20512875% 0.000000 0.747984 0.748646 0.752032 0.747188 0.750986 0.750683 0.078853 0.023810 0.060000 0.346154max 1.000000 0.999999 0.999985 0.999993 0.999986 0.999998 0.999987 0.078853 1.023810 1.000000 1.089744数据探查
# 查看数据重复情况data.duplicated().sum()
0
# 查看数据缺失情况data.isnull().sum()
obs_mth 0bad_ind 0uid 0td_score 0jxl_score 0mj_score 0rh_score 0zzc_score 0zcx_score 0person_info 0finance_info 0credit_info 0act_info 0dtype: int64
# 查看好坏样本的分布data.bad_ind.value_counts()
0.0 940081.0 1798Name: bad_ind, dtype: int64观察样本在时间上的分布
# 查看样本在月份上的分布data.groupby(data.obs_mth).agg({'obs_mth':np.size})
obs_mthobs_mth 2018-06-30 205652018-07-31 340302018-09-30 107092018-10-31 145272018-11-30 15975挑选训练样本和时间外样本(OOT)
# 选择'2018-11-30'之外的数据作为时间内样本,用于模型训练train = data[data.obs_mth != '2018-11-30'].reset_index().copy()# 选择'2018-11-30'的数据作为时间外样本,用于模型验证valid = data[data.obs_mth == '2018-11-30'].reset_index().copy()构建训练集和验证集
# 挑选特征feature_list = ['td_score', 'jxl_score', 'mj_score','rh_score', 'zzc_score', 'zcx_score', 'person_info', 'finance_info','credit_info', 'act_info']x_train = train[feature_list].copy()y_train = train['bad_ind'].copy()x_valid = valid[feature_list].copy()y_valid = valid['bad_ind'].copy()训练逻辑回归模型
# 构建并训练逻辑回归模型lr = LogisticRegression(C = 0.11, class_weight='balanced')lr.fit(x_train, y_train)# 在训练集上的评价指标y_pred_train = lr.predict_proba(x_train)[:, 1]fpr_lr_train,tpr_lr_train, _ = metrics.roc_curve(y_train, y_pred_train)ks_train = abs(fpr_lr_train - tpr_lr_train).max()print("the KS on train set is:", ks_train)# 在验证集上的评价指标y_pred_valid = lr.predict_proba(x_valid)[:, 1]fpr_lr_valid,tpr_lr_valid, _ = metrics.roc_curve(y_valid, y_pred_valid)ks_valid = abs(fpr_lr_valid - tpr_lr_valid).max()print("the KS on valid set is:", ks_valid)
the KS on train set is: 0.45180401329378495the KS on valid set is: 0.41464427841696455ROC曲线
# 训练集和验证集上的ROC对比from matplotlib import pyplot as pltplt.plot(fpr_lr_train, tpr_lr_train, label = 'LR_train')plt.plot(fpr_lr_valid, tpr_lr_valid, label = 'LR_valid')plt.plot([0,1], [0,1], 'k--')plt.xlabel('Flase positive rate')plt.ylabel('True positive rate')plt.title('ROC Curve')plt.legend(loc='best')plt.show()
通常我们使用ROC曲线(Receiver Operating Characteristic Curve)来衡量模型的整体区分度,以及通过ROC曲线的平稳度来推断模型的鲁棒性和泛化能力。
生成模型报告
通过分箱,分别对KS值,正负样本数、正负样本占比、捕获率等进行汇总,生成最终的模型报告。
# 生成模型报告model = lrrow_num, col_num = 0, 0bins = 20Y_predict = [s[1] for s in model.predict_proba(x_valid)]Y = y_validrows = Y.shape[0]lis = [(Y_predict[i], Y[i]) for i in range(rows)]ks_lis = sorted(lis, key=lambda x : x[0], reverse=True)bin_num = int(rows/bins + 1)good = sum([1 for (p,y) in ks_lis if y <= 0.5])bad = sum([1 for (p,y) in ks_lis if y > 0.5])good_cnt, bad_cnt = 0,0KS = []GOOD = []GOOD_CNT = []BAD = []BAD_CNT = []BAD_PCTG = []BAD_RATE = []DCT_REPORT = []report = {}for j in range(bins): ds = ks_lis[j * bin_num : min(bin_num * (j + 1), rows)] good1 = sum([1 for (p,y) in ds if y <= 0.5]) bad1 = sum([1 for (p,y) in ds if y > 0.5]) bad_cnt += bad1 good_cnt += good1 bad_pctg = round(bad_cnt / sum(y_valid), 3) bad_rate = round(bad1 /(bad1 + good1), 3) ks = round(math.fabs(bad_cnt / bad - good_cnt / good), 3) KS.append(ks) GOOD.append(good1) GOOD_CNT.append(good_cnt) BAD.append(bad1) BAD_CNT.append(bad_cnt) BAD_PCTG.append(bad_pctg) BAD_RATE.append(bad_rate) report['KS'] = KS report['正样本个数'] = GOOD report['正样本累计个数'] = GOOD_CNT report['负样本个数'] = BAD report['负样本累计个数'] = BAD_CNT report['捕获率'] = BAD_PCTG report['负样本占比'] = BAD_RATE pd.DataFrame(report)
报告结果如下所示:
KS 正样本个数 正样本累计个数 负样本个数 负样本累计个数 捕获率 负样本占比0 0.220 712 712 87 87 0.265 0.1091 0.293 759 1471 40 127 0.387 0.0502 0.323 773 2244 26 153 0.466 0.0333 0.390 761 3005 38 191 0.582 0.0484 0.398 780 3785 19 210 0.640 0.0245 0.394 784 4569 15 225 0.686 0.0196 0.396 782 5351 17 242 0.738 0.0217 0.398 782 6133 17 259 0.790 0.0218 0.375 790 6923 9 268 0.817 0.0119 0.361 787 7710 12 280 0.854 0.01510 0.335 791 8501 8 288 0.878 0.01011 0.290 797 9298 2 290 0.884 0.00312 0.254 794 10092 5 295 0.899 0.00613 0.222 793 10885 6 301 0.918 0.00814 0.208 787 11672 12 313 0.954 0.01515 0.182 791 12463 8 321 0.979 0.01016 0.137 797 13260 2 323 0.985 0.00317 0.096 796 14056 3 326 0.994 0.00418 0.045 799 14855 0 326 0.994 0.00019 0.000 792 15647 2 328 1.000 0.003
通过观察上述报告,我们可以看出,模型的最大的KS值出现在编号为4的分箱中,在报告中,前4箱的样本总数为3006,其中负样本190个,捕获率达到57.9%,也就是说,如果在风控决策中拒绝掉分数最低的20%的人,就可以捕获到57.9%的负样本。
3. 评分映射
根据我们在第一部分中推导出来的评分映射公式,我们可以在验证集上,映射算出每个样本的最终风险分。这里需要注意的是,逻辑回归的输出中正样本和负样本的定义与我们实际也业务中的正负样本的定义刚好相反,即数据集中的正样本(即bad_ind为1)是我们业务上的负样本,也就是欺诈样本。因此上述映射公式中的加号,在这里应该改为减号。
# 评分计算def score(x, coef, intercept): xbeta = intercept for i in range(len(x) - 1): xbeta += x[i] * coef[i] score = 650-50 * xbeta / math.log(2) return scorex_valid['score'] = x_valid.apply(lambda x : score(x, lr.coef_[0],lr.intercept_[0]) ,axis=1) x_valid.head()
# 计算KSfpr_lr,tpr_lr,_ = metrics.roc_curve(y_valid, x_valid['score']) val_ks = abs(fpr_lr - tpr_lr).max() print('val_ks : ',val_ks)
val_ks : 0.415602928637454
通过对模型进行映射评分,在时间外样本上的KS值与逻辑回归模型预测的KS值一致,因此通过这种方式可以验证映射函数的逻辑是否正确。因为在映射函数逻辑正确的情况下,是不会影响模型的排序能力的, 故映射后的KS值应当与模型映射前直接输出的KS值是一致的
4.划分评分等级
在得到用每个用户的评分之后,还可以根据评分对用户进行等级划分。如果希望某个区间的逾期率变大或变小,可以通过调整阈值参数来实现
# 划分评级def level(score): level = 0 if score <= 680: level = "D" elif score <= 730 and score > 680 : level = "C" elif score <= 780 and score > 730: level = "B" elif score > 780 : level = "A" return levelx_valid['level'] = x_valid.score.map(lambda x : level(x) )x_valid['level'].groupby(x_valid['level']).count()/len(x_valid)
levelA 0.033239B 0.167074C 0.208951D 0.590736Name: level, dtype: float64
好了,以上就是关于使用逻辑回归构建评分卡的全部内容,逻辑回归是信贷风控中解释性较强的模型,往往用到的场景比较多,且因为其效果一般都还不错,在银行和各大互联网金融公司往往会作为baseline来使用,至于评分卡建模,后期我们会介绍一种基于XGBoost的评分卡构建方法。
标签: #逻辑回归的方程