2.7.py xgboost版评分映射

主要修改点有2处:

1.xgboost的参数,有些参数现版本的xgboost是没有的,需要注释掉或者使用现在的替换

2.xgboost版评分映射的问题,由于预测的是逾期的概率,因此我们需要使用基础分-后面的,而不是+

#%%
import pandas as pd  
from sklearn.metrics import roc_auc_score,roc_curve,auc  
from sklearn import metrics  
from sklearn.linear_model import LogisticRegression  
import numpy as np  
data = pd.read_csv('xxx/Acard.txt')  
data.head()  
data.obs_mth.unique()
'''
array(['2018-10-31', '2018-07-31', '2018-09-30', '2018-06-30',
       '2018-11-30'], dtype=object)

'''
#每个月的数据量
data.obs_mth.value_counts()
'''
Out[233]: 
2018-07-31    34030
2018-06-30    20565
2018-11-30    15975
2018-10-31    14527
2018-09-30    10709
Name: obs_mth, dtype: int64
'''

train = data[data.obs_mth != '2018-11-30'].reset_index().copy()   #训练集
val = data[data.obs_mth == '2018-11-30'].reset_index().copy()  #测试集
  
feature_lst = ['person_info','finance_info','credit_info','act_info']  
x = train[feature_lst]  
y = train['bad_ind']  
  
val_x =  val[feature_lst]  
val_y = val['bad_ind']  #0.0205320813771518


#%%
lr_model = LogisticRegression(C=0.1,class_weight='balanced')  
lr_model.fit(x,y) 
 
#训练集
y_pred = lr_model.predict_proba(x)[:,1]  
fpr_lr_train,tpr_lr_train,_ = roc_curve(y,y_pred)  
train_ks = abs(fpr_lr_train - tpr_lr_train).max()  
print('train_ks : ',train_ks)  #0.4482325608488951

#测试集  
y_pred = lr_model.predict_proba(val_x)[:,1]  
fpr_lr,tpr_lr,_ = roc_curve(val_y,y_pred)  
val_ks = abs(fpr_lr - tpr_lr).max()  
print('val_ks : ',val_ks)  #0.4198642457760936

from matplotlib import pyplot as plt  
plt.plot(fpr_lr_train,tpr_lr_train,label = 'train LR')  
plt.plot(fpr_lr,tpr_lr,label = 'evl LR')  
plt.plot([0,1],[0,1],'k--')  
plt.xlabel('False positive rate')  
plt.ylabel('True positive rate')  
plt.title('ROC Curve')  
plt.legend(loc = 'best')  
plt.show() 

#%% ks
import math
model = lr_model  
row_num, col_num = 0, 0  
bins = 20  
Y_predict = [s[1] for s in model.predict_proba(val_x)]  
Y = val_y  
nrows = Y.shape[0]  
lis = [(Y_predict[i], Y[i]) for i in range(nrows)]  
ks_lis = sorted(lis, key=lambda x: x[0], reverse=True)  
bin_num = int(nrows/bins+1)  
bad = sum([1 for (p, y) in ks_lis if y > 0.5])  
good = sum([1 for (p, y) in ks_lis if y <= 0.5])  
bad_cnt, good_cnt = 0, 0  
KS = []  
BAD = []  
GOOD = []  
BAD_CNT = []  
GOOD_CNT = []  
BAD_PCTG = []  
BADRATE = []  
dct_report = {}  
for j in range(bins):  
    ds = ks_lis[j*bin_num: min((j+1)*bin_num, nrows)]  
    bad1 = sum([1 for (p, y) in ds if y > 0.5])  
    good1 = sum([1 for (p, y) in ds if y <= 0.5])  
    bad_cnt += bad1  
    good_cnt += good1  
    bad_pctg = round(bad_cnt/sum(val_y),3)  
    badrate = round(bad1/(bad1+good1),3)  
    ks = round(math.fabs((bad_cnt / bad) - (good_cnt / good)),3)  
    KS.append(ks)  
    BAD.append(bad1)  
    GOOD.append(good1)  
    BAD_CNT.append(bad_cnt)  
    GOOD_CNT.append(good_cnt)  
    BAD_PCTG.append(bad_pctg)  
    BADRATE.append(badrate)  
    dct_report['KS'] = KS  
    dct_report['负样本个数'] = BAD  
    dct_report['正样本个数'] = GOOD  
    dct_report['负样本累计个数'] = BAD_CNT  
    dct_report['正样本累计个数'] = GOOD_CNT  
    dct_report['捕获率'] = BAD_PCTG  
    dct_report['负样本占比'] = BADRATE  
val_repot = pd.DataFrame(dct_report)  
print(val_repot)  

#%% 利用pyecharts来画图 

