信用卡欺诈案例

逻辑回归

    逻辑回归是一种经典的二分类算法,一般拿到分类任务时,会先用逻辑回归来试一下。

    逻辑回归简单地讲,就是采用某种非线性/线性公式,计算出0-1之间的值,设置一个阈值,再进行分类

目录

一、读取数据,先了解一下

二、数据预处理

2.1  计算正常样本和异常样本的比例:pd.value_counts

2.2 Amount 这列的数据标准化

三、建立模型

3.1 下采样方式进行模型训练

1. 下采样,获得正反例数目均衡的样本,用作模型训练

2. 将数据分训练集、测试集

3. 实例化模型

3.2 过采样方式创建模型

1. SMOTE算法原理

2. 安装imblearn库:pip install imblearn

3. 程序

四、模型评估方法

4.1 精度

4.2  召回率

4.3 混淆矩阵

4.4 代码

4.5 阈值对预测结果的影响


一、读取数据,先了解一下


  
  
  1. # 数据处理3大件
  2. import numpy as np
  3. import pandas as pd
  4. import matplotlib.pyplot as plt

  
  
  1. data=pd.read_csv( 'creditcard.csv')
  2. print(data.shape) #(284807, 31)
  3. print(data.describe())
  4. data.head() #和print(data.head()) 的效果不一样

1. 这个文件中,第一列是时间(独一无二,像主关键字),v1-v28是属性

2. Amount这一列的值和其他不太一样,可能需要预处理

3. class表示样本类别,0-正例,1-反例,正例反例的数目差异对预测十分重要

 

二、数据预处理

2.1  计算正常样本和异常样本的比例:pd.value_counts


  
  
  1. count_classes=pd.value_counts(data[ 'Class'],sort= 'True').sort_index()
  2. print(count_classes)
  3. count_classes.plot(kind= 'bar')
  4. plt.title( 'Fraud class histogram')
  5. plt.xlabel( 'class')
  6. plt.ylabel( 'frequency')

结论:正反例的数目很不均衡,训练的时候有两种方式,下采样(取同样少的正例)/过采样(让反例数目和反例一样多)

2.2 Amount 这列的数据标准化

    由于取值的大小对训练也是有影响的,所以有这个处理的必要,但是并不是说一定要标准化,有可能不标准化,反而更符合实际情况呢,这个是后话,我们接下来看一下应该要怎么样进行标准化。顺便把与建模没有关系的time那一列删掉。


  
  
  1. from sklearn.preprocessing import StandardScaler
  2. data[ 'normAmount']=StandardScaler().fit_transform(data[ 'Amount'].values.reshape( -1, 1))
  3. data=data.drop([ 'Time', 'Amount'],axis= 1)
  4. data.head()

     

注意:要在series后面加values.reshape(),否则会报错!原视频中的代码是没有的,这点注意一下

 

三、建立模型

3.1 下采样方式进行模型训练

1. 下采样,获得正反例数目均衡的样本,用作模型训练


  
  
  1. # 下采样:以浪费样本为代价
  2. # 如果不下采样,X-y如下:
  3. X=data.loc[:,data.columns != 'Class']
  4. y=data.loc[:,data.columns == 'Class']
  5. # 下采样
  6. number_records_fraud=len(data[data[ 'Class']== 1]) #计算异常样本的数目
  7. fraud_indices=np.array(data[data.Class== 1].index) #取出异常样本所在位置的索引值,<class 'numpy.ndarray'>
  8. normal_indices=data[data.Class== 0].index # 取出正常样本所在位置的索引值#<class 'pandas.core.indexes.numeric.Int64Index'>
  9. #从正常样本中随机取出异常样本数目的样本
  10. random_normal_indices=np.random.choice(normal_indices, number_records_fraud,replace= False)
  11. random_normal_indices=np.array(random_normal_indices) #转换成为ndarray类型,虽然我也不知道为什么中间有个过度的类型
  12. under_sample_indices=np.concatenate([fraud_indices,random_normal_indices]) #正常样本与异常样本所在索引
  13. under_sample_data=data.iloc[under_sample_indices,:] #通过索引取出训练样本
  14. X_under_sample=under_sample_data.iloc[:,under_sample_data.columns != 'Class'] #train_data
  15. Y_under_sample=under_sample_data.iloc[:,under_sample_data.columns == 'Class'] #train_target

2. 将数据分训练集、测试集


  
  
  1. # 构造训练集和测试集
  2. from sklearn.cross_validation import train_test_split
  3. # 为了对比下采样与不处理构建模型的差异
  4. X_train,X_test,y_train,y_test=train_test_split(X,y,test_size= 0.3,random_state= 0) #测试数据占30%,指定随机方式有利于复现
  5. X_train_undersample,X_tes_undersamplet,y_train_undersample,y_test_undersample=train_test_split(X_under_sample,Y_under_sample,test_size= 0.3,random_state= 0)

