评分卡模型(一)评分卡建模实战

小P:我看你做的这些数据挖掘,虽然预测结果挺准的,但是完全不知道怎么来的啊

小H:其实在风控领域有个很流行的评分卡模型,可以很直观的告诉你什么特征加分,什么特征减分,每个样本有多少分

小P:这个可以啊,那它有什么缺点吗

小H:缺点,那自然是准确率可能会低一点~

数据探索

导入相关库

import pandas as pd
import numpy as np
import math
from sklearn.model_selection import train_test_split,cross_val_score  # 数据分区库
import xgboost as xgb
from sklearn.metrics import accuracy_score, auc, confusion_matrix, f1_score, \precision_score, recall_score, roc_curve, roc_auc_score, precision_recall_curve  # 导入指标库
from imblearn.over_sampling import SMOTE  # 过抽样处理库SMOTE
import matplotlib.pyplot as plt
import prettytable  # 导入表格库
from pandas_profiling import ProfileReport # 自动eda
import sweetviz as sv # 自动eda
import matplotlib.pyplot as plt
from matplotlib import ticker
import seaborn as sns
import os
import shutil
import toad
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import learning_curve
from sklearn.model_selection import ShuffleSplit
from toad.plot import  bin_plot, badrate_plot
from sklearn.preprocessing import LabelEncoder
from collections import defaultdict
from sklearn.linear_model import LogisticRegression
from scipy.stats import scoreatpercentile
from toad.scorecard import ScoreCard
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder  # 数据预处理库
%matplotlib inline
# 风格设置
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文
sns.set(style="ticks") # 设置风格# 导入自定义模块
import sys
sys.path.append("/Users/heinrich/Desktop/Heinrich-blog/数据分析使用手册")
from keyIndicatorMapping import *

数据准备

上述自定义模块keyIndicatorMapping如果有需要的同学可关注公众号HsuHeinrich,回复【数据挖掘-自定义函数】自动获取~

以下数据如果有需要的同学可关注公众号HsuHeinrich,回复【数据挖掘-评分卡01】自动获取~

# 读取数据
raw_data = pd.read_csv('train.csv')  # 读取数据文件
raw_data.head()

# 变量分类
var_class_dic = var_class(raw_data, 'target')
y_col = get_key(var_class_dic, 'y')[0]
date_col = get_key(var_class_dic, 'date')
number_col = get_key(var_class_dic, 'number')
object_col = get_key(var_class_dic, 'object')
# 更改数据类型
raw_data = raw_data.apply(pd.to_numeric, errors='ignore') # 把能转换成数字的都转换成数字,不能转化的由error=True参数控制忽略掉。
# raw_data[date_col] = raw_data[date_col].apply(pd.to_datetime) # 转时间列
# 数据审查
na_count = raw_data.isnull().any().sum() # 缺失值样本量
n_samples, n_features = raw_data.shape  # 总样本量,总特征数
print('samples: {0}| features: {1} | na count: {2}'.format(n_samples, n_features, na_count))
samples: 108940| features: 167 | na count: 8
# 定义id列
ids_col = ['APP_ID_C']
# 定义排除的特征列:一般包括ID列、日期列、目标列
ex_lis = ids_col+date_col+[y_col]
# 定义排除列不含y
ex_lis_noy = ids_col+date_col

变量信息

# 变量统计信息
raw_data_detect=toad.detector.detect(raw_data)
raw_data_detect

# 变量价值信息 输出iv值、gini指数,entropy熵、unique values
# 对于数据量大或高维度数据,建议使用iv_only=True 2. 要去掉主键,日期等高unique values且不用于建模的特征
toad.quality(raw_data.drop(ex_lis_noy, axis=1), y_col, iv_only=True)

特征工程

样本拆分

# 样本拆分:训练样本、测试样本
train = raw_data.loc[raw_data.month.isin(['2019-03','2019-04','2019-05'])==True,:]
test = raw_data.loc[raw_data.month.isin(['2019-03','2019-04','2019-05'])==False,:]

特征初筛

