机器学习案例-信用卡诈骗识别。

数据简介

本次数据为欧洲的信用卡的持卡人在2013年9月某两天的交易数据,由于涉及到数据的敏感性问题其中V1~V28的变量都是进行了主成分分析后合成的脱敏的数据。
变量名称介绍
在这里插入图片描述

数据预处理

导入数据及数据初步展示

data <- read.csv("creditcard.csv")
head(data)

#导入数据还可以使用reader包中的read_csv()函数,它可以显示导入数据的进度。

library(readr)
data <- read_csv("creditcard.csv")
#把数据转换为数据框格式
data <- as.data.frame(data)
> #查看数据的基本结构和类型
> str(data)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':	284807 obs. of  31 variables:
 $ Time  : num  0 0 1 1 2 2 4 7 7 9 ...
 $ V1    : num  -1.36 1.192 -1.358 -0.966 -1.158 ...
 $ V2    : num  -0.0728 0.2662 -1.3402 -0.1852 0.8777 ...
 $ V3    : num  2.536 0.166 1.773 1.793 1.549 ...
 $ V4    : num  1.378 0.448 0.38 -0.863 0.403 ...
 $ V5    : num  -0.3383 0.06 -0.5032 -0.0103 -0.4072 ...
 $ V6    : num  0.4624 -0.0824 1.8005 1.2472 0.0959 ...
 $ V7    : num  0.2396 -0.0788 0.7915 0.2376 0.5929 ...
 $ V8    : num  0.0987 0.0851 0.2477 0.3774 -0.2705 ...
 $ V9    : num  0.364 -0.255 -1.515 -1.387 0.818 ...
 $ V10   : num  0.0908 -0.167 0.2076 -0.055 0.7531 ...
 $ V11   : num  -0.552 1.613 0.625 -0.226 -0.823 ...
 $ V12   : num  -0.6178 1.0652 0.0661 0.1782 0.5382 ...
 $ V13   : num  -0.991 0.489 0.717 0.508 1.346 ...
 $ V14   : num  -0.311 -0.144 -0.166 -0.288 -1.12 ...
 $ V15   : num  1.468 0.636 2.346 -0.631 0.175 ...
 $ V16   : num  -0.47 0.464 -2.89 -1.06 -0.451 ...
 $ V17   : num  0.208 -0.115 1.11 -0.684 -0.237 ...
 $ V18   : num  0.0258 -0.1834 -0.1214 1.9658 -0.0382 ...
 $ V19   : num  0.404 -0.146 -2.262 -1.233 0.803 ...
 $ V20   : num  0.2514 -0.0691 0.525 -0.208 0.4085 ...
 $ V21   : num  -0.01831 -0.22578 0.248 -0.1083 -0.00943 ...
 $ V22   : num  0.27784 -0.63867 0.77168 0.00527 0.79828 ...
 $ V23   : num  -0.11 0.101 0.909 -0.19 -0.137 ...
 $ V24   : num  0.0669 -0.3398 -0.6893 -1.1756 0.1413 ...
 $ V25   : num  0.129 0.167 -0.328 0.647 -0.206 ...
 $ V26   : num  -0.189 0.126 -0.139 -0.222 0.502 ...
 $ V27   : num  0.13356 -0.00898 -0.05535 0.06272 0.21942 ...
 $ V28   : num  -0.0211 0.0147 -0.0598 0.0615 0.2152 ...
 $ Amount: num  149.62 2.69 378.66 123.5 69.99 ...
 $ Class : num  0 0 0 0 0 0 0 0 0 0 ...
 - attr(*, "spec")=
  .. cols(
  ..   Time = col_double(),
  ..   V1 = col_double(),
  ..   V2 = col_double(),
  ..   V3 = col_double(),
  ..   V4 = col_double(),
  ..   V5 = col_double(),
  ..   V6 = col_double(),
  ..   V7 = col_double(),
  ..   V8 = col_double(),
  ..   V9 = col_double(),
  ..   V10 = col_double(),
  ..   V11 = col_double(),
  ..   V12 = col_double(),
  ..   V13 = col_double(),
  ..   V14 = col_double(),
  ..   V15 = col_double(),
  ..   V16 = col_double(),
  ..   V17 = col_double(),
  ..   V18 = col_double(),
  ..   V19 = col_double(),
  ..   V20 = col_double(),
  ..   V21 = col_double(),
  ..   V22 = col_double(),
  ..   V23 = col_double(),
  ..   V24 = col_double(),
  ..   V25 = col_double(),
  ..   V26 = col_double(),
  ..   V27 = col_double(),
  ..   V28 = col_double(),
  ..   Amount = col_double(),
  ..   Class = col_double()
  .. )