3. 实例化模型

(交叉验证-实例化模型-带入数据训练模型-评价模型(score))

     交叉验证还可以对比不同参数的效果,从而选出最合适的参数。本例中的c是正则化惩罚项,用途就是在recall_score差不多的情况下,选出更好的一组参数,这组参数的特点是浮动差异小,泛化能力更强,没那么容易过拟合。


  
  
  1. #使用逻辑回归进行建模操作
  2. from sklearn.linear_model import LogisticRegression
  3. from sklearn.cross_validation import KFold,cross_val_score
  4. from sklearn.metrics import confusion_matrix,recall_score,classification_report

  
  
  1. def print_kfold_scores(x_train_data, y_train_data):
  2. fold=KFold(len(y_train_data), 5,shuffle= False) #数据数目,交叉折叠次数5次,不进行洗牌
  3. c_param_range=[ 0.01, 0.1, 1, 10, 100] #待选的模型参数
  4. # 新建一个dataFrame类型(csv,就像一个表格),列名是参数取值、平均召回率
  5. result_table=pd.DataFrame(index=range(len(c_param_range), 2),columns=[ 'C_parameter', 'Mean recall score'])
  6. result_table[ 'C_parameter']=c_param_range
  7. j= 0
  8. for c_param in c_param_range: # 将待选参数一个一个进行模型训练,并分别计算对应的召回率
  9. print( '==========================')
  10. print( 'C parameter:',c_param)
  11. # print('C parameter:' + str(c_param))
  12. print( '--------------------------')
  13. recall_accs=[]
  14. for iteration,indices in enumerate(fold,start= 1): #和交叉验证有关
  15. lr=LogisticRegression(C=c_param,penalty= 'l1') #实例化逻辑回归模型
  16. lr.fit(x_train_data.iloc[indices[ 0],:],y_train_data.iloc[indices[ 0],:].values.ravel()) #将数据带入训练
  17. y_pred_undersample=lr.predict(x_train_data.iloc[indices[ 1],:].values) #预测结果
  18. recall_acc=recall_score(y_train_data.iloc[indices[ 1],:].values,y_pred_undersample) #召回率
  19. recall_accs.append(recall_acc)
  20. print( 'Iteration',iteration, ': recall score =',recall_acc) # 交叉验证的折叠次数为5,有5次小结果
  21. result_table.loc[j, 'Mean recall score']=np.mean(recall_accs) #计算该参数对应的平均召回率
  22. j+= 1
  23. print( '')
  24. print( 'Mean recall score',np.mean(recall_accs))
  25. print( '')
  26. best_c = result_table.iloc[result_table[ 'Mean recall score'].astype( 'float64').idxmax()][ 'C_parameter']
  27. print( '**************************************')
  28. print( 'best model to choose from cross validation is with C parameter = ',best_c)
  29. print( '**************************************')
  30. return best_c
  31. best_c=print_kfold_scores(X_train_undersample,y_train_undersample)

    注意:和学习视频中的代码有一些不同,best_c的求解那一行,如果不加上astype('float64')进行类型转换,会报错:reduction operation 'argmax' not allowed for this dtype

   结果:


  
  
  1. ==========================
  2. C parameter: 0.01
  3. --------------------------
  4. Iteration 1 : recall score = 0.958904109589041
  5. Iteration 2 : recall score = 0.9178082191780822
  6. Iteration 3 : recall score = 1.0
  7. Iteration 4 : recall score = 0.9594594594594594
  8. Iteration 5 : recall score = 0.9848484848484849
  9. Mean recall score 0.9642040546150135
  10. ==========================
  11. C parameter: 0.1
  12. --------------------------
  13. Iteration 1 : recall score = 0.8356164383561644
  14. Iteration 2 : recall score = 0.863013698630137
  15. Iteration 3 : recall score = 0.9491525423728814
  16. Iteration 4 : recall score = 0.9324324324324325
  17. Iteration 5 : recall score = 0.8939393939393939
  18. Mean recall score 0.8948309011462019
  19. ==========================
  20. C parameter: 1
  21. --------------------------
  22. Iteration 1 : recall score = 0.8493150684931506
  23. Iteration 2 : recall score = 0.8767123287671232
  24. Iteration 3 : recall score = 0.9661016949152542
  25. Iteration 4 : recall score = 0.9459459459459459
  26. Iteration 5 : recall score = 0.8939393939393939
  27. Mean recall score 0.9064028864121736
  28. ==========================
  29. C parameter: 10
  30. --------------------------
  31. Iteration 1 : recall score = 0.8493150684931506
  32. Iteration 2 : recall score = 0.8767123287671232
  33. Iteration 3 : recall score = 0.9661016949152542
  34. Iteration 4 : recall score = 0.9459459459459459
  35. Iteration 5 : recall score = 0.8787878787878788
  36. Mean recall score 0.9033725833818705
  37. ==========================
  38. C parameter: 100
  39. --------------------------
  40. Iteration 1 : recall score = 0.863013698630137
  41. Iteration 2 : recall score = 0.8767123287671232
  42. Iteration 3 : recall score = 0.9830508474576272
  43. Iteration 4 : recall score = 0.9459459459459459
  44. Iteration 5 : recall score = 0.8787878787878788
  45. Mean recall score 0.9095021399177424
  46. **************************************
  47. best model to choose from cross validation is with C parameter = 0.01
  48. **************************************