# 方式1:根据缺失率、iv、相关系数初筛
raw_data_1s, drop_lst= toad.selection.select(train, train[y_col], empty=0.7, iv=0.1, corr=0.7, return_drop=True, exclude=ex_lis)
# 方式2: 通过机器学习筛选重要特征
# 分类变量标签化
df = obj_label(raw_data, ex_lis)
# 构造xgboost数据
X = df.drop(ex_lis, axis=1)
y = df[y_col]def xgb_topN(X, y, n):# XGB分类模型param_dist = {'eval_metric':['logloss','auc','error'], 'use_label_encoder':False}xgb_select = xgb.XGBClassifier(**param_dist, seed=11)xgb_select.fit(X, y)# 获取top10特征features = X.columns  # 获取特征名称importances = xgb_select.feature_importances_  # 获取特征重要性xgb_topN_feature = list(pd.Series(importances, index=features).sort_values(ascending=False)[:n].index)return xgb_topN_feature# 合并两特征并集
N=10
xgb_topN_feature = xgb_topN(X, y, N)
features = list(set(raw_data_1s.columns.to_list()+xgb_topN_feature))# 构造新数据集
train_s = train[features].copy()print("drop empty:", len(drop_lst['empty']),  "drop iv:", len(drop_lst['iv']),  "drop corr:", len(drop_lst['corr']),"xgb keep:", N,"keep:", train_s.shape[1])
drop empty: 0 drop iv: 131 drop corr: 14 xgb keep: 10 keep: 29

变量分箱

# 得到切分节点 卡方分箱 默认为左闭右开
combiner = toad.transform.Combiner()
combiner.fit(train_s, train_s[y_col], method='chi',min_samples=0.05, exclude=ex_lis)
# 导出箱的节点
bins = combiner.export()
print(bins)
{'var_l_68': [0.000255689, 0.002045513, 0.013040143, 0.025313219], 'var_l_91': [0.000125945, 0.002141058], 'var_b17': [], 'var_l_107': [4.26e-05, 0.158232299], 'var_l_71': [0.00134285], 'var_l_67': [], 'var_d1': [['Hit-6+ Vintage'], ['Hit-lt 6 Vinta', 'nan']], 'var_b18': [-9999, 2], 'var_l_119': [0.0035087720000000003, 0.426829268], 'var_l_33': [], 'var_b15': [-8888, 1, 3], 'var_l_58': [0.000534759], 'var_b20': [], 'var_b12': [-8888, -999], 'var_l_89': [0.0005875440000000001, 0.004700353], 'var_l_19': [0.000328176], 'var_d7': [['LARGE FLEET OPERATOR', 'COMPANY', 'STRATEGIC TRANSPRTER', 'DOCTOR-SELF EMPLOYED', 'SALARIED', 'HOUSEWIFE', 'DOCTOR-SALARIED', 'CONSULTANT', 'SAL(RETIRAL AGE 58)', 'MEDIUM FLEETOPERATOR', 'STRATEGIC CAPTIVE'], ['RETAIL TRANSPORTER', 'SAL(RETIRAL AGE 60)', 'nan', 'STUDENT', 'SERVICES', 'OTHERS', 'MANUFACTURING', 'TRADER', 'PENSIONER', 'CARETAKER', 'AGENT', 'FIRST TIME USERS', 'DIRECTOR', 'SMALL RD TRANS.OPR', 'SERV-PRIVATE SECTOR', 'TRADING'], ['PROPRIETOR', 'SELF-EMPLOYED', 'BUSINESSMAN', 'RETIRED PERSONNEL', 'STRATEGIC S1', 'CONTRACTOR', 'GOVERNMENT SERVICE', 'AGRICULTURIST', 'MANAGER', 'RETAIL', 'TEACHER', 'SCHOOLS', 'BANKS SERVICE', 'OFFICER', 'ACCOUNTANT', 'RESTAURANT KEEPER', 'Salaried', 'GENARAL RETAILER', 'SERV-PUBLIC SECTOR', 'Defence (NCO)', 'POLICEMAN', 'ADVISOR', 'STRATEGIC S2', 'SALESMAN', 'BARRISTER', 'OTHERS NOT DEFINED', 'RETAIL CAPTIVE', 'SUP STRAT TRANSPORT', 'CARPENTER', 'SECRETARY', 'LECTURER', 'JEWELLER', 'DRIVER', 'ATTORNEY AT LAW', 'STRATEGIC S3', 'PROGRAMMER', 'TECHNICIAN', 'TAILOR', 'PLANTER', 'PRIEST', 'EXECUTIVE ASSISTANT', 'STRATEGIC BUS OP', 'HELPER', 'CLERK', 'PROOF READER', 'ASSOCIATION', 'TYPIST', 'DISPENSER', 'ADMINSTRATOR', 'BUS CONTROLLER', 'Trading', 'TAXI DRIVER', 'QUANTITY SURVEYOR', 'INDUSTRY', 'ENGINEERING', 'NURSE', 'PRIVATE TAILOR', 'GARAGIST', 'CHAIRMAN', 'STOCKBROKER(S)-COMMD', 'HAIRDRESSER', 'PHARMACIST', 'RETAIL BUS OPERATOR']], 'var_d2': [669.0, 748.0, 782.0, 818.0], 'var_l_125': [0.001808318, 0.237654321, 0.401360544], 'var_b10': [-8888.0, 0.548229531], 'var_l_43': [], 'var_d11': [['N'], ['U']], 'var_d5': [['O', 'nan', 'F'], ['M']], 'var_l_60': [0.000429369, 0.001288107, 0.004723057, 0.014169171], 'var_b19': [-9999, 1, 2, 6], 'var_b9': [-9999, -8888, 9]}
  • Bivar图