> summary(data)
      Time              V1                  V2                  V3                 V4                 V5                   V6          
 Min.   :     0   Min.   :-56.40751   Min.   :-72.71573   Min.   :-48.3256   Min.   :-5.68317   Min.   :-113.74331   Min.   :-26.1605  
 1st Qu.: 54202   1st Qu.: -0.92037   1st Qu.: -0.59855   1st Qu.: -0.8904   1st Qu.:-0.84864   1st Qu.:  -0.69160   1st Qu.: -0.7683  
 Median : 84692   Median :  0.01811   Median :  0.06549   Median :  0.1799   Median :-0.01985   Median :  -0.05434   Median : -0.2742  
 Mean   : 94814   Mean   :  0.00000   Mean   :  0.00000   Mean   :  0.0000   Mean   : 0.00000   Mean   :   0.00000   Mean   :  0.0000  
 3rd Qu.:139321   3rd Qu.:  1.31564   3rd Qu.:  0.80372   3rd Qu.:  1.0272   3rd Qu.: 0.74334   3rd Qu.:   0.61193   3rd Qu.:  0.3986  
 Max.   :172792   Max.   :  2.45493   Max.   : 22.05773   Max.   :  9.3826   Max.   :16.87534   Max.   :  34.80167   Max.   : 73.3016  
       V7                 V8                  V9                 V10                 V11                V12                V13          
 Min.   :-43.5572   Min.   :-73.21672   Min.   :-13.43407   Min.   :-24.58826   Min.   :-4.79747   Min.   :-18.6837   Min.   :-5.79188  
 1st Qu.: -0.5541   1st Qu.: -0.20863   1st Qu.: -0.64310   1st Qu.: -0.53543   1st Qu.:-0.76249   1st Qu.: -0.4056   1st Qu.:-0.64854  
 Median :  0.0401   Median :  0.02236   Median : -0.05143   Median : -0.09292   Median :-0.03276   Median :  0.1400   Median :-0.01357  
 Mean   :  0.0000   Mean   :  0.00000   Mean   :  0.00000   Mean   :  0.00000   Mean   : 0.00000   Mean   :  0.0000   Mean   : 0.00000  
 3rd Qu.:  0.5704   3rd Qu.:  0.32735   3rd Qu.:  0.59714   3rd Qu.:  0.45392   3rd Qu.: 0.73959   3rd Qu.:  0.6182   3rd Qu.: 0.66251  
 Max.   :120.5895   Max.   : 20.00721   Max.   : 15.59500   Max.   : 23.74514   Max.   :12.01891   Max.   :  7.8484   Max.   : 7.12688  
      V14                V15                V16                 V17                 V18                 V19                 V20           
 Min.   :-19.2143   Min.   :-4.49894   Min.   :-14.12985   Min.   :-25.16280   Min.   :-9.498746   Min.   :-7.213527   Min.   :-54.49772  
 1st Qu.: -0.4256   1st Qu.:-0.58288   1st Qu.: -0.46804   1st Qu.: -0.48375   1st Qu.:-0.498850   1st Qu.:-0.456299   1st Qu.: -0.21172  
 Median :  0.0506   Median : 0.04807   Median :  0.06641   Median : -0.06568   Median :-0.003636   Median : 0.003735   Median : -0.06248  
 Mean   :  0.0000   Mean   : 0.00000   Mean   :  0.00000   Mean   :  0.00000   Mean   : 0.000000   Mean   : 0.000000   Mean   :  0.00000  
 3rd Qu.:  0.4931   3rd Qu.: 0.64882   3rd Qu.:  0.52330   3rd Qu.:  0.39968   3rd Qu.: 0.500807   3rd Qu.: 0.458949   3rd Qu.:  0.13304  
 Max.   : 10.5268   Max.   : 8.87774   Max.   : 17.31511   Max.   :  9.25353   Max.   : 5.041069   Max.   : 5.591971   Max.   : 39.42090  
      V21                 V22                  V23                 V24                V25                 V26          
 Min.   :-34.83038   Min.   :-10.933144   Min.   :-44.80774   Min.   :-2.83663   Min.   :-10.29540   Min.   :-2.60455  
 1st Qu.: -0.22839   1st Qu.: -0.542350   1st Qu.: -0.16185   1st Qu.:-0.35459   1st Qu.: -0.31715   1st Qu.:-0.32698  
 Median : -0.02945   Median :  0.006782   Median : -0.01119   Median : 0.04098   Median :  0.01659   Median :-0.05214  
 Mean   :  0.00000   Mean   :  0.000000   Mean   :  0.00000   Mean   : 0.00000   Mean   :  0.00000   Mean   : 0.00000  
 3rd Qu.:  0.18638   3rd Qu.:  0.528554   3rd Qu.:  0.14764   3rd Qu.: 0.43953   3rd Qu.:  0.35072   3rd Qu.: 0.24095  
 Max.   : 27.20284   Max.   : 10.503090   Max.   : 22.52841   Max.   : 4.58455   Max.   :  7.51959   Max.   : 3.51735  
      V27                  V28                Amount             Class         
 Min.   :-22.565679   Min.   :-15.43008   Min.   :    0.00   Min.   :0.000000  
 1st Qu.: -0.070840   1st Qu.: -0.05296   1st Qu.:    5.60   1st Qu.:0.000000  
 Median :  0.001342   Median :  0.01124   Median :   22.00   Median :0.000000  
 Mean   :  0.000000   Mean   :  0.00000   Mean   :   88.35   Mean   :0.001728  
 3rd Qu.:  0.091045   3rd Qu.:  0.07828   3rd Qu.:   77.17   3rd Qu.:0.000000  
 Max.   : 31.612198   Max.   : 33.84781   Max.   :25691.16   Max.   :1.000000  
