逻辑回归——银行贷款检查

背景:本文数据样本来源于2013年9月欧洲持卡人在两天内进行的284808笔信用卡交易,其中有493笔欺诈交易。由于保密问题,只包含作为PCA转化结果的数字输入变量,特征V1,V2,… V28是使用PCA获得的主要组件,交易金额是常量,是否欺诈(class)是分类变量。
目的:得到较为准确的欺诈检测方法
过程:使用python pandas,numpy,matplotlib,以及机器学习库中的逻辑回归LogisticRegression

1,获取数据
获取数据之后先不着急选用模型,先观察数据集


2.jpg

数据集一共31列 ,其中
time:交易时长
V1-V28:特征集
amount:交易金额
class:0表示正常样本,1表示异常样本
amount 列没有经过脱敏,先对amount进行数据规范化处理,得到nomamount,以及删除对模型没有印象的数据


5.jpg

数据处理完成,接下来查看数据是否有缺失值,如果有,则需要判断使用中位数还是均值等填充,以便接下来的模型训练


3.jpg

数据无缺失值,不需要进行缺失值处理,查看样本分布规则


image.png

正常样本跟异常样本数据存在很大的不均衡,对后续模型评估会产生很大影响,对样本不均衡的处理方法有两种方案(也许还有,只是我还没学到):
1,下采样:将数据变得同样少,缺点:误杀值也会变的很大
2,过采样:将数据变得同样多,缺点:容易导致召回率变低
这里我们采用两6种方法,具体查看两种方法的区别
下采样:


6.jpg

下采样完成,开始交叉验证:数据划分
训练集,测试集,其中训练集包含有验证集,在选用模型划分数据可以体现


7.jpg

使用K折交叉验证,这里对比了L1正则化跟L2正则化,结果一致
# 建立模型,进行验证,求出最优参数解

from sklearn.model_selection import KFold, cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, recall_score, classification_report
def printing_Kfold_scores(x_train_data,y_train_data):
    fold = KFold(5,shuffle=False) 
    # 会得到一个可迭代对象(可以用 for 循环遍历取出),可以遍历5次,每次遍历出来的会是一个2值列表,
    # 存放每一次的训练集和验证集的索引


    # Different C parameters
    c_param_range = [0.01,0.1,1,10,100]

    results_table = pd.DataFrame(index = range(len(c_param_range),2), columns = ['C_parameter','Mean recall score'])
    results_table['C_parameter'] = c_param_range

    # the k-fold will give 2 lists: train_indices = indices[0], test_indices = indices[1]
    j = 0
    for c_param in c_param_range:
        print('-------------------------------------------')
        print('C parameter: ', c_param)
        print('-------------------------------------------')
        print('')

        recall_accs = []
        for iteration, indices in enumerate(fold.split(x_train_data),start=1):
            # enumerate 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中
            # iteration 表示第几次循环,indices 是一个列表里面有两个元素,indices[0]表示训练集索引,indices[1] 表示验证集索引

            # Call the logistic regression model with a certain C parameter
            lr = LogisticRegression(C = c_param, penalty = 'l1', solver = 'liblinear')

            # Use the training data to fit the model. In this case, we use the portion of the fold to train the model
            # with indices[0]. We then predict on the portion assigned as the 'test cross validation' with indices[1]
            lr.fit(x_train_data.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())
            
            # Predict values using the test indices in the training data
            y_pred_undersample = lr.predict(x_train_data.iloc[indices[1],:].values)

            # Calculate the recall score and append it to a list for recall scores representing the current c_parameter
            recall_acc = recall_score(y_train_data.iloc[indices[1],:].values,y_pred_undersample)
            recall_accs.append(recall_acc)
            print('Iteration ', iteration,': recall score = ', recall_acc)

        # The mean value of those recall scores is the metric we want to save and get hold of.
        results_table.loc[j,'Mean recall score'] = np.mean(recall_accs)
        j += 1
        print('')
        print('Mean recall score ', np.mean(recall_accs))
        print('')

    best_c_l1 = results_table.loc[results_table['Mean recall score'].astype(float).idxmax()]['C_parameter']
    
    # Finally, we can check which C parameter is the best amongst the chosen.
    print('*********************************************************************************')
    print('Best model to choose from cross validation is with C parameter = ', best_c_l1)
    print('*********************************************************************************')
    
    return best_c_l1, results_table

把l1换成l2查看两种正则化惩罚项结果

11.jpg

