本文共 8561 字,大约阅读时间需要 28 分钟。
某银行为提升信用卡反欺诈检测能力,提供了脱敏后的一份个人交易记录。考虑数据本身的隐私性,数据提供之初已经进行了类似PCA的处理,并得到了若干数据特征。在不需要做额外特征提取工作的情况下,本项目意在通过逻辑回归模型的调优,得到较为准确可靠的反欺诈检测方法,分析过程中使用到了Python Pandas, Numpy, Matplotlib, Seaborn以及机器学习库Scikit-Learn等。
数据链接:
链接:https://pan.baidu.com/s/11uT0CHYPenX_67qTdr-Tjg 密码:b9xo完整代码实现如下:
下采样完整代码:import pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.preprocessing import StandardScalerfrom sklearn.model_selection import train_test_splitfrom sklearn.linear_model import LogisticRegressionfrom sklearn.model_selection import KFold,cross_val_score #cross_val_score交叉验证from sklearn.metrics import confusion_matrix,recall_score,classification_reportfrom sklearn.model_selection import cross_val_predictdata = 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_cbest_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 pdimport numpy as npfrom sklearn.preprocessing import StandardScalerfrom imblearn.over_sampling import SMOTEfrom sklearn.metrics import confusion_matrixfrom sklearn.model_selection import train_test_splitfrom sklearn.linear_model import LogisticRegressionfrom sklearn.metrics import confusion_matrix,recall_scorefrom 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.3x_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))#过采样后训练数据集的数量398038def 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_cbest_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)
转载地址:http://jfulf.baihongyu.com/