> #查看样本类别比例
> table(data$Class)

     0      1 
284315    492 
> prop.table(table(data$Class))

          0           1 
0.998272514 0.001727486 

缺失值识别

 #可视化展示缺失值情况
> #使用VIM包中的aggr函数画出缺失值的图
> library(VIM)
> aggr(data,prop=F,number=T)
> sum(!complete.cases(data))
[1] 0

在这里插入图片描述
从缺失值图形及缺失值计算结果看均为没有缺失值所以不需要处理。

分层抽样

处理类别不平衡问题
由于数据中类别为诈骗数据和非诈骗数据的样本数差距过大,会影响建模的准确性。
所以我们从类别为诈骗的样本数据中抽取和非诈骗数据的样本数一样的样本,然后合并在一起组成一个新的样本。
这样在新的样本中诈骗数据和非诈骗数据就一致了。这样就解决了类别不平衡的问题了。

#把时间这一列转换为小时
data$Time_Hour <- round(data$Time/3600,0)
#把class列转换为因子型
data$Class <- as.factor(data$Class)

#筛选出类别为诈骗的样本
data_1 <- data[data$Class==1,]
#筛选出类别为非诈骗的样本
data_0 <- data[data$Class==0,]

##随机抽样与诈骗样本个数相同的非诈骗样本,然后合并成新数据
#设定随机种子
set.seed(1234)
#从非诈骗数据中抽取与诈骗数据个数相同的非诈骗样本
index <- sample(1:length(rownames(data_0)),length(row.names(data_1)))
#合并成新数据
data_0_new <- data_0[index,]

data_end <- rbind(data_1,data_0_new)

#剔除Time 列,用Time_hour列代替,并且把Time_hour列放在第一列

data_end <- data.frame(data_end$Time_Hour,data_end[,2:31])

