某银行为提升信用卡反欺诈检测能力,提供了脱敏后的一份个人交易记录。考虑数据本身的隐私性,数据提供之初已经进行了类似PCA的处理,并得到了若干数据特征。在不需要做额外特征提取工作的情况下,本项目意在通过逻辑回归模型的调优,得到较为准确可靠的反欺诈检测方法,分析过程中使用到了Python Pandas, Numpy, Matplotlib, Seaborn以及机器学习库Scikit-Learn等。
数据链接:
链接:https://pan.baidu.com/s/11uT0CHYPenX_67qTdr-Tjg
密码:b9xo
完整代码实现如下:
下采样完整代码:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold,cross_val_score #cross_val_score交叉验证
from sklearn.metrics import confusion_matrix,recall_score,classification_report
from sklearn.model_selection import cross_val_predict
data = pd.read_csv('/Users/hxx/Downloads/creditcard.csv')
print(data.head())
#查看数据样本是否均衡(正负样本是否均衡)
pd.value_counts(data['Class'],sort=True).sort_index()
#print(pd.value_counts(data['Class'],sort=True).sort_index())#value_count计算某列属性中属性不为1的值有多少个
count_classes = pd.value_counts(data['Class'],sort=True).sort_index()#value_counts()是一种查看表格某列中有多少个不同值的快捷方法,并计算每个不同值有在该列中有多少重复值。
count_classes.plot(kind='bar')##简单的pandas也可以画图,kind=bar画的条状图,kind=line画的线性图
plt.title('Fraud class histogrm')
plt.xlabel('Class')
plt.ylabel('Frequency')
plt.show()
#从上图中可以发现,正反数据比例不均衡,因此引入采样对数据进行调整
#采样分为下采样和上采样,下采样就是对数据量大的进行减少,上采样就是对数据量较少的进行添加数据
# 预处理
#我们从数据中发现Amount这个属性对应的数据值与其他属性数据相差过大,因此进行标准化处理
#标准化就是对数据先减去均值在处以标准差,去均值的好处使数据关于原点对称,除以标准差好处使各个维度的数据取值范围尽可能的相同
data['normAmount'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1,1))
#Fit()简单来说,就是求得训练集X的均值啊,方差啊,最大值啊,最小值啊这些训练集X固有的属性。可以理解为一个训练过程
#Transform()在Fit的基础上,进行标准化,降维,归一化等操作(看具体用的是哪个工具,如PCA,StandardScaler等)
#fit_transform(Data)对部分数据先拟合fit,找到该part的整体指标,如均值、方差、最大值最小值等等,然后对Data进行转换transform,从而实现数据的标准化、归一化等等
#reshape(a,b)函数中a代表行数,b代表列数,就是转换成a行b列,但是-1代表未指定,因此这边normAmount就是多少行一列的数据
data = data.drop(['Time','Amount'],axis=1)#去掉Time列和Amount列,axis=1代表的列
print(data.head())
# 下采样
X = data.iloc[:,data.columns != 'Class']
y = data.iloc[:,data.columns == 'Class']
#data.iloc函数是基于位置索引,添加条件进行过滤
number_records_fraud = len(data[data.Class==1])
fraud_indices = np.array(data[data.Class==1].index)#用一个数组将class==1的对应的索引记录下来
normal_indices = np.array(data[data.Class==0].index)#得到class==0的对应的索引
#随机选取class==1的索引,个数为class==1的个数
random_normal_indices = np.random.choice(normal_indices,number_records_fraud,replace=False)#replace指定为False时,采样不会重复
#将class==1和class==0的索引集合起来
under_sample_data = np.concatenate([fraud_indices,random_normal_indices])
#从下采样的索引取回对应的其他属性的值
under_sample_data = data.iloc[under_sample_data,:]#把索引还原成对应的数据
X_undersample = under_sample_data.iloc[:,under_sample_data.columns!='Class']#下采样中x的训练数据集
y_undersample = under_sample_data.iloc[:,under_sample_data.columns=='Class']#下采样中y的标签数据集
print("正常样本的占比:",len(under_sample_data[under_sample_data.Class==0])/len(under_sample_data))
print("异常样本的占比:",len(under_sample_data[under_sample_data.Class==1])/len(under_sample_data))
print("下采样策略的总体样本数量:",len(under_sample_data))
# 数据集的划分
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3,random_state=0)#random_state是设置随机种子与random seed作用相同,随机种子确定下来,他会随机做,但是固定模式
#print("原始训练集包含样本数量:",len(X_train))
#print("原始测试集包含样本数量:",len(X_test))
#print("原始样本总数:",len(X))
# 下采样数据集的划分
X_train_undersample,X_test_undersample,y_train_undersample,y_test_undersample = train_test_split(X_undersample,y_undersample,test_size=0.3,random_state=0)
print("下采样训练集包含样本数量:",len(X_train_undersample))
print("下采样试集包含样本数量:",len(X_test_undersample))
print("下采样样本总数:",len(under_sample_data))
def print_Kfold_scores(X_train_data,y_train_data):
#KFold表示k折交叉验证
fold = KFold(5,shuffle=False)#将训练/测试数据集划分5个互斥子集,每次用其中一个子集当作验证集,剩下的4个作为训练集,进行5次训练和测试,得到5个结果.shuffle=False就是不重新洗牌获得的数据一样
#定义不同力度的正则化惩罚力度
c_param_range = [0.01,0.1,1,10,100]
#展示结果用的表格
results_table = pd.DataFrame(columns=['C_parameter','Mean recall score'])
results_table['C_parameter'] = c_param_range
j = 0
for c_param in c_param_range:
print('-----------------------')
print('正则化惩罚力度:',c_param)
print('-----------------------')
print('')
recall_accs = []
for iteration , indices in enumerate(fold.split(X_train_data)):
#print('X_train_data.iloc[indices[0],:]',X_train_data.iloc[indices[0],:])
#print('y_train_data.iloc[indices[0],:]',y_train_data.iloc[indices[0],:])
#print('X_train_data.iloc[indices[1],:]',X_train_data.iloc[indices[1],:])
#enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标
lr = LogisticRegression(C = c_param,penalty='l2')
#训练模型,注意索引不要给错,训练的时候一定传入的是训练集,所以x和y的索引都是0
lr.fit(X_train_data.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())
#建立好模型后,预测模型结果,这里用的是验证机,索引为1
y_pred_undersample = lr.predict(X_train_data.iloc[indices[1],:].values)
#有了预测结果后进行评估,这里recall_score需要引入预测值和真实值
recall_acc = recall_score(y_train_data.iloc[indices[1],:],y_pred_undersample)
#一会还要算平均,所以每一步结果保存起来
recall_accs.append(recall_acc)
print('Iteration',iteration,':召回率:',recall_acc)
results_table.loc[j,'Mean recall score'] = np.mean(recall_accs)
j+=1
print('')
print('平均召回率',np.mean(recall_accs))
print('')
best_c =results_table.loc[results_table['Mean recall score'].astype('float32').idxmax()]['C_parameter']
print('*************************')
print('效果最好的模型所选参数=',best_c)
return best_c
best_c = print_Kfold_scores(X_train_undersample,y_train_undersample)
lr = LogisticRegression(C = best_c,penalty='l2')
lr.fit(X_train_undersample,y_train_undersample)#用下采样x和y的训练集训练模型
y_pred_undersample = lr.predict(X_test)#用真正的x测试集进行预测
recall = recall_score(y_test,y_pred_undersample)#将真正的x测试集结果与y的测试集得到召回率
print('召回率:',recall)
上采样完整代码如下:
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from imblearn.over_sampling import SMOTE
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix,recall_score
from sklearn.model_selection import KFold,cross_val_score #cross_val_score交叉验证
data = pd.read_csv('/Users/hxx/Downloads/creditcard.csv')
dataMatrix = np.mat(data)
X = dataMatrix[:,:-1]#除了最后一列其他的都为x数据集
y = dataMatrix[:,-1]#最后一列为y的数据集
print(len(y))
#标准化
scaler = StandardScaler().fit(X)
dataStand = scaler.transform(X)
print(dataStand[:5,:])
#将数据集划分0.7和0.3
x_train,x_test,y_train,y_test = train_test_split(X,y,test_size=0.3,random_state=0)
oversample = SMOTE()#实例化
#我们只是对训练数据集的少样本进行生成,不需要懂测试集
x_train_oversample,y_train_oversample = oversample.fit_sample(x_train,y_train)
#print(len(y_train))#过采样前训练数据集的数量199364
#print(len(y_train_oversample))#过采样后训练数据集的数量398038
def print_Kfold_scores(X_train_data,y_train_data):
#KFold表示k折交叉验证
fold = KFold(5,shuffle=False)#将训练/测试数据集划分5个互斥子集,每次用其中一个子集当作验证集,剩下的4个作为训练集,进行5次训练和测试,得到5个结果.shuffle=False就是不重新洗牌获得的数据一样
#定义不同力度的正则化惩罚力度
c_param_range = [0.01,0.1,1,10,100]
#展示结果用的表格
results_table = pd.DataFrame(columns=['C_parameter','Mean recall score'])
results_table['C_parameter'] = c_param_range
j = 0
for c_param in c_param_range:
print('-----------------------')
print('正则化惩罚力度:',c_param)
print('-----------------------')
print('')
recall_accs = []
for iteration , (train,test) in enumerate(fold.split(X_train_data,y_train_data)):
lr = LogisticRegression(C = c_param,penalty='l2')#l2正则化
x_train,x_test,y_train,y_test=X_train_data[train],X_train_data[test],y_train_data[train],y_train_data[test]
#训练
lr.fit(x_train,y_train)
#预测
y_pred_undersample = lr.predict(x_test)
#计算召回率
recall_acc = recall_score(y_test,y_pred_undersample)
#一会还要算平均,所以每一步结果保存起来
recall_accs.append(recall_acc)
print('Iteration',iteration,':召回率:',recall_acc)
results_table.loc[j,'Mean recall score'] = np.mean(recall_accs)
j+=1
print('')
print('平均召回率',np.mean(recall_accs))
print('')
best_c =results_table.loc[results_table['Mean recall score'].astype('float32').idxmax()]['C_parameter']
print('*************************')
print('效果最好的模型所选参数=',best_c)
return best_c
best_c = print_Kfold_scores(x_train_oversample,y_train_oversample)#上采样x和y的训练集
#下面是真正的测试
lr = LogisticRegression(C=best_c,penalty='l2')
lr.fit(x_train_oversample,y_train_oversample)#用上采样x和y的训练集训练模型
y_pred_oversample = lr.predict(x_test)#用真正的x测试集进行预测
recall = recall_score(y_test,y_pred_oversample)#将真正的x测试集结果与y的测试集得到召回率
print('召回率1:',recall)