特征如下:
Time
Number of seconds elapsed between each transaction (over two days)
numeric
V1
No description provided
numeric
V2
No description provided
numeric
V3
No description provided
numeric
V4
No description provided
numeric
V5
No description provided
numeric
V6
No description provided
numeric
V7
No description provided
numeric
V8
No description provided
numeric
V9
No description provided
numeric
V10
No description provided
numeric
V11
No description provided
numeric
V12
No description provided
numeric
V13
No description provided
numeric
V14
No description provided
numeric
V15
No description provided
numeric
V16
No description provided
numeric
V17
No description provided
numeric
V18
No description provided
numeric
V19
No description provided
numeric
V20
No description provided
numeric
V21
No description provided
numeric
V22
No description provided
numeric
V23
No description provided
numeric
V24
No description provided
numeric
V25
No description provided
numeric
V26
No description provided
numeric
V27
No description provided
numeric
V28
abc
numeric
Amount
Amount of money for this transaction
numeric
Class
Fraud or Not-Fraud
boolean
只有Amount没有做标准化处理(mean不为0!!!):见:https://www.kaggle.com/mlg-ulb/creditcardfraud/data
from:https://www.kaggle.com/nikitaivanov/getting-high-sensitivity-for-imbalanced-data 主要使用了smote和聚类两种思路!
In this notebook we will try to predict fraud transactions from a given data set. Given that the data is imbalanced, standard metrics for evaluating classification algorithm (such as accuracy) are invalid. We will focus on the following metrics: Sensitivity (true positive rate) and Specificity (true negative rate). Of course, they are dependent on each other, so we want to find optimal trade-off between them. Such trade-off usually depends on the application of the algorithm, and in case of fraud detection I would prefer to see high sensitivity (e.g. given that a transaction is fraud, I want to be able to detect it with high probability).
For dealing with skewed data I am going to use SMOTE algorithm. In two words, the idea is to create synthetic samples (in opposite to oversampling with replacement) through finding nearest examples (KNN), calculating difference between them, multiplying this difference by a random number between 0 and 1 and adding the result to the initial sample. For this purpose we are going to use SMOTE
function from DMwR
package.
Algorithms I am going to implement are Support Vector Machine (SVM), Logistic regression and Random Forest. Models will be trained on the original and SMOTEd data and their performance will be measured on the entire data set.
As a bonus, we are going to have some fun and use K-means centroids of the negative examples together with the original positive examples as a new dataset and train our algorithm on it. We then compare results.
##Loading required packeges
library(ggplot2) #visualization
library(caret) #train model
library(dplyr) #data manipulation
library(kernlab) #svm
library(nnet) #models (logit, neural nets)
library(DMwR) #SMOTE data
##Load data
d = read.csv("../input/creditcard.csv")
n = ncol(d)
str(d)
d$Class = ifelse(d$Class == 0, 'No', 'Yes') %>% as.factor()
Loading required package: lattice
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
Attaching package: ‘kernlab’
The following object is masked from ‘package:ggplot2’:
alpha
Loading required package: grid
'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 : int 0 0 0 0 0 0 0 0 0 0 …
It is always a good idea first to plot a response variable to check for skewness in data:
qplot(x = d$Class, geom = 'bar') + xlab('Fraud (Yes/No)') + ylab('Number of transactions')
Keeping in mind that the data is highly skewed we proceed. First split the data into training and test sets.
idx = createDataPartition(d$Class, p = 0.7, list = F)
d[, -n] = scale(d[, -n]) #perform scaling
train = d[idx, ]
test = d[-idx, ]
Calculate baseline accuracy for future reference
blacc = nrow(d[d$Class == 'No', ])/nrow(d)*100
cat('Baseline accuracy:', blacc)
Baseline accuracy: 99.82725
To begin with, let's train our models on the original dataset to see what we get if use unbalanced data. Due to computational limitations of my laptop, I will only run logistic regression for this purpose.
m1 = multinom(data = train, Class ~ .)
p1 = predict(m1, test[, -n], type = 'class')
cat(' Accuracy of the model', mean(p1 == test[, n])*100, '\n', 'Baseline accuracy', blacc)
# weights: 32 (31 variable)
initial value 138189.980799
final value 31315.159746
converged
Accuracy of the model 99.92744
Baseline accuracy 99.82725
Though accuracy (99.92%) of the model might look impressive at a first glance, in fact it isn't. Simply predicting 'not a fraud' for all transactions will give 99.83% accuracy. To really evaluate model's perfomance we need to check confusion matrix.
confusionMatrix(p1, test[, n], positive = 'Yes')
Confusion Matrix and Statistics
Reference
Prediction No Yes
No 85287 55
Yes 7 92
Accuracy : 0.9993
95% CI : (0.9991, 0.9994)
No Information Rate : 0.9983
P-Value \[Acc > NIR\] : 1.779e-15
Kappa : 0.7476
Mcnemar's Test P-Value : 2.387e-09
Sensitivity : 0.625850
Specificity : 0.999918
Pos Pred Value : 0.929293
Neg Pred Value : 0.999356
Prevalence : 0.001720
Detection Rate : 0.001077
Detection Prevalence : 0.001159
Balanced Accuracy : 0.812884
'Positive' Class : Yes
From the confusion matrix we see that while model has high accuracy (99.92%) and high specificity (99.98%), it has low sensitivity of 64%. In other words, only 64% of all fraudulent transactions were detected.
Now let's preprocess our data using SMOTE algorithm:
table(d$Class) #check initial distribution
newData <- SMOTE(Class ~ ., d, perc.over = 500,perc.under=100)
table(newData$Class) #check SMOTed distribution
No Yes
284315 492
No Yes
2460 2952
To train SVM (with RBF kernel) we are going to use train
function from caret
package. It allows to choose optimal parameters of the model (cost and sigma in this case). Cost refers to penalty for misclassifying examples and sigma is a parameter of RBF which measures similarity between examples. To choose best model we use 5-fold cross-validation. We then evaluate our model on the entire data set.
gr = expand.grid(C = c(1, 50, 150), sigma = c(0.01, 0.05, 1))
tr = trainControl(method = 'cv', number = 5)
m2 = train(data = newData, Class ~ ., method = 'svmRadial', trControl = tr, tuneGrid = gr)
m2
Support Vector Machines with Radial Basis Function Kernel
5412 samples
30 predictor
2 classes: 'No', 'Yes'
No pre-processing
Resampling: Cross-Validated (5 fold)
Summary of sample sizes: 4330, 4329, 4329, 4330, 4330
Resampling results across tuning parameters:
C sigma Accuracy Kappa
1 0.01 0.9445668 0.8891865
1 0.05 0.9626774 0.9250408
1 1.00 0.9672934 0.9344234
50 0.01 0.9717300 0.9430408
50 0.05 0.9863262 0.9723782
50 1.00 0.9695108 0.9388440
150 0.01 0.9789351 0.9574955
150 0.05 0.9850335 0.9697552
150 1.00 0.9695108 0.9388440
Accuracy was used to select the optimal model using the largest value.
The final values used for the model were sigma = 0.05 and C = 50.
As wee see, best tuning parameters are C = 50 and sigma = 0.05
Let's look at a confusion matrix
p2 = predict(m2, d[, -n])
confusionMatrix(p2, d[, n], positive = 'Yes')
Confusion Matrix and Statistics
Reference
Prediction No Yes
No 278470 2
Yes 5845 490
Accuracy : 0.9795
95% CI : (0.9789, 0.98)
No Information Rate : 0.9983
P-Value \[Acc > NIR\] : 1
Kappa : 0.1408
Mcnemar's Test P-Value : <2e-16
Sensitivity : 0.995935
Specificity : 0.979442
Pos Pred Value : 0.077348
Neg Pred Value : 0.999993
Prevalence : 0.001727
Detection Rate : 0.001720
Detection Prevalence : 0.022243
Balanced Accuracy : 0.987688
'Positive' Class : Yes
(Numbers may differ due to randomness of k-fold cv)
As expected we were able to achieve sensitivity of 99.59%. In other words, out of all fraudulent transactions we correctly detected 99.59% of them. This came in price of slightly lower accuracy (in comparison to the first model) - 97.95% vs. 99.92% and lower specificity 97.94% vs. 99.98%. The main disadvantage is low level of positive predicted value (i.e. given that prediction is positive, what is probability that the true state is positive) which this case is 7.74% vs. 85% for initial (unbalanced dataset) model. As was mentioned in the beginning, one should choose a model that matches certain goals. If the goal is to correctly identify fraudulent transactions even in price of low positive predicted value (which I believe the case), then the latter model (based on SMOTed data) should be used. Looking at confusion matrix we see that almost all fraudulent transactions were correctly identified and only 2.5% were mislabeled as fraudulent.
I'm planning to try couple more models and also use more sophisticated algorithm that uses K-means centroids of the majority class as samples for non fraudulent transactions.
m3 = randomForest(data = newData, Class ~ .)
p3 = predict(m3, d[, -n])
confusionMatrix(p3, d[, n], positive = 'Yes')
Error in eval(expr, envir, enclos): could not find function "randomForest"
Traceback:
library(randomForest)
m3 = randomForest(data = newData, Class ~ .)
p3 = predict(m3, d[, -n])
confusionMatrix(p3, d[, n], positive = 'Yes')
randomForest 4.6-12
Type rfNews() to see new features/changes/bug fixes.
Attaching package: ‘randomForest’
The following object is masked from ‘package:dplyr’:
combine
The following object is masked from ‘package:ggplot2’:
margin
Confusion Matrix and Statistics
Reference
Prediction No Yes
No 282105 0
Yes 2210 492
Accuracy : 0.9922
95% CI : (0.9919, 0.9926)
No Information Rate : 0.9983
P-Value \[Acc > NIR\] : 1
Kappa : 0.306
Mcnemar's Test P-Value : <2e-16
Sensitivity : 1.000000
Specificity : 0.992227
Pos Pred Value : 0.182087
Neg Pred Value : 1.000000
Prevalence : 0.001727
Detection Rate : 0.001727
Detection Prevalence : 0.009487
Balanced Accuracy : 0.996113
'Positive' Class : Yes
Random forest performs really well. Sensitivity 100% and high specificity (more than 99%). All fraudulent transactions were detected and less than 1% of all transactions were falsely classified as fraud. Hence, Random Forest + SMOTE algorithm shloud be considered as final model.
For curiosity, let's take another approach in dealing with imbalanced data. We are going to separate the examples for positive and negative and from the latter one extract centroids (generated using K-means clustering). Number of clusters will be equal to the number of positive examples. We then use these centroids together with positive examples as a new sample.(思路就是聚类,将major class聚类为k个点,其中k为欺诈信用卡的样本数!)
neg = d[d$Class == 'No', ] #negative examples
pos = d[d$Class == 'Yes', ] #positive examples
n_pos = sum(d$Class == 'Yes') #calculate number of positive examples
clus = kmeans(neg[, -n], centers = n_pos, iter.max = 100) #perform K-means
neg = as.data.frame(clus$centers) #extract centroids as new sample
neg$Class = 'No'
newData = rbind(neg, pos) #merge positive and negative examples
newData$Class = factor(newData$Class)
We run random forest on the new dataset, newData
, and check confusion matrix.
m4 = randomForest(data = newData, Class ~ .)
p4 = predict(m4, d[, -n])
confusionMatrix(p4, d[, n], positive = 'Yes')
Confusion Matrix and Statistics
Reference
Prediction No Yes
No 210086 0
Yes 74229 492
Accuracy : 0.7394
95% CI : (0.7378, 0.741)
No Information Rate : 0.9983
P-Value \[Acc > NIR\] : 1
Kappa : 0.0097
Mcnemar's Test P-Value : <2e-16
Sensitivity : 1.000000
Specificity : 0.738920
Pos Pred Value : 0.006584
Neg Pred Value : 1.000000
Prevalence : 0.001727
Detection Rate : 0.001727
Detection Prevalence : 0.262357
Balanced Accuracy : 0.869460
'Positive' Class : Yes
Well, while sensitivity is still 100%, specificity dropped to 72% leading to a big fraction of false positive predictions. Learning on the data that was transformed using SMOTE algorithm gave much better results.
from:https://www.kaggle.com/themlguy/undersample-and-oversample-approach-explored
# This Python 3 environment comes with many helpful analytics libraries installed
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import os
print(os.listdir("../input"))
['creditcard.csv']
import matplotlib.pyplot as plt
from sklearn.cross_validation import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import StandardScaler
import seaborn as sns
from sklearn.metrics import confusion_matrix,recall_score,precision_recall_curve,auc,roc_curve,roc_auc_score,classification_report
/opt/conda/lib/python3.6/site-packages/sklearn/cross_validation.py:41: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
"This module will be removed in 0.20.", DeprecationWarning)
creditcard_data=pd.read_csv("../input/creditcard.csv")
creditcard_data['Amount']=StandardScaler().fit_transform(creditcard_data['Amount'].values.reshape(-1, 1))
creditcard_data.drop(['Time'], axis=1, inplace=True)
def generatePerformanceReport(clf,X_train,y_train,X_test,y_test,bool_):
if bool_==True:
clf.fit(X_train,y_train.values.ravel())
pred=clf.predict(X_test)
cnf_matrix=confusion_matrix(y_test,pred)
tn, fp, fn, tp=cnf_matrix.ravel()
print('---------------------------------')
print('Length of training data:',len(X_train))
print('Length of test data:', len(X_test))
print('---------------------------------')
print('True positives:',tp)
print('True negatives:',tn)
print('False positives:',fp)
print('False negatives:',fn)
#sns.heatmap(cnf_matrix,cmap="coolwarm_r",annot=True,linewidths=0.5)
print('----------------------Classification report--------------------------')
print(classification_report(y_test,pred))
#generate 50%, 66%, 75% proportions of normal indices to be combined with fraud indices 也就是说采样后的黑白样本比例是:0.5,0.66,0.75
#undersampled data
normal_indices=creditcard_data[creditcard_data['Class']==0].index
fraud_indices=creditcard_data[creditcard_data['Class']==1].index
for i in range(1,4):
normal_sampled_data=np.array(np.random.choice(normal_indices, i*len(fraud_indices),replace=False)) #a random sample is generated from normal_indices 主要是随机欠采样
undersampled_data=np.concatenate([fraud_indices, normal_sampled_data])
undersampled_data=creditcard_data.iloc[undersampled_data]
print('length of undersampled data ', len(undersampled_data))
print('% of fraud transactions in undersampled data ',len(undersampled_data.loc[undersampled_data['Class']==1])/len(undersampled_data))
#get feature and label data
feature_data=undersampled_data.loc[:,undersampled_data.columns!='Class']
label_data=undersampled_data.loc[:,undersampled_data.columns=='Class']
X_train, X_test, y_train, y_test=train_test_split(feature_data,label_data,test_size=0.30)
for j in [LogisticRegression(),SVC(),RandomForestClassifier(n_estimators=100)]:
clf=j
print(j)
generatePerformanceReport(clf,X_train,y_train,X_test,y_test,True)
#the above code classifies X_test which is part of undersampled data
#now, let us consider the remaining rows of dataset and use that as test set
remaining_indices=[i for i in creditcard_data.index if i not in undersampled_data.index]
testdf=creditcard_data.iloc[remaining_indices]
testdf_label=creditcard_data.loc[:,testdf.columns=='Class']
testdf_feature=creditcard_data.loc[:,testdf.columns!='Class']
generatePerformanceReport(clf,X_train,y_train,testdf_feature,testdf_label,False)
length of undersampled data 984
% of fraud transactions in undersampled data 0.5
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
Length of training data: 688
True positives: 144
True negatives: 134
False positives: 11
False negatives: 7
----------------------Classification report--------------------------
precision recall f1-score support
0 0.95 0.92 0.94 145
1 0.93 0.95 0.94 151
avg / total 0.94 0.94 0.94 296
Length of training data: 688
True positives: 461
True negatives: 270879
False positives: 13436
False negatives: 31
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 0.95 0.98 284315
1 0.03 0.94 0.06 492 #可以看到LR在测试数据集上表现并不好
avg / total 1.00 0.95 0.97 284807
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
Length of training data: 688
True positives: 144
True negatives: 140
False positives: 5
False negatives: 7
----------------------Classification report--------------------------
precision recall f1-score support
0 0.95 0.97 0.96 145
1 0.97 0.95 0.96 151
avg / total 0.96 0.96 0.96 296
Length of training data: 688
True positives: 463
True negatives: 267084
False positives: 17231
False negatives: 29
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 0.94 0.97 284315
1 0.03 0.94 0.05 492 #看来svm在测试数据集上也不行啊
avg / total 1.00 0.94 0.97 284807
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=100, n_jobs=1,
oob_score=False, random_state=None, verbose=0,
Length of training data: 688
True positives: 144
True negatives: 142
False positives: 3
False negatives: 7
----------------------Classification report--------------------------
precision recall f1-score support
0 0.95 0.98 0.97 145
1 0.98 0.95 0.97 151
avg / total 0.97 0.97 0.97 296
Length of training data: 688
True positives: 485
True negatives: 275060
False positives: 9255
False negatives: 7
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 0.97 0.98 284315
1 0.05 0.99 0.09 492 #Rf也不行????
avg / total 1.00 0.97 0.98 284807
length of undersampled data 1476
% of fraud transactions in undersampled data 0.3333333333333333
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
Length of training data: 1033
True positives: 130
True negatives: 291
False positives: 5
False negatives: 17
----------------------Classification report--------------------------
precision recall f1-score support
0 0.94 0.98 0.96 296
1 0.96 0.88 0.92 147
avg / total 0.95 0.95 0.95 443
Length of training data: 1033
True positives: 442
True negatives: 278887
False positives: 5428
False negatives: 50
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 0.98 0.99 284315
1 0.08 0.90 0.14 492
avg / total 1.00 0.98 0.99 284807
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
Length of training data: 1033
True positives: 133
True negatives: 286
False positives: 10
False negatives: 14
----------------------Classification report--------------------------
precision recall f1-score support
0 0.95 0.97 0.96 296
1 0.93 0.90 0.92 147
avg / total 0.95 0.95 0.95 443
Length of training data: 1033
True positives: 453
True negatives: 274909
False positives: 9406
False negatives: 39
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 0.97 0.98 284315
1 0.05 0.92 0.09 492
avg / total 1.00 0.97 0.98 284807
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=100, n_jobs=1,
oob_score=False, random_state=None, verbose=0,
Length of training data: 1033
True positives: 128
True negatives: 293
False positives: 3
False negatives: 19
----------------------Classification report--------------------------
precision recall f1-score support
0 0.94 0.99 0.96 296
1 0.98 0.87 0.92 147
avg / total 0.95 0.95 0.95 443
Length of training data: 1033
True positives: 473
True negatives: 281560
False positives: 2755
False negatives: 19
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 0.99 1.00 284315
1 0.15 0.96 0.25 492
avg / total 1.00 0.99 0.99 284807
length of undersampled data 1968
% of fraud transactions in undersampled data 0.25
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
Length of training data: 1377
True positives: 116
True negatives: 451
False positives: 5
False negatives: 19
----------------------Classification report--------------------------
precision recall f1-score support
0 0.96 0.99 0.97 456
1 0.96 0.86 0.91 135
avg / total 0.96 0.96 0.96 591
Length of training data: 1377
True positives: 433
True negatives: 282245
False positives: 2070
False negatives: 59
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 0.99 1.00 284315
1 0.17 0.88 0.29 492
avg / total 1.00 0.99 1.00 284807
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
Length of training data: 1377
True positives: 118
True negatives: 447
False positives: 9
False negatives: 17
----------------------Classification report--------------------------
precision recall f1-score support
0 0.96 0.98 0.97 456
1 0.93 0.87 0.90 135
avg / total 0.96 0.96 0.96 591
Length of training data: 1377
True positives: 445
True negatives: 279369
False positives: 4946
False negatives: 47
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 0.98 0.99 284315
1 0.08 0.90 0.15 492
avg / total 1.00 0.98 0.99 284807
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=100, n_jobs=1,
oob_score=False, random_state=None, verbose=0,
Length of training data: 1377
True positives: 112
True negatives: 455
False positives: 1
False negatives: 23
----------------------Classification report--------------------------
precision recall f1-score support
0 0.95 1.00 0.97 456
1 0.99 0.83 0.90 135
avg / total 0.96 0.96 0.96 591
Length of training data: 1377
True positives: 469
True negatives: 283466
False positives: 849
False negatives: 23
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 1.00 1.00 284315
1 0.36 0.95 0.52 492
avg / total 1.00 1.00 1.00 284807
整体来看,因为欠采样只是用了一个模型,因此预测效果很差!!!因为没有用到全量数据特征,所以在全部数据集上表现并不好!
#oversampled_data data
normal_sampled_indices=creditcard_data.loc[creditcard_data['Class']==0].index
oversampled_data=creditcard_data.iloc[normal_sampled_indices]
fraud_data=creditcard_data.loc[creditcard_data['Class']==1]
oversampled_data=oversampled_data.append([fraud_data]*300, ignore_index=True) #此处过采样处理是直接将欺诈样本复制300份!!!
print('length of oversampled_data data ', len(oversampled_data))
print('% of fraud transactions in oversampled_data data ',len(oversampled_data.loc[oversampled_data['Class']==1])/len(oversampled_data))
#get feature and label data
feature_data=oversampled_data.loc[:,oversampled_data.columns!='Class']
label_data=oversampled_data.loc[:,oversampled_data.columns=='Class']
X_train, X_test, y_train, y_test=train_test_split(feature_data,label_data,test_size=0.30)
for j in [LogisticRegression(),RandomForestClassifier(n_estimators=100)]:
clf=j
print(j)
generatePerformanceReport(clf,X_train,y_train,X_test,y_test,True)
#the above code classifies X_test which is part of undersampled data
#now, let us consider the remaining rows of dataset and use that as test set
remaining_indices=[i for i in creditcard_data.index if i not in oversampled_data.index]
testdf=creditcard_data.iloc[remaining_indices]
testdf_label=creditcard_data.loc[:,testdf.columns=='Class']
testdf_feature=creditcard_data.loc[:,testdf.columns!='Class']
generatePerformanceReport(clf,X_train,y_train,testdf_feature,testdf_label,False)
length of oversampled_data data 431915
% of fraud transactions in oversampled_data data 0.3417339059768704 最后复制后的欺诈样本比例为白样本的33%
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
Length of training data: 302340
True positives: 39803
True negatives: 84311
False positives: 1027
False negatives: 4434
----------------------Classification report--------------------------
precision recall f1-score support
0 0.95 0.99 0.97 85338
1 0.97 0.90 0.94 44237
avg / total 0.96 0.96 0.96 129575
Length of training data: 302340
True positives: 444
True negatives: 281055
False positives: 3260
False negatives: 48
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 0.99 0.99 284315
1 0.12 0.90 0.21 492 #效果也不咋的啊!
avg / total 1.00 0.99 0.99 284807
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=100, n_jobs=1,
oob_score=False, random_state=None, verbose=0,
Length of training data: 302340
True positives: 44237
True negatives: 85327
False positives: 11
False negatives: 0
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 1.00 1.00 85338
1 1.00 1.00 1.00 44237
avg / total 1.00 1.00 1.00 129575
Length of training data: 302340
True positives: 492
True negatives: 284304
False positives: 11
False negatives: 0
----------------------Classification report--------------------------
precision recall f1-score support
0 1.00 1.00 1.00 284315
1 0.98 1.00 0.99 492 #随机森林还是不错的!!!
avg / total 1.00 1.00 1.00 284807
Random forest classifier with oversampled approach performs better compared to undersampled approach!!!
from:https://www.kaggle.com/gargmanish/how-to-handle-imbalance-data-study-in-detail
This all I have done by using Analytics Vidya's blog please find the link Analytics Vidya
Undersampling:- it means taking the less number of majority class (In our case taking less number of Normal transactions so that our new data will be balanced
Oversampling: it means using replicating the data of minority class (fraud class) so that we can have a balanced data
SMOTE: it is also a type of oversampling but in this we will make the synthetic example of Minority data and will give as a balanced data
First I will start with the Undersampling and will try to classify using these Models
# This Python 3 environment comes with many helpful analytics libraries installed
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
from subprocess import check_output
print(check_output(["ls", "../input"]).decode("utf8"))
creditcard.csv
import pandas as pd # to import csv and for data manipulation
import matplotlib.pyplot as plt # to plot graph
import seaborn as sns # for intractve graphs
import numpy as np # for linear algebra
import datetime # to dela with date and time
%matplotlib inline
from sklearn.preprocessing import StandardScaler # for preprocessing the data
from sklearn.ensemble import RandomForestClassifier # Random forest classifier
from sklearn.tree import DecisionTreeClassifier # for Decision Tree classifier
from sklearn.svm import SVC # for SVM classification
from sklearn.linear_model import LogisticRegression
from sklearn.cross_validation import train_test_split # to split the data
from sklearn.cross_validation import KFold # For cross vbalidation
from sklearn.model_selection import GridSearchCV # for tunnig hyper parameter it will use all combination of given parameters
from sklearn.model_selection import RandomizedSearchCV # same for tunning hyper parameter but will use random combinations of parameters
from sklearn.metrics import confusion_matrix,recall_score,precision_recall_curve,auc,roc_curve,roc_auc_score,classification_report
import warnings
warnings.filterwarnings('ignore')
/opt/conda/lib/python3.6/site-packages/sklearn/cross_validation.py:43: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
"This module will be removed in 0.20.", DeprecationWarning)
data = pd.read_csv("../input/creditcard.csv",header = 0)
data.info()
RangeIndex: 284807 entries, 0 to 284806
Data columns (total 31 columns):
Time 284807 non-null float64
V1 284807 non-null float64
V2 284807 non-null float64
V3 284807 non-null float64
V4 284807 non-null float64
V5 284807 non-null float64
V6 284807 non-null float64
V7 284807 non-null float64
V8 284807 non-null float64
V9 284807 non-null float64
V10 284807 non-null float64
V11 284807 non-null float64
V12 284807 non-null float64
V13 284807 non-null float64
V14 284807 non-null float64
V15 284807 non-null float64
V16 284807 non-null float64
V17 284807 non-null float64
V18 284807 non-null float64
V19 284807 non-null float64
V20 284807 non-null float64
V21 284807 non-null float64
V22 284807 non-null float64
V23 284807 non-null float64
V24 284807 non-null float64
V25 284807 non-null float64
V26 284807 non-null float64
V27 284807 non-null float64
V28 284807 non-null float64
Amount 284807 non-null float64
Class 284807 non-null int64
dtypes: float64(30), int64(1)
memory usage: 67.4 MB
# Now lets check the class distributions
sns.countplot("Class",data=data)
# now let us check in the number of Percentage
Count_Normal_transacation = len(data[data["Class"]==0]) # normal transaction are repersented by 0
Count_Fraud_transacation = len(data[data["Class"]==1]) # fraud by 1
Percentage_of_Normal_transacation = Count_Normal_transacation/(Count_Normal_transacation+Count_Fraud_transacation)
print("percentage of normal transacation is",Percentage_of_Normal_transacation*100)
Percentage_of_Fraud_transacation= Count_Fraud_transacation/(Count_Normal_transacation+Count_Fraud_transacation)
print("percentage of fraud transacation",Percentage_of_Fraud_transacation*100)
原始数据样本就是:500:1
percentage of normal transacation is 99.82725143693798
percentage of fraud transacation 0.1727485630620034
Fraud_transacation = data[data["Class"]==1]
Normal_transacation= data[data["Class"]==0]
plt.figure(figsize=(10,6))
plt.subplot(121)
Fraud_transacation.Amount.plot.hist(title="Fraud Transacation")
plt.subplot(122)
Normal_transacation.Amount.plot.hist(title="Normal Transaction")
# the distribution for Normal transction is not clear and it seams that all transaction are less than 2.5 K
Fraud_transacation = data[data["Class"]==1]
Normal_transacation= data[data["Class"]==0]
plt.figure(figsize=(10,6))
plt.subplot(121)
Fraud_transacation[Fraud_transacation["Amount"]<= 2500].Amount.plot.hist(title="Fraud Tranascation")
plt.subplot(122)
Normal_transacation[Normal_transacation["Amount"]<=2500].Amount.plot.hist(title="Normal Transaction")
Before re sampling lets have look at the different accuracy matrices
Accuracy = TP+TN/Total
Precison = TP/(TP+FP)
Recall = TP/(TP+FN)
TP = True possitive means no of possitve cases which are predicted possitive
TN = True negative means no of negative cases which are predicted negative
FP = False possitve means no of negative cases which are predicted possitive
FN= False Negative means no of possitive cases which are predicted negative
Now for our case recall will be a better option because in these case no of normal transacations will be very high than the no of fraud cases and sometime a fraud case will be predicted as normal. So, recall will give us a sense of only fraud cases
Resampling
in this we will resample our data with different size
then we will try to use this resampled data to train our model
then we will use this model to predict for our original data
# for undersampling we need a portion of majority class and will take whole data of minority class
fraud_indices= np.array(data[data.Class==1].index)
normal_indices = np.array(data[data.Class==0].index)
#now let us a define a function for make undersample data with different proportion
#different proportion means with different proportion of normal classes of data
def undersample(normal_indices,fraud_indices,times):#times denote the normal data = times*fraud data
Normal_indices_undersample = np.array(np.random.choice(normal_indices,(times*Count_Fraud_transacation),replace=False)) #和上面例子是一样的!!!
undersample_data= np.concatenate([fraud_indices,Normal_indices_undersample])
undersample_data = data.iloc[undersample_data,:]
print("the normal transacation proportion is :",len(undersample\_data\[undersample\_data.Class==0\])/len(undersample\_data\[undersample\_data.Class\]))
print("the fraud transacation proportion is :",len(undersample\_data\[undersample\_data.Class==1\])/len(undersample\_data\[undersample\_data.Class\]))
print("total number of record in resampled data is:",len(undersample\_data\[undersample\_data.Class\]))
return(undersample\_data)
## first make a model function for modeling with confusion matrix
def model(model,features_train,features_test,labels_train,labels_test):
clf= model
clf.fit(features_train,labels_train.values.ravel())
pred=clf.predict(features_test)
cnf_matrix=confusion_matrix(labels_test,pred)
print("the recall for this model is :",cnf_matrix[1,1]/(cnf_matrix[1,1]+cnf_matrix[1,0]))
fig= plt.figure(figsize=(6,3))# to plot the graph
print("TP",cnf_matrix[1,1,]) # no of fraud transaction which are predicted fraud
print("TN",cnf_matrix[0,0]) # no. of normal transaction which are predited normal
print("FP",cnf_matrix[0,1]) # no of normal transaction which are predicted fraud
print("FN",cnf_matrix[1,0]) # no of fraud Transaction which are predicted normal
sns.heatmap(cnf_matrix,cmap="coolwarm_r",annot=True,linewidths=0.5)
plt.title("Confusion_matrix")
plt.xlabel("Predicted_class")
plt.ylabel("Real class")
plt.show()
print("\n----------Classification Report------------------------------------")
print(classification_report(labels_test,pred))
def data_prepration(x): # preparing data for training and testing as we are going to use different data
#again and again so make a function
x_features= x.ix[:,x.columns != "Class"]
x_labels=x.ix[:,x.columns=="Class"]
x_features_train,x_features_test,x_labels_train,x_labels_test = train_test_split(x_features,x_labels,test_size=0.3) #30%用于测试
print("length of training data")
print(len(x_features_train))
print("length of test data")
print(len(x_features_test))
return(x_features_train,x_features_test,x_labels_train,x_labels_test)
# before starting we should standridze our ampount column
data["Normalized Amount"] = StandardScaler().fit_transform(data['Amount'].reshape(-1, 1))
data.drop(["Time","Amount"],axis=1,inplace=True)
data.head()
V1
V2
V3
V4
V5
V6
V7
V8
V9
V10
…
V21
V22
V23
V24
V25
V26
V27
V28
Class
Normalized Amount
0
-1.359807
-0.072781
2.536347
1.378155
-0.338321
0.462388
0.239599
0.098698
0.363787
0.090794
…
-0.018307
0.277838
-0.110474
0.066928
0.128539
-0.189115
0.133558
-0.021053
0
0.244964
1
1.191857
0.266151
0.166480
0.448154
0.060018
-0.082361
-0.078803
0.085102
-0.255425
-0.166974
…
-0.225775
-0.638672
0.101288
-0.339846
0.167170
0.125895
-0.008983
0.014724
0
-0.342475
2
-1.358354
-1.340163
1.773209
0.379780
-0.503198
1.800499
0.791461
0.247676
-1.514654
0.207643
…
0.247998
0.771679
0.909412
-0.689281
-0.327642
-0.139097
-0.055353
-0.059752
0
1.160686
3
-0.966272
-0.185226
1.792993
-0.863291
-0.010309
1.247203
0.237609
0.377436
-1.387024
-0.054952
…
-0.108300
0.005274
-0.190321
-1.175575
0.647376
-0.221929
0.062723
0.061458
0
0.140534
4
-1.158233
0.877737
1.548718
0.403034
-0.407193
0.095921
0.592941
-0.270533
0.817739
0.753074
…
-0.009431
0.798278
-0.137458
0.141267
-0.206010
0.502292
0.219422
0.215153
0
-0.073403
5 rows × 30 columns
# Now make undersample data with differnt portion
for i in range(1,4):
print("the undersample data for {} proportion".format(i))
print()
Undersample_data = undersample(normal_indices,fraud_indices,i)
print("------------------------------------------------------------")
print()
print("the model classification for {} proportion".format(i))
print()
undersample_features_train,undersample_features_test,undersample_labels_train,undersample_labels_test=data_prepration(Undersample_data)
print()
clf=LogisticRegression()
model(clf,undersample_features_train,undersample_features_test,undersample_labels_train,undersample_labels_test)
print("________________________________________________________________________________________________________")
#Proportion 2nd contains 66% noraml transaction
#proportion 3rd contains 75 % normal transaction
the undersample data for 1 proportion
the normal transacation proportion is : 0.5
the fraud transacation proportion is : 0.5
the model classification for 1 proportion
length of training data
688
length of test data
296
the recall for this model is : 0.897260273973
TP 131
TN 147
FP 3
FN 15
----------Classification Report------------------------------------
precision recall f1-score support
0 0.91 0.98 0.94 150
1 0.98 0.90 0.94 146 #测试集上???咋会这么高!!!
avg / total 0.94 0.94 0.94 296
________________________________________________________________________________________________________
the undersample data for 2 proportion
the normal transacation proportion is : 0.6666666666666666
the fraud transacation proportion is : 0.3333333333333333
the model classification for 2 proportion
length of training data
1033
length of test data
443
the recall for this model is : 0.929078014184
TP 131
TN 296
FP 6
FN 10
----------Classification Report------------------------------------
precision recall f1-score support
0 0.97 0.98 0.97 302
1 0.96 0.93 0.94 141
avg / total 0.96 0.96 0.96 443
________________________________________________________________________________________________________
the undersample data for 3 proportion
the normal transacation proportion is : 0.75
the fraud transacation proportion is : 0.25
the model classification for 3 proportion
length of training data
1377
length of test data
591
the recall for this model is : 0.892086330935
TP 124
TN 446
FP 6
FN 15
----------Classification Report------------------------------------
precision recall f1-score support
0 0.97 0.99 0.98 452
1 0.95 0.89 0.92 139
avg / total 0.96 0.96 0.96 591
________________________________________________________________________________________________________
#let us train this model using undersample data and test for the whole data test set #用欠采样训练的模型来预测全量数据集
for i in range(1,4):
print("the undersample data for {} proportion".format(i))
print()
Undersample_data = undersample(normal_indices,fraud_indices,i)
print("------------------------------------------------------------")
print()
print("the model classification for {} proportion".format(i))
print()
undersample_features_train,undersample_features_test,undersample_labels_train,undersample_labels_test=data_prepration(Undersample_data)
data_features_train,data_features_test,data_labels_train,data_labels_test=data_prepration(data)
#the partion for whole data
print()
clf=LogisticRegression()
model(clf,undersample_features_train,data_features_test,undersample_labels_train,data_labels_test)
# here training for the undersample data but tatsing for whole data
print("_________________________________________________________________________________________")
the undersample data for 1 proportion
the normal transacation proportion is : 0.5
the fraud transacation proportion is : 0.5
the model classification for 1 proportion
length of training data
688
length of test data
296
length of training data
199364
length of test data
85443
the recall for this model is : 0.923076923077
TP 132
TN 81568
FP 3732
FN 11
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 0.96 0.98 85300
1 0.03 0.92 0.07 143 #果然是预测全量数据不好!!!
avg / total 1.00 0.96 0.98 85443
_________________________________________________________________________________________
the undersample data for 2 proportion
the normal transacation proportion is : 0.6666666666666666
the fraud transacation proportion is : 0.3333333333333333
the model classification for 2 proportion
length of training data
1033
length of test data
443
length of training data
199364
length of test data
85443
the recall for this model is : 0.913333333333
TP 137
TN 84232
FP 1061
FN 13
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 0.99 0.99 85293
1 0.11 0.91 0.20 150
avg / total 1.00 0.99 0.99 85443
_________________________________________________________________________________________
the undersample data for 3 proportion
the normal transacation proportion is : 0.75
the fraud transacation proportion is : 0.25
the model classification for 3 proportion
length of training data
1377
length of test data
591
length of training data
199364
length of test data
85443
the recall for this model is : 0.894366197183
TP 127
TN 84750
FP 551
FN 15
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 0.99 1.00 85301
1 0.19 0.89 0.31 142
avg / total 1.00 0.99 1.00 85443
_________________________________________________________________________________________
1.Try with SVM and then Random Forest in same Manner
SVM with Undersample data
for i in range(1,4):
print("the undersample data for {} proportion".format(i))
print()
Undersample_data = undersample(normal_indices,fraud_indices,i)
print("------------------------------------------------------------")
print()
print("the model classification for {} proportion".format(i))
print()
undersample_features_train,undersample_features_test,undersample_labels_train,undersample_labels_test=data_prepration(Undersample_data)
print()
clf= SVC()# here we are just changing classifier
model(clf,undersample_features_train,undersample_features_test,undersample_labels_train,undersample_labels_test)
print("________________________________________________________________________________________________________")
the undersample data for 1 proportion
the normal transacation proportion is : 0.5
the fraud transacation proportion is : 0.5
the model classification for 1 proportion
length of training data
688
length of test data
296
the recall for this model is : 0.933734939759
TP 155
TN 117
FP 13
FN 11
----------Classification Report------------------------------------
precision recall f1-score support
0 0.91 0.90 0.91 130
1 0.92 0.93 0.93 166
avg / total 0.92 0.92 0.92 296
________________________________________________________________________________________________________
the undersample data for 2 proportion
the normal transacation proportion is : 0.6666666666666666
the fraud transacation proportion is : 0.3333333333333333
the model classification for 2 proportion
length of training data
1033
length of test data
443
the recall for this model is : 0.923076923077
TP 120
TN 302
FP 11
FN 10
----------Classification Report------------------------------------
precision recall f1-score support
0 0.97 0.96 0.97 313
1 0.92 0.92 0.92 130
avg / total 0.95 0.95 0.95 443
________________________________________________________________________________________________________
the undersample data for 3 proportion
the normal transacation proportion is : 0.75
the fraud transacation proportion is : 0.25
the model classification for 3 proportion
length of training data
1377
length of test data
591
the recall for this model is : 0.858974358974
TP 134
TN 428
FP 7
FN 22
----------Classification Report------------------------------------
precision recall f1-score support
0 0.95 0.98 0.97 435
1 0.95 0.86 0.90 156
avg / total 0.95 0.95 0.95 591
________________________________________________________________________________________________________
#let us train this model using undersample data and test for the whole data test set
for i in range(1,4):
print("the undersample data for {} proportion".format(i))
print()
Undersample_data = undersample(normal_indices,fraud_indices,i)
print("------------------------------------------------------------")
print()
print("the model classification for {} proportion".format(i))
print()
undersample_features_train,undersample_features_test,undersample_labels_train,undersample_labels_test=data_prepration(Undersample_data)
data_features_train,data_features_test,data_labels_train,data_labels_test=data_prepration(data)
#the partion for whole data
print()
clf=SVC()
model(clf,undersample_features_train,data_features_test,undersample_labels_train,data_labels_test)
# here training for the undersample data but tatsing for whole data
print("_________________________________________________________________________________________")
the undersample data for 1 proportion
the normal transacation proportion is : 0.5
the fraud transacation proportion is : 0.5
the model classification for 1 proportion
length of training data
688
length of test data
296
length of training data
199364
length of test data
85443
the recall for this model is : 0.941176470588
TP 128
TN 81207
FP 4100
FN 8
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 0.95 0.98 85307
1 0.03 0.94 0.06 136
avg / total 1.00 0.95 0.97 85443
_________________________________________________________________________________________
the undersample data for 2 proportion
the normal transacation proportion is : 0.6666666666666666
the fraud transacation proportion is : 0.3333333333333333
the model classification for 2 proportion
length of training data
1033
length of test data
443
length of training data
199364
length of test data
85443
the recall for this model is : 0.922580645161
TP 143
TN 82552
FP 2736
FN 12
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 0.97 0.98 85288
1 0.05 0.92 0.09 155
avg / total 1.00 0.97 0.98 85443
_________________________________________________________________________________________
the undersample data for 3 proportion
the normal transacation proportion is : 0.75
the fraud transacation proportion is : 0.25
the model classification for 3 proportion
length of training data
1377
length of test data
591
length of training data
199364
length of test data
85443
the recall for this model is : 0.888888888889
TP 136
TN 83261
FP 2029
FN 17
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 0.98 0.99 85290
1 0.06 0.89 0.12 153
avg / total 1.00 0.98 0.99 85443
_________________________________________________________________________________________
2 .so to improve precision we must have to tune the hyper parameter of these models
3 That I will do in next version
4 For now lets try with my favorite Random Forest classifier
# Random Forest Classifier with undersample data only
for i in range(1,4):
print("the undersample data for {} proportion".format(i))
print()
Undersample_data = undersample(normal_indices,fraud_indices,i)
print("------------------------------------------------------------")
print()
print("the model classification for {} proportion".format(i))
print()
undersample_features_train,undersample_features_test,undersample_labels_train,undersample_labels_test=data_prepration(Undersample_data)
print()
clf= RandomForestClassifier(n_estimators=100)# here we are just changing classifier
model(clf,undersample_features_train,undersample_features_test,undersample_labels_train,undersample_labels_test)
print("________________________________________________________________________________________________________")
the undersample data for 1 proportion
the normal transacation proportion is : 0.5
the fraud transacation proportion is : 0.5
the model classification for 1 proportion
length of training data
688
length of test data
296
the recall for this model is : 0.858064516129
TP 133
TN 139
FP 2
FN 22
----------Classification Report------------------------------------
precision recall f1-score support
0 0.86 0.99 0.92 141
1 0.99 0.86 0.92 155
avg / total 0.93 0.92 0.92 296
________________________________________________________________________________________________________
the undersample data for 2 proportion
the normal transacation proportion is : 0.6666666666666666
the fraud transacation proportion is : 0.3333333333333333
the model classification for 2 proportion
length of training data
1033
length of test data
443
the recall for this model is : 0.890410958904
TP 130
TN 294
FP 3
FN 16
----------Classification Report------------------------------------
precision recall f1-score support
0 0.95 0.99 0.97 297
1 0.98 0.89 0.93 146
avg / total 0.96 0.96 0.96 443
________________________________________________________________________________________________________
the undersample data for 3 proportion
the normal transacation proportion is : 0.75
the fraud transacation proportion is : 0.25
the model classification for 3 proportion
length of training data
1377
length of test data
591
the recall for this model is : 0.863636363636
TP 133
TN 436
FP 1
FN 21
----------Classification Report------------------------------------
precision recall f1-score support
0 0.95 1.00 0.98 437
1 0.99 0.86 0.92 154
avg / total 0.96 0.96 0.96 591
________________________________________________________________________________________________________
#let us train this model using undersample data and test for the whole data test set
for i in range(1,4):
print("the undersample data for {} proportion".format(i))
print()
Undersample_data = undersample(normal_indices,fraud_indices,i)
print("------------------------------------------------------------")
print()
print("the model classification for {} proportion".format(i))
print()
undersample_features_train,undersample_features_test,undersample_labels_train,undersample_labels_test=data_prepration(Undersample_data)
data_features_train,data_features_test,data_labels_train,data_labels_test=data_prepration(data)
#the partion for whole data
print()
clf=RandomForestClassifier(n_estimators=100)
model(clf,undersample_features_train,data_features_test,undersample_labels_train,data_labels_test)
# here training for the undersample data but tatsing for whole data
print("_________________________________________________________________________________________")
the undersample data for 1 proportion
the normal transacation proportion is : 0.5
the fraud transacation proportion is : 0.5
the model classification for 1 proportion
length of training data
688
length of test data
296
length of training data
199364
length of test data
85443
the recall for this model is : 0.971631205674
TP 137
TN 83064
FP 2238
FN 4
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 0.97 0.99 85302
1 0.06 0.97 0.11 141
avg / total 1.00 0.97 0.99 85443
_________________________________________________________________________________________
the undersample data for 2 proportion
the normal transacation proportion is : 0.6666666666666666
the fraud transacation proportion is : 0.3333333333333333
the model classification for 2 proportion
length of training data
1033
length of test data
443
length of training data
199364
length of test data
85443
the recall for this model is : 0.967320261438
TP 148
TN 84448
FP 842
FN 5
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 0.99 1.00 85290
1 0.15 0.97 0.26 153
avg / total 1.00 0.99 0.99 85443
_________________________________________________________________________________________
the undersample data for 3 proportion
the normal transacation proportion is : 0.75
the fraud transacation proportion is : 0.25
the model classification for 3 proportion
length of training data
1377
length of test data
591
length of training data
199364
length of test data
85443
the recall for this model is : 0.967948717949
TP 151
TN 84964
FP 323
FN 5
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 1.00 1.00 85287
1 0.32 0.97 0.48 156
avg / total 1.00 1.00 1.00 85443
_________________________________________________________________________________________
featimp = pd.Series(clf.feature_importances_,index=data_features_train.columns).sort_values(ascending=False)
print(featimp) # this is the property of Random Forest classifier that it provide us the importance
V14 0.206364
V10 0.134424
V11 0.098375
V12 0.097194
V17 0.088706
V4 0.075658
V3 0.071006
V16 0.034599
V2 0.020407
V18 0.019018
V7 0.017165
V21 0.014312
V27 0.011712
V19 0.011044
V8 0.010244
V1 0.008564
Normalized Amount 0.007908
V9 0.007183
V20 0.007094
V15 0.006852
V26 0.006653
V5 0.006597
V22 0.006507
V13 0.005839
V24 0.005519
V28 0.005390
V6 0.005303
V25 0.005210
V23 0.005154
dtype: float64
# make a new data with only class and V14
data1=data[["V14","V10","V12","V17","V4","Class"]]
data1.head()
V14
V10
V12
V17
V4
Class
0
-0.311169
0.090794
-0.617801
0.207971
1.378155
0
1
-0.143772
-0.166974
1.065235
-0.114805
0.448154
0
2
-0.165946
0.207643
0.066084
1.109969
0.379780
0
3
-0.287924
-0.054952
0.178228
-0.684093
-0.863291
0
4
-1.119670
0.753074
0.538196
-0.237033
0.403034
0
Undersample_data1 = undersample(normal_indices,fraud_indices,1)
#only for 50 % proportion it means normal transaction and fraud transaction are equal so passing
Undersample_data1_features_train,Undersample_data1_features_test,Undersample_data1_labels_train,Undersample_data1_labels_test = data_prepration(Undersample_data1)
the normal transacation proportion is : 0.5
the fraud transacation proportion is : 0.5
total number of record in resampled data is: 984
length of training data
688
length of test data
296
clf= RandomForestClassifier(n_estimators=100)
model(clf,Undersample_data1_features_train,Undersample_data1_features_test,Undersample_data1_labels_train,Undersample_data1_labels_test)
the recall for this model is : 0.93006993007
TP 133
TN 149
FP 4
FN 10
----------Classification Report------------------------------------
precision recall f1-score support
0 0.94 0.97 0.96 153
1 0.97 0.93 0.95 143
avg / total 0.95 0.95 0.95 296
全量数据没有测试????但从acc和recall看,top5特征的效果也还不错!!!
# now we will divied our data sets into two part and we will train and test and will oversample the train data and predict for test data
data = pd.read_csv("../input/creditcard.csv",header = 0)
print("length of training data",len(data))
print("length of normal data",len(data[data["Class"]==0]))
print("length of fraud data",len(data[data["Class"]==1]))
length of training data 284807
length of normal data 284315
length of fraud data 492
data_train_X,data_test_X,data_train_y,data_test_y=data_prepration(data)
data_train_X.columns
data_train_y.columns
length of training data
199364
length of test data
85443
Index(['Class'], dtype='object')
# ok Now we have a traing data
data_train_X["Class"]= data_train_y["Class"] # combining class with original data
data_train = data_train_X.copy() # for naming conevntion
print("length of training data",len(data_train))
normal_data = data_train[data_train["Class"]==0]
print("length of normal data",len(normal_data))
fraud_data = data_train[data_train["Class"]==1]
print("length of fraud data",len(fraud_data))
length of training data 199364
length of normal data 199009
length of fraud data 355
# Now start oversamoling of training data
for i in range (365): # the number is choosen by myself on basis of nnumber of fraud transaction
normal_data= normal_data.append(fraud_data)
os_data = normal_data.copy()
print("length of oversampled data is ",len(os_data))
print("Number of normal transcation in oversampled data",len(os_data[os_data["Class"]==0]))
print("No.of fraud transcation",len(os_data[os_data["Class"]==1]))
print("Proportion of Normal data in oversampled data is ",len(os_data[os_data["Class"]==0])/len(os_data))
print("Proportion of fraud data in oversampled data is ",len(os_data[os_data["Class"]==1])/len(os_data))
length of oversampled data is 328584
Number of normal transcation in oversampled data 199009
No.of fraud transcation 129575
Proportion of Normal data in oversampled data is 0.6056563922771651
Proportion of fraud data in oversampled data is 0.39434360772283494
# before applying any model standerdize our data amount
os_data["Normalized Amount"] = StandardScaler().fit_transform(os_data['Amount'].reshape(-1, 1))
os_data.drop(["Time","Amount"],axis=1,inplace=True) 其实随机森林对特征是否标准化无感,但是svm和LR就非常非常关键了
os_data.head()
V1
V2
V3
V4
V5
V6
V7
V8
V9
V10
…
V21
V22
V23
V24
V25
V26
V27
V28
Class
Normalized Amount
82656
1.356574
-1.535896
1.014585
-0.980949
-1.840651
0.495094
-1.535552
0.235415
-0.847601
1.180545
…
-0.578444
-0.948479
0.038288
-0.051798
0.350549
-0.338308
0.073518
0.017247
0
-0.240655
202761
0.078384
0.693709
-0.282273
-1.007720
1.058216
-0.035670
0.838345
0.070423
-0.094317
-0.221217
…
-0.303203
-0.775385
-0.086534
-1.414806
-0.360046
0.208073
0.234031
0.072388
0
-0.371265
85985
-3.549282
-3.403880
2.389801
1.080311
1.683676
-1.100104
-0.699287
0.171644
0.935805
-0.256182
…
-0.284722
0.428109
2.844650
0.006528
0.466552
0.421108
0.260494
-0.472237
0
-0.383217
215180
2.084961
0.009129
-3.842413
-0.551511
3.139773
2.743495
0.130580
0.552759
-0.030368
-0.295843
…
0.034740
0.187883
-0.014668
0.682901
0.410981
0.734260
-0.081080
-0.064606
0
-0.374769
75855
1.193268
-0.071682
0.611175
-0.232721
-0.478724
-0.216029
-0.329775
0.071921
0.009225
-0.112748
…
-0.043944
-0.080370
0.101692
0.090155
0.041104
0.914386
-0.053130
-0.002135
0
-0.388278
5 rows × 30 columns
# Now use this oversampled data for trainig the model and predict value for the test data that we created before
os_train_X,os_test_X,os_train_y,os_test_y=data_prepration(os_data)
clf= RandomForestClassifier(n_estimators=100)
model(clf,os_train_X,os_test_X,os_train_y,os_test_y)
length of training data
230008
length of test data
98576
the recall for this model is : 1.0
TP 38975
TN 59596
FP 5
FN 0
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 1.00 1.00 59601
1 1.00 1.00 1.00 38975
avg / total 1.00 1.00 1.00 98576
Observations
# now take all over sampled data as trainging and test it for test data
os_data_X = os_data.ix[:,os_data.columns != "Class"]
os_data_y = os_data.ix[:,os_data.columns == "Class"]
#for that we have to standrdize the normal amount and drop the time from it
data_test_X["Normalized Amount"] = StandardScaler().fit_transform(data_test_X['Amount'].reshape(-1, 1))
data_test_X.drop(["Time","Amount"],axis=1,inplace=True)
data_test_X.head()
V1
V2
V3
V4
V5
V6
V7
V8
V9
V10
…
V20
V21
V22
V23
V24
V25
V26
V27
V28
Normalized Amount
11514
1.451038
-0.603389
0.007125
-0.616909
-0.260790
0.474328
-0.826944
0.042607
1.101926
0.110945
…
-0.054708
-0.249080
-0.389480
-0.151185
-1.380077
0.610950
-0.163068
-0.005513
-0.013058
-0.320476
162269
-6.697569
4.179960
-4.866476
-0.626586
-3.024024
-1.324855
-0.835983
2.692196
1.844012
2.825418
…
0.649757
0.035932
0.852066
0.245004
1.155756
0.098178
-0.214949
0.996161
1.252345
0.050478
158202
2.104037
0.065442
-1.428655
0.323540
0.393572
-0.720375
0.054806
-0.347347
2.082360
-0.464191
…
-0.271997
0.093486
0.657963
-0.007259
0.431328
0.360900
-0.474799
-0.024631
-0.056532
-0.357576
203014
-2.602873
-1.593223
0.029747
-3.264885
1.156256
0.930955
-0.477817
0.828043
-0.543710
-0.592860
…
-1.154639
-0.680829
-1.305820
0.841971
-1.009959
-0.495993
0.056765
-0.434924
0.375225
-0.176200
129141
-1.325968
1.418993
-0.531978
-1.422122
2.635501
3.223994
0.477654
0.538505
0.756693
1.527077
…
0.941600
-0.599390
-1.053070
-0.004289
0.917391
0.221693
0.059054
0.459664
-0.018905
-0.324681
5 rows × 29 columns
# now use it for modeling
clf= RandomForestClassifier(n_estimators=100)
model(clf,os_data_X,data_test_X,os_data_y,data_test_y)
the recall for this model is : 0.773722627737
TP 106
TN 85300
FP 6
FN 31
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 1.00 1.00 85306
1 0.95 0.77 0.85 137
avg / total 1.00 1.00 1.00 85443
Observations
# Lets Use SMOTE for Sampling
#lets start with importing libraries
from imblearn.over_sampling import SMOTE
data = pd.read_csv('../input/creditcard.csv')
os = SMOTE(random_state=0) # We are using SMOTE as the function for oversampling
data_train_X,data_test_X,data_train_y,data_test_y=data_prepration(data)
columns = data_train_X.columns
length of training data
199364
length of test data
85443
# now use SMOTE to oversample our train data which have features data_train_X and labels in data_train_y
os_data_X,os_data_y=os.fit_sample(data_train_X,data_train_y)
os_data_X = pd.DataFrame(data=os_data_X,columns=columns )
os_data_y= pd.DataFrame(data=os_data_y,columns=["Class"])
print("length of oversampled data is ",len(os_data_X))
print("Number of normal transcation in oversampled data",len(os_data_y[os_data_y["Class"]==0]))
print("No.of fraud transcation",len(os_data_y[os_data_y["Class"]==1]))
print("Proportion of Normal data in oversampled data is ",len(os_data_y[os_data_y["Class"]==0])/len(os_data_X))
print("Proportion of fraud data in oversampled data is ",len(os_data_y[os_data_y["Class"]==1])/len(os_data_X))
length of oversampled data is 398078
Number of normal transcation in oversampled data 199039
No.of fraud transcation 199039 # smote后1:1了
Proportion of Normal data in oversampled data is 0.5
Proportion of fraud data in oversampled data is 0.5
# Let us first do our amount normalised and other that we are doing above #过采样前一定一定要标准化!!!
os_data_X["Normalized Amount"] = StandardScaler().fit_transform(os_data_X['Amount'].reshape(-1, 1))
os_data_X.drop(["Time","Amount"],axis=1,inplace=True)
data_test_X["Normalized Amount"] = StandardScaler().fit_transform(data_test_X['Amount'].reshape(-1, 1))
data_test_X.drop(["Time","Amount"],axis=1,inplace=True)
# Now start modeling
clf= RandomForestClassifier(n_estimators=100)
model(clf,os_data_X,data_test_X,os_data_y,data_test_y)
the recall for this model is : 0.862275449102
TP 144
TN 85253
FP 23
FN 23
----------Classification Report------------------------------------
precision recall f1-score support
0 1.00 1.00 1.00 85276
1 0.86 0.86 0.86 167
avg / total 1.00 1.00 1.00 85443
observation
综合结论就是:随机森林+过采样(直接复制或者smote后,黑白比例1:3)效果比较好!
from:http://www.dataguru.cn/article-11449-1.html
一、项目简介
Credit Card Fraud Detection
https://www.kaggle.com/dalpozz/creditcardfraud
是一个典型的分类问题,欺诈分类的比例比较小,直接使用分类模型容易忽略。在实际应用场景下往往是保证一定准确率的情况下尽量提高召回率。一个典型案例是汽车制造行业,一旦发生一例汽车安全故障,同批次的车辆需要全部召回,造成了巨大的经济损失。
二、数据印象
2.1. 简单数据分析
数据规模:中度规模(对于mac而言)。数据共284807条,后期算法选择需要注意复杂度。
数据特征:V1~V28是PCA的结果,而且进行了规范化,可以做一些统计上的特征学习;Amount字段和Time字段可以进行额外的统计学和bucket统计。
数据质量:无缺失值,数据规整,享受啊。
经验:时间字段较好可以处理为月份、小时和日期,直接的秒数字段往往无意义。
2.2. 探索性数据分析
三、数据预处理
数据已经十分规整了,所以先直接使用基础模型来预测下数据。
L1规划化
L1规范化的模型
L2规范化
L2规范化的模型
Baseline基础模型:采用线性模型,利用L1的稀疏性,precision和recall均可以达到0.85左右,roc_auc可以达到0.79左右。
基础模型结果
由上图可见:
precision较大时波动波动比较大。recall大于0.8后,准确率下滑严重。
AUC面积是0.97,后来根据参考文献3知,AUC大于0.92时之后比较难修正。
Baseline模型的评价metric:
收集更多的数据,不适合这个场景。
改变评价标准:
使用混淆矩阵计算准确度和回收度。
F1score
Kappa
ROC curves - sensitivity/specificity ratio
数据采样处理
- 收集等多数据:不适合这个场景。- 过采样Over-sampling:当数据集较少时,主动添加少类别的数据;
SMOT算法通过插值来实现。不适合本数据集。容易过拟合,运算时间长。- 欠采样Under-sampling:
当数据集足够大时,删除大类别的数据;集成方法`EasyEnsemble/BalanceCascade`
通过将反例放在不同学习器中使用,从全局看不会丢失重要信息。
本案例数据量中等:选用欠采样+EasyEnsemble的方式进行数据处理。
使用im-balanced生成测试数据。
http://contrib.scikit-learn.org/imbalanced-learn/auto_examples/index.html
from imblearn.ensemble import EasyEnsemblen_subsets = X.size * 2 /
(us_X.size) - 1ee = EasyEnsemble(n_subsets=n_subsets)sample_X,
sample_y = ee.fit_sample(X, y)
四、模型印象
模型:
选用easy_ensemble模型来优化。
具体实现代码见在线脚本
核心adboost代码如下:
结果如下:
easy_ensembel
对比普通的adboost数据
对比图
由上图可知,easy_ensemble提升了平滑度,但是AUC未有提升。
五、特征选择和特征学习
L1模型进行了嵌入式的特征选择,效果优于L2模型。在寻找解释性时会有帮助。
根据数据的统计特征,可以学习一些统计变量。
统计学习
增加如下的特征。
六、分析结果
使用SNE分析(常用于非线性可视化分析)来观看一次under_sample的结果。
https://bindog.github.io/blog/2016/06/04/from-sne-to-tsne-to-largevis/
如下图所示
SNE图
由上图可知两种类别的数据是可以区分的,但是部分数据融合在一起,当追求recall较大时,将会误判大量数据。
七、迭代问题
可以优化的方向:
可以通过学习新的特征,将数据在新维度上拉开距离
在计算机能力允许的情况下,设置合适的round轮次来调参。
八、表述模型
根据模型的SNE图和数据性可知,数据质量是比较好的。
easy_ensemble模型本身使用了adboost和bagging,每棵tree的复杂度不高,降低了bias;通过bagging,降低了variance。最终得到了较好的P-R图和AUC值。
通过LR模型的稀疏性特征值,可以制作出一个解释性报告。
参考
GBM vs xgboost vs lightGBM
https://www.kaggle.com/nschneider/gbm-vs-xgboost-vs-lightgbm
imbalanced-learn
http://contrib.scikit-learn.org/imbalanced-learn/index.html
Exploratory Undersampling for Class-Imbalance Learning
https://cs.nju.edu.cn/zhouzh/zhouzh.files/publication/tsmcb09.pdf
手机扫一扫
移动阅读更方便
你可能感兴趣的文章