#变量的重命名
library(plyr)
data_end <- rename(data_end,c("data_end.Time_Hour"="Time_Hour"))

> #按照类别进行分层抽样,建立训练集和测试集
> set.seed(1234)
> index2 <- sample(1:nrow(data_end),0.8*nrow(data_end))
> train <- data_end[index2,]
> test <- data_end[-index2,]
> table(train$Class)

  0   1 
397 390 
> table(test$Class)

  0   1 
 95 102

数据的标准化

#使用函数scale进行数据的标准化
#scale的原理为每一列数据减去此列的平均值然后再除去标准差
#如果是只是减去列的平均值的话就是数据的中心话
#对data_end数据进行标准化处理
data_s <- data_end
data_s[,1:30] <- scale(data_s[,1:30])
#对train数据进行标准化处理
train2 <- train
train2[,1:30] <- scale(train2[,1:30])

#对test数据进行标准化处理
test2 <- test
test2[,1:30] <- scale(test2[,1:30])

描述性分析

绘制不同时间诈骗次数的条形图

library(ggplot2)
#把Time_Hour列转换为因子
data_1$Time_Hour <- as.factor(data_1$Time_Hour)

ggplot(data_1,aes(Time_Hour,fill=Time_Hour)) +
  geom_bar()+
  theme_minimal()+
  theme(legend.position="none")

在这里插入图片描述
从图中可以发现诈骗最多的时候大多集中在凌晨的2点和上午的11点左右

绘制不同时间诈骗金额的箱线图

#绘制不同时间诈骗金额的箱线图
ggplot(data_1,aes(Time_Hour,Amount,fill=Time_Hour))+
  geom_boxplot()+
  theme_minimal()+
  theme(legend.position = "none")

在这里插入图片描述
整体而言诈骗金额平均为125左右,但是诈骗金额波动性比较大,最大的有2000多。

绘制不同时间诈骗金额的条形图

#绘制不同时间诈骗金额的条形图
Time_Amount <- aggregate(data_1$Amount,by=list(Time = data_1$Time_Hour),mean)

ggplot(Time_Amount,aes(Time,x,fill=Time))+
  geom_bar(stat = "identity")+
  theme_minimal()+
  theme(legend.position="none")

在这里插入图片描述
平均诈骗金额最高的是在第二天的12点,整体而言平均诈骗金额分布在125左右。

自动参数调整

使用caret包进行自动参数调整
参数调整是提升模型性能的一个重要过程,大多数机器学习算法都至少调整一个参数,而大多数复杂的模型都可以调整多个参数值来调整模型从而进行更好的拟合。
例如,寻找更适合的K值来调整K近邻模型,调节隐层层数和隐藏层的节点数等优化神经网络模型,支持向量机模型中调整核函数,“软边界”惩罚大小等进行优化。
虽然这可以让模型更适合数据,但是尝试所有可能的选项会非常复杂,所以需要一种更系统的方式。

在这里插入图片描述

使用iris数据介绍caret包中的自动调整参数的功能

> #自动参数调整
> #使用caret包进行自动参数调整
> #举例
> #使用决策树模型对iris数据进行建模,
> #使用caret包中的train函数进行建模并进行自动参数调整
> 
> library(caret)
> set.seed(1234)
> m_C50 <- train(Species~., data=iris,method='C5.0')
There were 40 warnings (use warnings() to see them)
> m_C50
C5.0 

150 samples
  4 predictor
  3 classes: 'setosa', 'versicolor', 'virginica' 

No pre-processing
Resampling: Bootstrapped (25 reps) 
Summary of sample sizes: 150, 150, 150, 150, 150, 150, ... 
Resampling results across tuning parameters:

  model  winnow  trials  Accuracy   Kappa    
  rules  FALSE    1      0.9353579  0.9019696
  rules  FALSE   10      0.9370844  0.9045424
  rules  FALSE   20      0.9325835  0.8976068
  rules   TRUE    1      0.9382311  0.9062975
  rules   TRUE   10      0.9407392  0.9099910
  rules   TRUE   20      0.9385430  0.9066136
  tree   FALSE    1      0.9347127  0.9009924
  tree   FALSE   10      0.9369888  0.9044013
  tree   FALSE   20      0.9332286  0.8985820
  tree    TRUE    1      0.9375860  0.9053246
  tree    TRUE   10      0.9399845  0.9088007
  tree    TRUE   20      0.9392443  0.9076915