3.2 过采样方式创建模型

1. SMOTE算法原理

    过采样涉及数据生成操作,SMOTE算法原理:

(1)对于少数类中的每一个样本,计算它到少数类样本集中所有样本的欧氏距离,得到其k近邻。

(2)根据样本的不平衡比例设置一个采样比例以确定采样倍率N。对于每一个少数类样本x,从其k近邻中随机选择若干个样本,假设选择的近邻为xn。

(3)对每个随机选出的近邻xn,分别与原样本按如下公式构建新样本:x_{new}=x+rand(0,1)\times (x\tilde{~}-x)

2. 安装imblearn库:pip install imblearn

3. 程序


  
  
  1. from imblearn.over_sampling import SMOTE
  2. from sklearn.ensemble import RandomForestClassifier
  3. from sklearn.metrics import confusion_matrix
  4. from sklearn.model_selection import train_test_split
  5. # 读入文件,将数据分成features-labels两部分
  6. credit_cards=pd.read_csv( 'creditcard.csv')
  7. columns=credit_cards.columns
  8. features_columns=columns.delete(len(columns) -1) #将倒数第二列的class删去,剩下的就全是可用于训练的特征了
  9. features=credit_cards[features_columns] #将csv中除了class这列的其他数据全部取出,作为特征(为啥不直接用drop呢)
  10. labels=credit_cards[ 'Class']
  11. # 划分训练集、测试集
  12. features_train,features_test,labels_train,labels_test=train_test_split(features,labels,test_size= 0.2,random_state= 0)
  13. # 过采样
  14. oversample=SMOTE(random_state= 0) #算法实例化
  15. os_features,os_labels=oversample.fit_sample(features_train,labels_train) #参数带入
  16. #len(os_labels[os_labels==1])
  17. # 转换成能被逻辑回归模型接受的数据类型
  18. os_features=pd.DataFrame(os_features)
  19. os_labels=pd.DataFrame(os_labels)
  20. # 带入前面写好的逻辑回归模型
  21. best_c=print_kfold_scores(os_features,os_labels)

结果:由于现在的数据总量已经达到40w+,所以计算需要一定时间


  
  
  1. ==========================
  2. C parameter: 0.01
  3. --------------------------
  4. Iteration 1 : recall score = 0.8903225806451613
  5. Iteration 2 : recall score = 0.8947368421052632
  6. Iteration 3 : recall score = 0.968861347792409
  7. Iteration 4 : recall score = 0.9518031237291302
  8. Iteration 5 : recall score = 0.9584308811729921
  9. Mean recall score 0.9328309550889913
  10. ==========================
  11. C parameter: 0.1
  12. --------------------------
  13. Iteration 1 : recall score = 0.8903225806451613
  14. Iteration 2 : recall score = 0.8947368421052632
  15. Iteration 3 : recall score = 0.9703220095164324
  16. Iteration 4 : recall score = 0.9600575944427957
  17. Iteration 5 : recall score = 0.9605082379837548
  18. Mean recall score 0.9351894529386815
  19. ==========================
  20. C parameter: 1
  21. --------------------------
  22. Iteration 1 : recall score = 0.8903225806451613
  23. Iteration 2 : recall score = 0.8947368421052632
  24. Iteration 3 : recall score = 0.9701228283722474
  25. Iteration 4 : recall score = 0.9587496290434266
  26. Iteration 5 : recall score = 0.9603763423132302
  27. Mean recall score 0.9348616444958656
  28. ==========================
  29. C parameter: 10
  30. --------------------------
  31. Iteration 1 : recall score = 0.8903225806451613
  32. Iteration 2 : recall score = 0.8947368421052632
  33. Iteration 3 : recall score = 0.969768728560363
  34. Iteration 4 : recall score = 0.9603653510073532
  35. Iteration 5 : recall score = 0.9607720293248041
  36. Mean recall score 0.9351931063285889
  37. ==========================
  38. C parameter: 100
  39. --------------------------
  40. Iteration 1 : recall score = 0.8903225806451613
  41. Iteration 2 : recall score = 0.8947368421052632
  42. Iteration 3 : recall score = 0.970366271992918
  43. Iteration 4 : recall score = 0.9590903595256153
  44. Iteration 5 : recall score = 0.9598377683252547
  45. Mean recall score 0.9348707645188424
  46. **************************************
  47. best model to choose from cross validation is with C parameter = 10.0
  48. **************************************