两种模型最优参数C均为0.01,但是l2评分明显小于l1,下面使用该参数进行模型评估
这里选用混淆矩阵评估模型,(还有ROC曲线,精确率等常用模型)

# 下采样混淆矩阵
lr = LogisticRegression(C = 0.01, penalty = 'l1', solver = 'liblinear')
lr.fit(x_train_undersample, y_train_undersample.values.ravel())
y_pred_undersample = lr.predict(x_test_undersample.values)
cnf_matrix = confusion_matrix(y_test_undersample, y_pred_undersample)
np.set_printoptions(precision = 2)

print('Recall matric in the testiing datasets:', cnf_matrix[1,1]/(cnf_matrix[1,0] + cnf_matrix[1,1]))

plt.figure()
plt.imshow(cnf_matrix, interpolation = 'nearest', cmap = plt.cm.Blues)
plt.title('Confusion Mtric')
plt.colorbar()
tick_marks = np.arange(2)
plt.xticks(tick_marks, [0,1], rotation = 0)
plt.yticks(tick_marks,[0,1])
thresh = cnf_matrix.max() / 2.
for i, j in itertools.product(range(cnf_matrix.shape[0]), range(cnf_matrix.shape[1])):
    plt.text(j, i, cnf_matrix[i, j],
             horizontalalignment="center",
             color="white" if cnf_matrix[i, j] > thresh else "black")

plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')
12.jpg

这里可以看到召回率大约在0.94左右,我们再看看原数据的混淆矩阵,将上面的训练模型数据改成原数据即可


13.jpg

召回率明显下降很多,只有0.55左右,召回率偏低,但是误杀数并不多,在来看看使用原数据测试集对下采样进行预测


14.png

这里可以看到,召回率0.91左右,但是误杀数高达10544,也就是说预测出了135个结果,误杀了10544个,接下来,我们需要查看阈值对混淆矩阵的影响,系统默认的阈值是0.5,意思是对所有概率或评分在0.5以上的,分类到1,0.5一下的,分类到0,所以我们需要根据实际需求设置阈值
这里给一点小建议,凡是出现两次或以上次数的代码,都将它打包成函数调用(教训)
def plot_confusion_matric(cm,classes,title = 'Confusion matric', cmap = plt.cm.Blues):
    plt.imshow(cm, interpolation = 'nearest', cmap = cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation = 0)
    plt.yticks(tick_marks, classes)
    thresh = cm.max()/2
    for i,j in itertools.product(range(cm.shape[0]),range(cm.shape[1])):
        plt.text(j, i, cm[i,j], horizontalalignment='center', color = 'white' if cm[i,j] > thresh else 'black')
    plt.tight_layout()
    plt.xlabel('True label')
    plt.ylabel('Predicted label')

混淆矩阵生成函数

# 不同阈值对混淆矩阵的影响

lr = LogisticRegression(C = 0.01, penalty = 'l1', solver = 'liblinear')
lr.fit(x_train_undersample, y_train_undersample.values.ravel())
y_pred_undersample = lr.predict_proba(x_test_undersample.values)

thresholds = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

plt.figure(figsize = (10,10))
j = 1
for i in thresholds:
    y_test_pred_hight_recall = y_pred_undersample[:,1] > i
    plt.subplot(3,3,j)
    j += 1
    cnf_matrix = confusion_matrix(y_test_undersample, y_test_pred_hight_recall)
    np.set_printoptions(precision = 2)
    print('Recall matric in the testiing datasets:', cnf_matrix[1,1]/(cnf_matrix[1,0] + cnf_matrix[1,1]))

    class_name = [0,1]
    plot_confusion_matric(cnf_matrix, classes = class_name, title = 'Thresholds >= %s'%i)
15.jpg

这里可以看到不同阈值对召回率的影响,具体阈值跟召回率的选择,需要根据具体情景选择,下面我们在看看使用过采样处理数据
过采样的原理:在少数样本T中,找到特征向量Xi的K个近邻,在这K个中随机选择一个,重复这以过程,直到达到目标数N为止,可以说是基于“差值”合成新样本的算法
导入相关包,因为过采样跟下采样处理原理不一样,所以需要重新加载一遍数据


image.png

开始过采样,交叉验证,除了过采样之外,验证及混淆矩阵跟下采样差不多,这里就不多累赘了


image.png

image.png

image.png

混淆矩阵中,跟图14对比,可以明显的看到误杀值下降很大,说明过采样明显减少了误杀值,所以在数据不均衡的情况下,较经常使用过采样,但是有一点,那是运行速度很慢,我的老年机跑了十几分钟.......
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341