Accuracy was used to select the optimal model using the
 largest value.
The final values used for the model were trials = 10, model =
 rules and winnow = TRUE.

结果中包含候选模型的评估列表,可以发现共建立并测试了12个模型,基于3个C5.0调整参数的组合:model, trials和winnow。每个候选模型都给出了模型精度和Kappa统计量,最下方还展示了最佳后选模型所对应的参数值。
Kappa用来统计衡量模型的稳定性
很差的一致性: <0.2
尚可的一致性: 0.2~0.4
中等的一致性: 0.4~0.6
不错的一致性: 0.6~0.8
很好的饿一致性:0.8~1

定制调参数
定制调参需要时通过设置train中trControl及trGrid两个参数进行定制的。而设置这两个参数需要分别用到trainControl函数及expand.grid函数进行设置,参数trControl主要用来设置重抽样的方法例如设置使用五折交叉验证的方法,trGrid是用来指定可以调整哪些参数及调整的范围。

#定制调整参数
> #trainControl这个函数是为了设置train函数重采样的方式,例如这里就是使用五折交叉验证的方法
> trControl <- trainControl(method = 'cv',number = 5,selectionFunction = 'oneSE')
> #expand.grid是用来设置需要调整的参数及调整的范围,结果用在train函数中
> grid <- expand.grid(.model='tree',
+                     .trials = c(1,3,5),
+                     .winnow='FALSE')
> set.seed(1234)
> 
> m_C502 <- train(Species~., data=iris, method="C5.0",
+                 trControl=trControl,
+                 tuneGrid=grid)
Warning message:
In Ops.factor(x$winnow) : ‘!’ not meaningful for factors
> m_C502
C5.0 

150 samples
  4 predictor
  3 classes: 'setosa', 'versicolor', 'virginica' 

No pre-processing
Resampling: Cross-Validated (5 fold) 
Summary of sample sizes: 120, 120, 120, 120, 120 
Resampling results across tuning parameters:

  trials  Accuracy   Kappa
  1       0.9266667  0.89 
  3       0.9333333  0.90 
  5       0.9333333  0.90 

Tuning parameter 'model' was held constant at a value of tree
Tuning parameter 'winnow' was held constant at a value of FALSE
Accuracy was used to select the optimal model using  the one SE rule.
The final values used for the model were trials = 1, model = tree and winnow = FALSE.
> 

定制调参的过程
trainControl()函数用来创建一系列的配置选项,这些选项考虑到了诸如重抽样策略以及用于选择最佳模型的度量这些模型评价标准的管理。以上我们专注于两个主要参数:method和selectionFunction.
以上我们使用的是五折交叉验证的重抽样方法;
selectionFuncton参数可以设定一函数用来在各个候选者中选择特定的模型,共三个函数:
best函数简单地选择具有最好的某特定度量值的候选者,默认选项
oneSE函数选择最好性能标准差之内的最简单的候选者
Tolerance选择某个用户指定比例之内的最简单的候选者
train函数的介绍可以参考我的另一个文章
caret包介绍学习之train函数介绍

建模预测之随机森立

使用随机森立进行分建模并进行预测

 # 建模与预测之随机森立 --------------------------------------------------------------
> 
> #使用5折交叉验证的方法建立随机森林模型,并选取在最好性能标准差之内最简单的模型
> model_rf <- train(Class~.,data=train,mothed='rf', trControl=trainControl(method = 'cv',number = 5,selectionFunction = "oneSE"))
> model_rf
Random Forest 

787 samples
 30 predictor
  2 classes: '0', '1' 

No pre-processing
Resampling: Cross-Validated (5 fold) 
Summary of sample sizes: 629, 630, 630, 629, 630 
Resampling results across tuning parameters:

  mtry  Accuracy   Kappa    
   2    0.9427961  0.8855125
  16    0.9364589  0.8728728
  30    0.9402725  0.8805043