通过Bivar图观察变量分箱后的单调趋势,若存在波动性,则进行手动分箱

# 变量分布
# 定义df、y_col、figure_save_path
train_t = combiner.transform(train_s)
figure_save_path = "var_bivar_file"
if os.path.exists(figure_save_path):shutil.rmtree(figure_save_path)  os.mkdir(figure_save_path)
else:os.mkdir(figure_save_path)# 分箱变量展示
for x in bins.keys():bin_plot(train_t, x=x, target=y_col)plt.savefig('%s/%s.jpg' % (figure_save_path, x))plt.close()
# 计算展示的行列
num_plots = len(bins.keys())
num_cols = math.ceil(np.sqrt(num_plots))
num_rows = math.ceil(num_plots/num_cols)
# 生成网格图
fig = plt.figure(figsize = (80,60)) # 每调用一次plt.figure()函数就会创建一个新的显示窗口,与matlab中的figure类似
for i, x in enumerate(bins.keys()):path = figure_save_path+'/'+x+'.jpg'img = plt.imread(path)plt.subplot(num_cols, num_rows, i+1) # 表示第i张图片,下标只能从1开始,不能从0,plt.imshow(img)#下面两行是消除每张图片自己单独的横纵坐标,不然每张图片会有单独的横纵坐标,影响美观plt.xticks([])plt.yticks([])
fig.tight_layout() # 调整整体空白
plt.subplots_adjust(wspace =0, hspace =0) # 调整子图间距
plt.show()

  • 一些变量只有一个分组,需要剔除
  • 一些变量分箱后不具有单调趋势,需要进行手动调整。
    • 对于分类变量,存在一定的非单调趋势,若符合业务解释可不进行调整
    • 对于连续变量,存在v型趋势若符合业务解释可不进行调整。但存在上下波动趋势则一定需要手动调整
# 查找非单调趋势的连续变量和只有一个分组的变量(删除)
adj_col = []
del_col = []
for x, v in bins.items():if len(v)==0:del_col.append(x)elif x in object_col:passelse:df_temp = bin_plot(train_t, x=x, target=y_col, return_frame=True)plt.close()L = list(df_temp[1]['badrate'])if all(x<=y for x, y in zip(L, L[1:])) or all(x>=y for x, y in zip(L, L[1:])) : # 连续变量分箱后非单调passelse:adj_col.append(x)print('adj_col:',adj_col)
print('del_col:',del_col)
adj_col: ['var_l_68', 'var_l_107', 'var_b18', 'var_l_119', 'var_b12', 'var_d2', 'var_l_125', 'var_b10', 'var_b19', 'var_b9']
del_col: ['var_b17', 'var_l_67', 'var_l_33', 'var_b20', 'var_l_43']
# 手动调整分箱:部分变量分箱后,badrate没有呈现单调趋势
# 这里只调整var_b9(存在上下波动趋势)
print(bins['var_b9'])
[-9999, -8888, 9]
# 手动调整
adj_bin = {'var_b9': [-9999,9]}  # 合并2,3箱
combiner.set_rules(adj_bin)
train_t = combiner.transform(train_s)
# 绘制Bivar图,观察调整后的趋势
bin_plot(train_t, x='var_b9', target=y_col)
plt.show()

调整后的var_b9具有单调趋势

  • badrate图
  • 用来观察变量在不同样本下分箱是否具有稳定性,若不稳定,则需要手动分箱
  • 同样也可以用来观察变量在不同时间段分箱是否具有稳定性,例如训练样本、测试样本在每个月份的分箱稳定性