#其实就每个分区逾期率和ks的曲线图
from pyecharts.charts import *  
from pyecharts import options as opts  
from pylab import *  
mpl.rcParams['font.sans-serif'] = ['SimHei']  
np.set_printoptions(suppress=True)  
pd.set_option('display.unicode.ambiguous_as_wide', True)  
pd.set_option('display.unicode.east_asian_width', True)  
line = (  
  
    Line()  
    .add_xaxis(list(val_repot.index))  
    .add_yaxis(  
        "分组坏人占比",  
        list(val_repot.负样本占比),  
        yaxis_index=0,  
        color="red",  
    )  
    .set_global_opts(  
        title_opts=opts.TitleOpts(title="行为评分卡模型表现"),  
    )  
    .extend_axis(  
        yaxis=opts.AxisOpts(  
            name="累计坏人占比",  
            type_="value",  
            min_=0,  
            max_=0.5,  
            position="right",  
            axisline_opts=opts.AxisLineOpts(  
                linestyle_opts=opts.LineStyleOpts(color="red")  
            ),  
            axislabel_opts=opts.LabelOpts(formatter="{value}"),  
        )  
  
    )  
    .add_xaxis(list(val_repot.index))  
    .add_yaxis(  
        "KS",  
        list(val_repot['KS']),  
        yaxis_index=1,  
        color="blue",  
        label_opts=opts.LabelOpts(is_show=False),  
    )  
)  
line.render_notebook()  


#还有最好在jupyter 上面跑,Spyder不展示该图

#%%
print('变量名单:',feature_lst)  
print('系数:',lr_model.coef_)  
print('截距:',lr_model.intercept_)  
'''
变量名单: ['person_info', 'finance_info', 'credit_info', 'act_info']
系数: [[ 3.4946237  11.40440098  2.45601882 -1.6844742 ]]
截距: [-0.34578469]
'''

import math
#算分数onekey   
def score(person_info,finance_info,credit_info,act_info):  
    xbeta = person_info * ( 3.49460978) 
                  + finance_info * ( 11.40051582 ) 
                  + credit_info * (2.45541981) 
                  + act_info * ( -1.68676079) 
                  -0.34484897   
    score = 650-34* (xbeta)/math.log(2)  
    return score  
val['score'] = val.apply(lambda x : 
                            score(x.person_info,x.finance_info,x.
                            credit_info,x.act_info) ,axis=1)  
fpr_lr,tpr_lr,_ = roc_curve(val_y,val['score'])  
val_ks = abs(fpr_lr - tpr_lr).max()  
print('val_ks : ',val_ks)  

#%%

#对应评级区间  
def level(score):  
    level = 0  
    if score <= 600:  
        level = "D"  
    elif score <= 640 and score > 600 :   
        level = "C"  
    elif score <= 680 and score > 640:  
        level = "B"  
    elif  score > 680 :  
        level = "A"  
    return level  
val['level'] = val.score.map(lambda x : level(x) )  
print(val.level.groupby(val.level).count()/len(val))  



#%% xgb

import xgboost as xgb  
data = pd.read_csv('xxx/Acard.txt')  
df_train = data[data.obs_mth != '2018-11-30'].reset_index().copy()  
val = data[data.obs_mth == '2018-11-30'].reset_index().copy()  
lst = ['person_info','finance_info','credit_info','act_info']  
  
train = data[data.obs_mth != '2018-11-30'].reset_index().copy()  
evl = data[data.obs_mth == '2018-11-30'].reset_index().copy()  
  
x = train[lst]  
y = train['bad_ind']  
  
evl_x =  evl[lst]  
evl_y = evl['bad_ind']  



#%% 
#定义XGB函数  
def XGB_test(train_x,train_y,test_x,test_y):  
    from multiprocessing import cpu_count  
    clf = xgb.XGBClassifier(
        boosting_type='gbdt', num_leaves=31, 
                reg_Ap=0.0, reg_lambda=1,  
        max_depth=2, n_estimators=800,
                max_features = 140, objective='binary:logistic',  
        subsample=0.7, colsample_bytree=0.7, subsample_freq=1,  
        learning_rate=0.05, min_child_weight=50,
                random_state=None,n_jobs=cpu_count()-1,  
        num_iterations = 800 #迭代次数  
    )  
    clf.fit(train_x, train_y,eval_set=[(train_x, train_y),(test_x,test_y)],
                eval_metric='auc',early_stopping_rounds=100)  
    #print(clf.n_features_) 现在乜有这个参数了  
    return clf #,clf.best_score_[ 'valid_1']['auc']   

#模型训练
model = XGB_test(x,y,evl_x,evl_y) 

#训练集预测
y_pred = model.predict_proba(x)[:,1]  
fpr_xgb_train,tpr_xgb_train,_ = roc_curve(y,y_pred)  
train_ks = abs(fpr_xgb_train - tpr_xgb_train).max()  
print('train_ks : ',train_ks)  #train_ks :  0.45953542070724995 