Accuracy was used to select the optimal model using  the one SE rule.
The final value used for the model was mtry = 2.
> 
> #使用模型对test数据集进行预测
> pre <- predict(model_rf,test)
> 
> #使用混淆矩阵查看预测效果
> table(pre,test$Class)
   
pre  0  1
  0 88 13
  1  7 89
> 
> #查看各个变量对于模型的重要性
> plot(varImp(model_rf))
> 

在这里插入图片描述

建模预测之KNN算法

首先介绍关于KNN算法的介绍可以参考文章:
深入浅出KNN算法(一) KNN算法原理

# 建模与预测之KNN建模 -------------------------------------------------------------
#调用knn的包class
library(class)

#knn预测
#Knn用的数据需要进行标准化,因为计算的是距离,所以需要消除量纲对距离的影响。
results=c()
for (i in 1:10) {
  pred_knn <- knn(train2[-31],test2[-31],train2$Class,i)
  Table <- table(pred_knn,test$Class)
  acc <- sum(diag(Table))/sum(Table)
  results <- c(results,acc)
  
}

plot(1:10,results,type="h",col="red",xlab="K值",ylab="准确率",pch=20)
text(1:10,results,labels = round(results,2),pos = 3)

在这里插入图片描述

> #结果显示K为3时模型准确率最高
> 
> #建立模型
> #train:训练集(去除目标变量)
> #test: 测试集(去除目标变量)
> #cl:训练集的目标变量
> #k:邻居的数量
> pred_knn <- knn(train = train2[-31],test=test2[-31],
+                 cl=train2$Class,k=3)
> table(pred_knn,test$Class)
        
pred_knn  0  1
       0 91 12
       1  4 90
> 

模型评估

# 模型评估 --------------------------------------------------------------------
> 
> 
> #计算kappa值
> A <- as.matrix(table(pred_knn,test$Class))
> A
        
pred_knn  0  1
       0 91 12
       1  4 90
> x <- sum(diag(A))/sum(A)
> x
[1] 0.9187817
> 
> y <- (sum(A[1,])*sum(A[,1]) + sum(A[2,])*sum(A[,2]))/(sum(A)*sum(A))
> y
[1] 0.4991883
> 
> kappa <- (x-y)/(1-y)
> 
> 
> 
>   
> kappa <- function(pre,class){
+   A <- as.matrix(table(pre,class))
+   
+   x <- sum(diag(A))/sum(A)
+   
+   
+   y <- (sum(A[1,])*sum(A[,1]) + sum(A[2,])*sum(A[,2]))/(sum(A)*sum(A))
+   
+   
+   k <- (x-y)/(1-y)
+   return(k)
+ }
> 
> #计算准确率,查全率,及kappa值
> 
> A <- as.matrix(table(pre,test$Class))
> A
   
pre  0  1
  0 88 13
  1  7 89
> P_zq <- sum(diag(A))/sum(A)
> P_zq 
[1] 0.8984772
> 
> p_cq <- A[2,2]/sum(A[,2])
> 
> k <- kappa(pre,test$Class)
> results_rf <- c(P_zq,p_cq,k)
> names(results_rf) <- c("准确率","查全率","kappa值")
> results_rf
   准确率    查全率   kappa值 
0.8984772 0.8725490 0.7971373 
> 
> A <- as.matrix(table(pred_knn,test$Class))
> A
        
pred_knn  0  1
       0 91 12
       1  4 90
> P_zq <- sum(diag(A))/sum(A)
> P_zq 
[1] 0.9187817
> 
> p_cq <- A[2,2]/sum(A[,2])
> 
> k <- kappa(pre,test$Class)
> results_knn <- c(P_zq,p_cq,k)
> names(results_knn) <- c("准确率","查全率","kappa值")
> results_knn
   准确率    查全率   kappa值 
0.9187817 0.8823529 0.7971373 
> 
> #从结果看knn的模型的准确率及查全率都要高一些所以knn模型的效果更好。
> 

Guess you like

Origin blog.csdn.net/weixin_42712867/article/details/105319077