# 训练、测试样本间稳定性
train_t = combiner.transform(train_s)
test_t = combiner.transform(test[train_s.columns])
data = pd.concat([train_t,test_t], join='inner', keys=['train', 'test'])\.reset_index(level=0).rename(columns={'level_0':'sample'})
figure_save_path = "var_badrate_file"
if os.path.exists(figure_save_path):shutil.rmtree(figure_save_path)  os.mkdir(figure_save_path)
else:os.mkdir(figure_save_path)# 分箱变量展示
for x in bins.keys():badrate_plot(data, x='sample', target=y_col, by=x) plt.title(x)plt.savefig('%s/%s.jpg' % (figure_save_path, x))plt.close()
# 计算展示的行列
num_plots = len(bins.keys())
num_cols = math.ceil(np.sqrt(num_plots))
num_rows = math.ceil(num_plots/num_cols)
# 生成网格图
fig = plt.figure(figsize = (80,60)) # 每调用一次plt.figure()函数就会创建一个新的显示窗口,与matlab中的figure类似
for i, x in enumerate(bins.keys()):path = figure_save_path+'/'+x+'.jpg'img = plt.imread(path)plt.subplot(num_cols, num_rows, i+1) # 表示第i张图片,下标只能从1开始,不能从0,plt.imshow(img)#下面两行是消除每张图片自己单独的横纵坐标,不然每张图片会有单独的横纵坐标,影响美观plt.xticks([])plt.yticks([])
fig.tight_layout() # 调整整体空白
plt.subplots_adjust(wspace =0, hspace =0) # 调整子图间距
plt.show()

# 不同月份稳定性
train_t = combiner.transform(train_s)
test_t = combiner.transform(test[train_s.columns])
data = pd.concat([train_t,test_t], join='inner', keys=['train', 'test'])\.reset_index(level=0).rename(columns={'level_0':'sample'})
figure_save_path = "var_badrate_file_month"
if os.path.exists(figure_save_path):shutil.rmtree(figure_save_path)  os.mkdir(figure_save_path)
else:os.mkdir(figure_save_path)# 分箱变量展示
for x in bins.keys():badrate_plot(data, x='month', target=y_col, by=x) plt.title(x)plt.savefig('%s/%s.jpg' % (figure_save_path, x))plt.close()
# 计算展示的行列
num_plots = len(bins.keys())
num_cols = math.ceil(np.sqrt(num_plots))
num_rows = math.ceil(num_plots/num_cols)
# 生成网格图
fig = plt.figure(figsize = (80,60)) # 每调用一次plt.figure()函数就会创建一个新的显示窗口,与matlab中的figure类似
for i, x in enumerate(bins.keys()):path = figure_save_path+'/'+x+'.jpg'img = plt.imread(path)plt.subplot(num_cols, num_rows, i+1) # 表示第i张图片,下标只能从1开始,不能从0,plt.imshow(img)#下面两行是消除每张图片自己单独的横纵坐标,不然每张图片会有单独的横纵坐标,影响美观plt.xticks([])plt.yticks([])
fig.tight_layout() # 调整整体空白
plt.subplots_adjust(wspace =0, hspace =0) # 调整子图间距
plt.show()

  • 变量稳定性较好,无论是两样本间还是各月份。除了var_l_52(月份间)和var_l_68存在些许交叉
  • 可以不进行分箱调整,为了展示手动调整操作,这里以和var_l_68(样本、月份均存在交叉)为例
# 手动调整分箱:var_b19在不同月份间存在交叉,不具有稳定性
# var_l_68的1,2箱存在交叉,合并为一箱
print(bins['var_b19'])
[-9999, 1, 2, 6]
# 手动调整
adj_bin = {'var_b19': [-9999, 1, 6]}
combiner.set_rules(adj_bin)
train_t = combiner.transform(train_s)
test_t = combiner.transform(test[train_s.columns])
data = pd.concat([train_t,test_t], join='inner', keys=['train', 'test'])\.reset_index(level=0).rename(columns={'level_0':'sample'})
# 绘制badrate图,观察调整后的结果
badrate_plot(data, x='sample', target=y_col, by='var_b19')
badrate_plot(data, x='month', target=y_col, by='var_b19')
plt.show()

手动分箱后,在不同样本、月份间均稳定