#跨时间验证集预测
y_pred = model.predict_proba(evl_x)[:,1]  
fpr_xgb,tpr_xgb,_ = roc_curve(evl_y,y_pred)  
evl_ks = abs(fpr_xgb - tpr_xgb).max()  
print('evl_ks : ',evl_ks)  #evl_ks :  0.4368715190475225

#画出ROC曲线并计算KS值
from matplotlib import pyplot as plt  
plt.plot(fpr_xgb_train,tpr_xgb_train,label = 'train LR')  
plt.plot(fpr_xgb,tpr_xgb,label = 'evl LR')  
plt.plot([0,1],[0,1],'k--')  
plt.xlabel('False positive rate')  
plt.ylabel('True positive rate')  
plt.title('ROC Curve')  
plt.legend(loc = 'best')  
plt.show()  


#计算分数,评分映射,原来梅老师这里是600-50*(math.log2((1- pred)/ pred)),但是由于预测的是坏用户,因此设置为减
def score(pred):   
    score = 600-50*(math.log2((1- pred)/ pred))  
    return score  
evl['xbeta'] = model.predict_proba(evl_x)[:,1]     
evl['score'] = evl.apply(lambda x : score(x.xbeta) ,axis=1)  
fpr_lr,tpr_lr,_ = roc_curve(evl_y,evl['score'])  
evl_ks = abs(fpr_lr - tpr_lr).max()  
print('val_ks : ',evl_ks)  #val_ks :  0.4368715190475225




#%%生成模型报告
row_num, col_num = 0, 0  
bins = 20  
Y_predict = evl['score']  
Y = evl_y  
nrows = Y.shape[0]  
lis = [(Y_predict[i], Y[i]) for i in range(nrows)]  
ks_lis = sorted(lis, key=lambda x: x[0], reverse=True)  
bin_num = int(nrows/bins+1)  
bad = sum([1 for (p, y) in ks_lis if y > 0.5])  
good = sum([1 for (p, y) in ks_lis if y <= 0.5])  
bad_cnt, good_cnt = 0, 0  
KS = []  
BAD = []  
GOOD = []  
BAD_CNT = []  
GOOD_CNT = []  
BAD_PCTG = []  
BADRATE = []  
dct_report = {}  
for j in range(bins):  
    ds = ks_lis[j*bin_num: min((j+1)*bin_num, nrows)]  
    bad1 = sum([1 for (p, y) in ds if y > 0.5])  
    good1 = sum([1 for (p, y) in ds if y <= 0.5])  
    bad_cnt += bad1  
    good_cnt += good1  
    bad_pctg = round(bad_cnt/sum(evl_y),3)  
    badrate = round(bad1/(bad1+good1),3)  
    ks = round(math.fabs((bad_cnt / bad) - (good_cnt / good)),3)  
    KS.append(ks)  
    BAD.append(bad1)  
    GOOD.append(good1)  
    BAD_CNT.append(bad_cnt)  
    GOOD_CNT.append(good_cnt)  
    BAD_PCTG.append(bad_pctg)  
    BADRATE.append(badrate)  
    dct_report['KS'] = KS  
    dct_report['BAD'] = BAD  
    dct_report['GOOD'] = GOOD  
    dct_report['BAD_CNT'] = BAD_CNT  
    dct_report['GOOD_CNT'] = GOOD_CNT  
    dct_report['BAD_PCTG'] = BAD_PCTG  
    dct_report['BADRATE'] = BADRATE  
val_repot = pd.DataFrame(dct_report)  
print(val_repot)



#%% 自定义损失函数,需要提供损失函数的一阶导和二阶导  
def loglikelood(preds, dtrain):  
    labels = dtrain.get_label()  
    preds = 1.0 / (1.0 + np.exp(-preds))  
    grad = preds - labels  
    hess = preds * (1.0-preds)  
    return grad, hess  
  
# 自定义前20%正样本占比最大化评价函数  
def binary_error(preds, train_data):  
    labels = train_data.get_label()  
    dct = pd.DataFrame({'pred':preds,'percent':preds,'labels':labels})  
    #取百分位点对应的阈值  
    key = dct['percent'].quantile(0.2)  
    #按照阈值处理成二分类任务  
    dct['percent']= dct['percent'].map(lambda x :1 if x <= key else 0)    
    #计算评价函数,权重默认0.5,可以根据情况调整  
    result = np.mean(dct[dct.percent== 1]['labels'] == 1)*0.5 
               + np.mean((dct.labels - dct.pred)**2)*0.5  
    return 'error',result  
  
watchlist  = [(dtest,'eval'), (dtrain,'train')]  
param = {'max_depth':3, 'eta':0.1, 'silent':1}  
num_round = 100  
# 自定义损失函数训练  
bst = xgb.train(param, dtrain, num_round, watchlist, loglikelood, binary_error) 

展示一些过程图片

 

原文地址:https://www.cnblogs.com/cgmcoding/p/15351744.html