四、模型评估方法

4.1 精度

    ——预测正确样本数(0-0,1-1)/所有样本数

4.2  召回率

(recall score)=TP/(TP+FN),具体含义见下表,一般作为检测类题目的评估标准

    简言之,就是实际筛选出来的/本应该筛选出来的

4.3 混淆矩阵:

  正类 负类
被检测到 TP:正类判断为正类 FP:负类判断为正类
未被检测到 FN:正类判断为负类 TN:负类判断为负类

4.4 代码


  
  
  1. # 混淆矩阵的可视化显示,以下代码可以直接作为模板
  2. import itertools
  3. def plot_confusion_matrix(cm, classes,
  4. title='Confusion matrix',
  5. cmap=plt.cm.Blues):
  6. """
  7. This function prints and plots the confusion matrix.
  8. """
  9. plt.imshow(cm, interpolation= 'nearest', cmap=cmap)
  10. plt.title(title)
  11. plt.colorbar()
  12. tick_marks = np.arange(len(classes))
  13. plt.xticks(tick_marks, classes, rotation= 0)
  14. plt.yticks(tick_marks, classes)
  15. thresh = cm.max() / 2.
  16. for i, j in itertools.product(range(cm.shape[ 0]), range(cm.shape[ 1])):
  17. plt.text(j, i, cm[i, j],
  18. horizontalalignment= "center",
  19. color= "white" if cm[i, j] > thresh else "black")
  20. plt.tight_layout()
  21. plt.ylabel( 'True label')
  22. plt.xlabel( 'Predicted label')

  
  
  1. # 过采样最佳参数构造的逻辑回归模型
  2. lr=LogisticRegression(C=best_c,penalty= 'l1')
  3. lr.fit(X_train,y_train.values.ravel())
  4. y_pred_oversample=lr.predict(X_test.values)
  5. #构造混淆矩阵
  6. cnf_matrix=confusion_matrix(y_test,y_pred_oversample)
  7. np.set_printoptions(precision= 2)
  8. print( 'recall metrix in the testing database:',cnf_matrix[ 1, 1]/(cnf_matrix[ 0, 1]+cnf_matrix[ 1, 1]))
  9. class_names=[ 0, 1]
  10. plt.figure()
  11. plot_confusion_matrix(cnf_matrix,classes=class_names,title= 'Confusion matrix')
  12. plt.show()

结果:这个是过采样的混淆矩阵,下采样差不多,就不赘述了

召回率:91/(91+56)

精度:(85284+91)/(85284+12+56+91)

4.5 阈值对预测结果的影响

    就是,当结果大于多少时,我们认为这是反例(本题中)


  
  
  1. # #阈值的影响
  2. # # 下采样最佳参数构造的逻辑回归模型(为了速度快一些)
  3. lr=LogisticRegression(C= 1,penalty= 'l1')
  4. lr.fit(X_train_undersample,y_train_undersample.values.ravel())
  5. y_pred_undersample_proba=lr.predict_proba(X_tes_undersamplet.values)
  6. threshold=[ 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
  7. plt.figure(figsize=( 10, 10))
  8. j= 1
  9. for i in threshold:
  10. y_test_pred_high_recall=y_pred_undersample_proba[:, 1]>i
  11. plt.subplot( 3, 3,j)
  12. j+= 1
  13. cnf_matrix = confusion_matrix(y_test_undersample, y_test_pred_high_recall)
  14. np.set_printoptions(precision= 2)
  15. print( 'recall metrix in the testing database:', cnf_matrix[ 1, 1] / (cnf_matrix[ 0, 1] + cnf_matrix[ 1, 1]))
  16. class_names = [ 0, 1]
  17. plot_confusion_matrix(cnf_matrix, classes=class_names, title= 'Threshold>%s'%i)

结果:

    逻辑回归是一种经典的二分类算法,一般拿到分类任务时,会先用逻辑回归来试一下。

猜你喜欢

转载自blog.csdn.net/weixin_43455338/article/details/86529561