# 剔除单分组变量
train_t.drop(del_col, axis=1, inplace=True)
test_t.drop(del_col, axis=1, inplace=True)print("keep:", train_t.shape[1])
keep: 24

WOE编码

目的是将特征的非线性关系转换为线性的,对异常值不敏感

w = toad.transform.WOETransformer()
#对WOE的值进行转化,映射到原数据集上。对训练集用fit_transform,测试集用transform.
train_w = w.fit_transform(train_t, train_t[y_col], exclude=ex_lis)
test_w = w.transform(test_t[train_t.columns])
data = pd.concat([train_w, test_w])

二次筛选

# psi筛选 筛选稳定性的变量
np.seterr(divide='ignore',invalid='ignore') # 防止0/0产生的invalid value
psi_df = toad.metrics.PSI(train_w, test_w).sort_values(0)
psi_df = psi_df.reset_index()
psi_df = psi_df.rename(columns = {'index': 'feature', 0: 'psi'})
col_keep = list(set(list(psi_df[psi_df.psi<0.02].feature)).union(set(ex_lis))) # 保留低psi特征和不参与特征的并集
train_psi = train_w[col_keep]print("keep:", train_psi.shape[1])
keep: 24
# 因为特征WOE编码后,部分变量的IV变低,且整体相关性变大。故再次进行特征筛选
train_psi_s2, drop_lst = toad.selection.select(train_psi,train_psi[y_col],empty=0.7,   iv=0.1, corr=0.7, return_drop=True, exclude=ex_lis)
print("keep:", train_psi_s2.shape[1],  "drop empty:", len(drop_lst['empty']),  "drop iv:", len(drop_lst['iv']),  "drop corr:", len(drop_lst['corr']))
keep: 13 drop empty: 0 drop iv: 9 drop corr: 2
# 逐步回归筛选变量
train_stp = toad.selection.stepwise(train_psi_s2,  train_psi_s2[y_col],  exclude=ex_lis,  direction='both',   criterion='aic',  estimator='ols',intercept=False)
print("keep:", train_stp.shape[1])
keep: 10

生成最终数据集

test_stp = test_w[train_stp.columns]
data_finall = pd.concat([train_stp, test_stp])
print(data_finall.shape)
(108940, 10)

数据建模

模型训练

# 样本拆分
X, y = data_finall.drop(ex_lis, axis=1), data_finall[y_col]
X_train, y_train = train_stp.drop(ex_lis, axis=1), train_stp[y_col]
X_test, y_test = test_stp.drop(ex_lis, axis=1), test_stp[y_col]
# 样本均衡处理
model_smote = SMOTE(random_state=0)  # 建立SMOTE模型对象 设置随机种子,保持采样样本一致
X_train, y_train = model_smote.fit_resample(X_train,y_train)  # 输入数据并作过抽样处理
# 模型训练
model_lr = LogisticRegression(C=0.1, class_weight='balanced')
model_lr.fit(X_train, y_train)
LogisticRegression(C=0.1, class_weight='balanced')

模型评估

  • 核心指标评估
model_confusion_metrics(model_lr, X_train, y_train, 'train')
model_confusion_metrics(model_lr, X_test, y_test, 'test')
confusion matrix for train+----------+--------------+--------------+
|          | prediction-0 | prediction-1 |
+----------+--------------+--------------+
| actual-0 |    45378     |    18566     |
| actual-1 |    23641     |    40303     |
+----------+--------------+--------------+
confusion matrix for test+----------+--------------+--------------+
|          | prediction-0 | prediction-1 |
+----------+--------------+--------------+
| actual-0 |     683      |     288      |
| actual-1 |    15786     |    26819     |
+----------+--------------+--------------+
model_core_metrics(model_lr, X_train, y_train, 'train')
model_core_metrics(model_lr, X_test, y_test, 'test')
core metrics for train+------+----------+-----------+--------+-------+------+
| auc  | accuracy | precision | recall |   f1  |  ks  |
+------+----------+-----------+--------+-------+------+
| 0.74 |   0.67   |   0.657   |  0.71  | 0.683 | 0.35 |
+------+----------+-----------+--------+-------+------+
core metrics for test+-------+----------+-----------+--------+-------+-------+
|  auc  | accuracy | precision | recall |   f1  |   ks  |
+-------+----------+-----------+--------+-------+-------+
| 0.728 |  0.631   |   0.041   | 0.703  | 0.078 | 0.335 |
+-------+----------+-----------+--------+-------+-------+
  • 测试集AUC较低;ks一般
  • 训练集与测试集的核心指标差异不大,不存在过拟合。ks接近,模型较稳定
  • 模型区分与排序能力评估
