機器學習實戰:基於邏輯迴歸模型的信用卡欺詐檢測

某銀行爲提升信用卡反欺詐檢測能力,提供了脫敏後的一份個人交易記錄。考慮數據本身的隱私性,數據提供之初已經進行了類似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==1class==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.70.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)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章