fig = plt.figure(figsize=(18,12))
plt.subplot(221)
plot_roc(model_lr, X_test, y_test, name='test')
plt.subplot(222)
plot_ks(model_lr, X_test, y_test, name='test')
plt.subplot(223)
plot_pr(model_lr, X_test, y_test, name='test')
plt.subplot(224)
plot_lift(model_lr, X_test, y_test, name='test')
plt.tight_layout()
plt.show()

  • ROC曲线弯曲度较小,并且头部不靠前(即较小的FPR没有产生较高的TPR)。因此该模型区分能力一般,排序能力一般
  • KS曲线中tpr与fpr有一定差异,最大差异值在0.3左右。因此模型行区分度一般
  • PR曲线precision较低,该模型在不平衡样本下的召回能力一般
  • lift图表明模型抓取bad客户的能力比随机高出3倍多,cum_lift下将较快,前置抓取能力较强
  • 模型泛化能力评估
fig = plt.figure(figsize=(18,12))
plt.subplot(221)
plot_cv_box(model_lr, X_test, y_test, name='test')
plt.subplot(222)
plot_learning_curve(model_lr, X_test, y_test, name='test')
plt.tight_layout()
plt.show()

  • cv箱线图表明模型存在一次异常值,说明模型泛化能力一般
  • 学习曲线表明模型欠拟合
  • 模型稳定性评估
# 模型PSI:小于10%,则无需更新模型;10%-20%, 需检查变化原因,加强监控频率;大于20%,则模型需要迭代
mpsi = model_psi(model_lr, X_train, X_test)
print('模型PSI:',mpsi)
模型PSI: 0.3299012600361123
  • 模型捕获报告评估
# 模型捕获率报告
y_test_prob = model_lr.predict_proba(X_test)[:, 1]
df_capture = capture_table(y_test_prob, y_test)
df_capture.columns=['KS', '负样本个数', '正样本个数', '负样本累计个数', '正样本累计个数', '捕获率', '负样本占比']
df_capture

  • 模型捕获率报告表明在前置50%的样本中能捕捉到84%的坏客户,较优秀
  • 负样本占比在第3、4箱出现跳动,排序能力较差

结果展示

评分卡

逻辑回归评分卡拉伸规则: S c o r e = A − B ∗ l o g ( p 1 − p ) Score=A-B*log(\frac{p}{1-p}) Score=A−B∗log(1−pp​)

  • 定义 o d d s = p 1 − p odds=\frac{p}{1-p} odds=1−pp​。表示违约与不违约的概率比
  • 预设条件:
    • 在某个特定odds设定特定的预期分值P0
    • 指定比率翻rate倍分数的变动值(PDO),一般rate=2
  • 根据预设条件有:
    P 0 = A − B ∗ l o g ( o d d s ) P_0=A-B*log(odds) P0​=A−B∗log(odds)
    P 0 + P D O = A − B ∗ l o g ( r a t e ∗ o d d s ) P_0+PDO=A-B*log(rate*odds) P0​+PDO=A−B∗log(rate∗odds)
  • 解出AB的值:
    B = P D O l o g ( r a t e ) B=\frac{PDO}{log(rate)} B=log(rate)PDO​
    A = P 0 + B ∗ l o g ( o d d s ) A=P_0+B*log(odds) A=P0​+B∗log(odds)
# 计算odds
bad_total=raw_data[y_col].sum()
good_total=raw_data.shape[0]-bad_total
odds=round(bad_total/good_total,2)
base_odds=round(good_total/bad_total,0)
print('bad_total:{0}\ngood_total:{1}\nodds:{2}\nbase_odds:{3}\n'.format(bad_total,good_total,odds,base_odds))
bad_total:2391
good_total:106549
odds:0.02
base_odds:45.0
# 生成评分报告 # 注意ScoreCard方法里求解A=												

评分卡模型(一)评分卡建模实战相关推荐

  1. (信贷风控八)行为评分卡模型(B卡)的介绍

    (八)行为评分卡模型(B卡)的介绍 在信贷业务中,评分卡分为三种: 申请评分卡(A卡) 行为评分卡(B卡) 催收评分卡(C卡) 本篇我们来学习一下行为评分卡(B卡),首先什么是行为评分卡呢,行为评分卡 ...

  2. 金融风控-申请评分卡模型-申请评分卡介绍

    从这篇博文开始,我将总结金融风控中的另外一个模型:申请评分卡模型.这篇博文将主要来介绍申请评分卡的一些基本概念. 本篇博文将以以下四个主题来进行介绍说明: 信用风险和评分卡模型的基本概念 申请评分卡在 ...

  3. 风控必备的评分卡模型,TempoAI 10分钟搞定

    8月20日,央行发布了<2020年第二季度支付体系运行总体情况>,数据显示,截至第二季度末,信用卡逾期半年未偿信贷总额838.84亿元,占信用卡应偿信贷余额的1.17%.与一季度相比,信用 ...

  4. logit回归模型的参数估计过程_评分卡模型原理及应用

    关注新蜂数字金融,ID:gh_c5ca7eb11df4 这是新蜂数字金融的第145篇原创首发文章 信用评分卡模型,作为金融业一项重要的风险控制手段,在行业中有着广泛的应用.只有对模型进行科学认知,理解 ...

  5. 数学建模实战——茂名市科技创新和科技金融评价模型

    数学建模实战--茂名市科技创新和科技金融评价模型 文章目录 数学建模实战--茂名市科技创新和科技金融评价模型 前言 一.题目分析 1.题目原题 2.题目分析 二.题目实战 1.数据处理 2.选择综合评 ...

  6. 评分卡模型建模详细步骤-评分卡建模实例之scorecardpy

    目录 0.引言 1.scorecardpy介绍 2.评分卡建模过程 2.1数据加载 2.1变量筛选 2.2数据划分 2.3变量分箱 2.3.1 自动分箱 2.3.2 手动调整分箱 2.4变量转化woe ...

  7. python金融风控评分卡模型和数据分析

    python金融风控评分卡模型和数据分析微专业课(博主录制):http://dwz.date/b9vv 作者Toby:持牌照消费金融模型专家,和中科院,中科大教授保持长期项目合作:和同盾,聚信立等外部 ...

  8. python金融风控评分卡模型

    python金融风控评分卡模型和数据分析微专业课(博主录制): [ http://dwz.date/b9vv ](https://study.163.com/series/1202875601.htm ...

  9. (信贷风控九)行为评分卡模型python实现

    python信用评分卡建模(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_ca ...

最新文章

  1. matlab GM(2,1)模型
  2. 如何从三流程序员成长为一名年薪50W的架构师(文末附送学习资料)
  3. DOS下操作注册表的部分命令
  4. VC++ 添加UNICODE和_UNICODE预处理选项
  5. OSPF的高级配置(连载1)
  6. 深度学习-Tensorflow2.2-Tensorboard可视化{5}-可视化基础-17
  7. Android总结 之 View系统学习(一)
  8. java整数四则运算课设_用面向对象方法设计实现整数的四则运算(java)
  9. mysql identifier name is too long_ORA-00972: identifier is too long 问题处理
  10. gcc是java的什么意思_为什么gcc支持Java而不是C#
  11. go int 转切片_一文掌握GO语言实战技能(二)
  12. Qt 学习之路 2(2):Qt 简介 笔记
  13. Bash基础——快捷键
  14. 严选chat_拔草 | 网易严选的零食,真的“严选”了吗?
  15. Xftp6的安装与使用
  16. 那位有epson R1900中文清零软件?
  17. 中国矿业大学计算机学院进复试,拟录取名单陆续公布!初试第二败北,倒数第一逆袭!...
  18. oracle 拼音首字母查询,使用ORACLE函数实现按汉字拼音首字母查询
  19. Win10桌面图标箭头去掉的方法总结
  20. [C++]牛客 WY11 星际穿越

热门文章

  1. NLifeBill第四章添加页面
  2. 高德地图H5 定位失败报错 geolocation time out. Get ipLocation failed解决方案
  3. DAX Calculate的使用说明
  4. 马云装神弄鬼拜见过被通缉的气功大师王林, 歪门邪道的人还办教育,用淘宝支付宝真的不放心
  5. Set接口下的三个实用类
  6. 交叉编译wpa_supplicant常见问题总结
  7. Aspen Plus教程-孙兰义-例7.1-质量分数求解摩尔回收率
  8. 使用安卓手机控制树莓派
  9. Django 启动出现(WARNINGS)
  10. 2020美团笔试题目:送餐小区数量