機器學習實戰(一):信用卡異常交易識別

1.數據處理

1.1 數據集初始可視化與問題查詢

數據集處理是機器學習中極其重要的一步,不同的測試集與訓練集構建方法會對機器學習的效果帶來巨大的影響。因此,常常在開始訓練模型之前,我們就做好不同重點的測試集與訓練集構建方法。

在處理數據集之前,可以針對感興趣的變量進行初步的可視化(直方圖、密度圖、時許圖等),並查詢數據集存在的問題(數據分佈有偏、量級差距過大、有缺失值等)

1.1.1 數據集查看與初始可視化
>>>data.head()
   Time        V1        V2        V3  ...       V27       V28  Amount  Class
0   0.0 -1.359807 -0.072781  2.536347  ...  0.133558 -0.021053  149.62      0
1   0.0  1.191857  0.266151  0.166480  ... -0.008983  0.014724    2.69      0
2   1.0 -1.358354 -1.340163  1.773209  ... -0.055353 -0.059752  378.66      0

# 查看Class分佈
data['Class'].value_counts()
0    284315
1       492
Name: Class, dtype: int64

# 查看數據集中是否存在確實值
data.isnull().all()
data.isnull().any()

# 數據標籤直方圖
count_classes = pd.value_counts(data['Class'],sort = True).sort_index()
count_classes.plot(kind = 'bar')
plt.title('Fraud class histogram')
plt.xlabel('Class')
plt.ylabel('Frequency')
plt.show()

該數據集有包含Time在內的30個變量,其中Class中,0爲正樣本,1爲負樣本;
初步判斷Time對本問題是不重要的變量,Amount變量與其他變量數量級差別過大,需進行標準化操作;
無缺失值;
正樣本與負樣本差距過大,考慮採取下采樣、過採樣兩種訓練集與測試集劃分方式。

1.1.2 數據處理

針對在上一步得到的問題進行數據處理,標準化處理是常見的必須操作。

# 數據標準化處理
from sklearn.preprocessing import StandardScaler
data['normAmount'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1,1))
data = data.drop(['Time','Amount'],axis = 1)

>>>data.head()
         V1        V2        V3  ...       V28  Class  normAmount
0 -1.359807 -0.072781  2.536347  ... -0.021053      0    0.244964
1  1.191857  0.266151  0.166480  ...  0.014724      0   -0.342475
2 -1.358354 -1.340163  1.773209  ... -0.059752      0    1.160686
3 -0.966272 -0.185226  1.792993  ...  0.061458      0    0.140534
4 -1.158233  0.877737  1.548718  ...  0.215153      0   -0.073403

2.訓練集與測試集的構建

測試集與訓練集的不同構建方式會對模型結果產生非常大的影響。在劃分數據集時,常見的流程是,先進行數據切片,在訓練集中對模型進行訓練,得到最優的模型之後,將該模型應用於測試集中進一步完善,最後將此模型應用於實踐。

2.1 預備工作

將特徵與標籤、正樣本與負樣本區分開來,以便後續操作。同時設置好測試集。

X = data.iloc[:,data.columns!='Class']
y = data.iloc[:,data.columns =='Class']

positve_indices = np.array(data[data.Class==0].index)
negative_indices = np.array(data[data.Class ==1].index)

# 得到有效測試集X_test,y_test
X_train,X_test,y_train,y_test =  train_test_split(X,y,test_size=0.3,random_state = 0)  
2.1 下采樣方式

下采樣方式是使得訓練集中的正樣本與負樣本個數相同(削減正樣本的數量)。

from sklearn.model_selection import train_test_split

# 隨機抽樣得到正樣本索引
random_positive_indices = np.random.choice(positve_indices,len(negative_indices),replace = False)
# 得到下采樣數據集索引
undersample_indices = np.array(list(random_positive_indices)+list(negative_indices)).flatten()

X_undersample = X.iloc[undersample_indices,:]
y_undersample = y.iloc[undersample_indices,:]

# 得到有效訓練集X_undersample_train,y_undersample_train
X_undersample_train,X_undersample_test,y_undersample_train,y_undersample_test = train_test_split(X_undesample,y_undersample,test_size=0.3,random_state = 0)
                                                 

有效訓練集X_undersample_train,y_undersample_train用於訓練模型
有效測試集y_test用於測試模型
爲什麼不用y_undersample_test來測試?首先,應當放到真實環境中去測試。其次,y_undersample_test中,正樣本與負樣本的個數比與原數據集的情況差別過大。

2.2 過採樣方式

SMOTE方式是使得訓練集中的正樣本與負樣本個數相同(增加負樣本的數量)。

# 保證每一次生成的樣本是一樣的
oversampler = SMOTE(random_state=0)
# 從訓練集中生成,使得數據集中正樣本數量與負樣本數量一致
os_features, os_labels = oversampler.fit_sample(X_train,y_train) 

# 得到訓練集os_features_train,os_labels_train
os_features_train,os_features_test,os_labels_train,os_features_test=train_test_split(os_features,os_features,test_size=0.3,random_state=0)

# 生成數據框方便矩陣運算
os_features_train = pd.DataFrame(os_features_train)
os_labels_train = pd.DataFrame(os_labels_train)

3.KFold交叉驗證

3.1 K折交叉驗證的流程

首先,在設定好測試集之後,就需要對其再次劃分進行K折交叉驗證。生成交叉驗證的代碼如下:

from sklearn.model_selection import KFold
# 交叉驗證:在訓練集中進一步拆分出訓練集與驗證集
# shuffle爲False時,無須設置隨機種子 
fold = KFold(n_splits=5,shuffle=False)
fold = fold.split(X_train_data)

# 查看fold的輸出結果,前者是測試集的index,後者是驗證集的index
for iteration, indices in fold.split(X_train_data):
    print(iteration)
    print(indices)

接着,應將選擇好的模型放入到K折交叉訓練集之中進行訓練。一次訓練的代碼如下(本項目使用邏輯迴歸進行分類):

# 指定算法模型,並且給定參數
lr = LogisticRegression(C = c_param,penalty='l1',solver='liblinear')

# 訓練模型
lr.fit(X_train_data.iloc[iteration,:],y_train_data.iloc[iteration,:].values.ravel())

# 建立好模型後,預測模型結果,使用驗證集
y_pred_undersample = lr.predict(X_train_data.iloc[indices,:].values)

# 有了預測結果之後就可以進行評估了
recall_acc = recall_score(y_train_data.iloc[indices,:].values,y_pred_undersample)
recall_accs.append(recall_acc)

最後,應將每次的結果進行平均,找到最適合的模型,將上述過程封裝成函數爲:

def printing_Kfold_scores(X_train_data,y_train_data):
    fold = KFold(n_splits=5,shuffle=True,random_state = 10)

    # 定義不同力度的正則化懲罰力度
    c_param_range = [0.01,0.1,1,10,100]
    # 生成一個儲存結果的數據框
    results_table = pd.DataFrame(index = range(len(c_param_range),2),columns=['C_parameter','Mean recall score'])
    results_table['C_parameter'] = c_param_range
    j = 0
    for c in c_param_range:
        c_param = c
        print('--------------------------------------')
        print('正則化懲罰力度:',c)
        print('--------------------------------------')
        print('')
        s = 1
        recall_accs = []
        for iteration,indices in fold.split(X_train_data):
            # 指定好模型
            lr = LogisticRegression(C = c_param ,penalty='l1',solver='liblinear')
            # 使用訓練集訓練模型
            lr.fit(X_train_data.iloc[iteration,:],y_train_data.iloc[iteration,:].values.ravel())
            # 使用驗證集進行驗證
            y_pred = lr.predict(X_train_data.iloc[indices,:])
            # 評估預測結果
            recall_acc = recall_score(y_train_data.iloc[indices, :].values, y_pred)
            print('iteration:',s,'召回率爲:',recall_acc)
            s = s+1
            recall_accs.append(recall_acc)
        # 執行完所有的交叉驗證之後,計算平均值
        recall_accs_avg =np.mean(recall_accs)
        print('')
        print('平均召回率爲:',recall_accs_avg)
        print('')
        results_table.iloc[j,1]=recall_accs_avg
        j = j+1
    # 找到最優模型
    best_c = results_table.loc[results_table['Mean recall score'].astype('float32').idxmax()]['C_parameter']
    print('*************************************************************')
    print('效果最好的模型所選參數=',best_c)
    print('*************************************************************')

    return best_c

下采樣數據集結果:

--------------------------------------
正則化懲罰力度: 0.01
--------------------------------------
iteration: 1 召回率爲: 0.9428571428571428
iteration: 2 召回率爲: 0.9264705882352942
iteration: 3 召回率爲: 0.9523809523809523
iteration: 4 召回率爲: 0.953125
iteration: 5 召回率爲: 0.9743589743589743
平均召回率爲: 0.9498385315664727
--------------------------------------
正則化懲罰力度: 0.1
--------------------------------------
iteration: 1 召回率爲: 0.9
iteration: 2 召回率爲: 0.8529411764705882
iteration: 3 召回率爲: 0.8888888888888888
iteration: 4 召回率爲: 0.90625
iteration: 5 召回率爲: 0.9230769230769231
平均召回率爲: 0.89423139768728
--------------------------------------
正則化懲罰力度: 1
--------------------------------------
iteration: 1 召回率爲: 0.9
iteration: 2 召回率爲: 0.8676470588235294
iteration: 3 召回率爲: 0.9365079365079365
iteration: 4 召回率爲: 0.90625
iteration: 5 召回率爲: 0.9102564102564102
平均召回率爲: 0.9041322811175754
--------------------------------------
正則化懲罰力度: 10
--------------------------------------
iteration: 1 召回率爲: 0.9285714285714286
iteration: 2 召回率爲: 0.8823529411764706
iteration: 3 召回率爲: 0.9365079365079365
iteration: 4 召回率爲: 0.890625
iteration: 5 召回率爲: 0.9102564102564102
平均召回率爲: 0.9096627433024492
--------------------------------------
正則化懲罰力度: 100
--------------------------------------
iteration: 1 召回率爲: 0.9285714285714286
iteration: 2 召回率爲: 0.8970588235294118
iteration: 3 召回率爲: 0.9365079365079365
iteration: 4 召回率爲: 0.890625
iteration: 5 召回率爲: 0.9102564102564102
平均召回率爲: 0.9126039197730375
*************************************************************
效果最好的模型所選參數= 0.01
*************************************************************

SMOTE過採樣方案結果:

--------------------------------------
正則化懲罰力度: 0.01
--------------------------------------
iteration: 1 召回率爲: 0.9153998203054807
iteration: 2 召回率爲: 0.9141990724224046
iteration: 3 召回率爲: 0.9115085480807139
iteration: 4 召回率爲: 0.9114050411779386
iteration: 5 召回率爲: 0.9098122284852619
平均召回率爲: 0.9124649420943598
--------------------------------------
正則化懲罰力度: 0.1
--------------------------------------
iteration: 1 召回率爲: 0.917340521114106
iteration: 2 召回率爲: 0.9166250445950767
iteration: 3 召回率爲: 0.913909895702663
iteration: 4 召回率爲: 0.9136867624514243
iteration: 5 召回率爲: 0.9121459088787564
平均召回率爲: 0.9147416265484052
--------------------------------------
正則化懲罰力度: 1
--------------------------------------
iteration: 1 召回率爲: 0.9184905660377358
iteration: 2 召回率爲: 0.9170174812700678
iteration: 3 召回率爲: 0.9143399878140569
iteration: 4 召回率爲: 0.9147919711932689
iteration: 5 召回率爲: 0.9129716727103006
平均召回率爲: 0.9155223358050861
--------------------------------------
正則化懲罰力度: 10
--------------------------------------
iteration: 1 召回率爲: 0.9178796046720575
iteration: 2 召回率爲: 0.9170888333927935
iteration: 3 召回率爲: 0.9144116698326225
iteration: 4 召回率爲: 0.9147919711932689
iteration: 5 召回率爲: 0.912325422755179
平均召回率爲: 0.9152995003691844
--------------------------------------
正則化懲罰力度: 100
--------------------------------------
iteration: 1 召回率爲: 0.9187061994609165
iteration: 2 召回率爲: 0.917160185515519
iteration: 3 召回率爲: 0.9148417619440163
iteration: 4 召回率爲: 0.9148989268779636
iteration: 5 召回率爲: 0.9124331310810325
平均召回率爲: 0.9156080409758897
*************************************************************
效果最好的模型所選參數= 100.0
*************************************************************

可以看到,針對不同的數據方式,其得到的結果可能會產生非常的差異。

3.2 K折交叉驗證模型結果的可視化

針對分類問題有許多模型效果評估指標,比如混淆矩陣,ROC,AUC等等。這裏僅使用混淆矩陣作爲示範。

import itertools

def plot_confusion_matrix(cm,classes,title = 'Confusion matrix', cmap = plt.cm.Blues):
    plt.imshow(cm,interpolation='nearest',cmap = cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks,classes,rotation = 0)
    plt.yticks(tick_marks,classes)

    thresh = cm.max()/2
    for i,j in itertools.product(range(cm.shape[0]),range(cm.shape[1])):
        plt.text(j,i,cm[i,j],
                 color = 'white'
                 if cm[i,j]>thresh
                 else 'black')
    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

下采樣方法的混淆矩陣

class_names = [0,1]
lr = LogisticRegression(C=best_c1,penalty='l1',solver='liblinear')
lr.fit(X_undersample_train,y_undersample_train.values.ravel())
y_pred_undersample = lr.predict(X_undersample_test.values)
cnf_matrix = confusion_matrix(y_undersample_test,y_pred_undersample)
np.set_printoptions(precision =2)
plot_confusion_matrix(cnf_matrix,classes=class_names,title = 'Confusion matrix')
plt.show()

在這裏插入圖片描述

SMOTE過採樣方法的混淆矩陣
在這裏插入圖片描述

4.問題查詢

可以從混淆矩陣中找到合適的閾值,來影響分類效果。

# 閾值對結果的影響
lr = LogisticRegression(C=0.01,penalty='l1',solver='liblinear')

# 訓練模型
lr.fit(X_train_undersample,y_train_undersample.values.ravel())

# 爲了控制閾值,因此返回概率值
y_pred_undersample_proba = lr.predict_proba(X_test_undersample.values)

# 指定不同的閾值
thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9] #0.4稍微異常就被抓,0.9非常有可能是的時候才抓起來
plt.figure(figsize=(10,10))
j=1
# 用混淆矩陣來進行展示
for i in thresholds:
    y_test_predictions_high_recall = y_pred_undersample_proba[:,1]>i
    plt.subplot(3,3,j)
    j +=1

    cnf_matrix = confusion_matrix(y_test_undersample,y_test_predictions_high_recall)
    np.set_printoptions(precision = 2)
    print('給定閾值爲:',i,'時測試集召回率:',cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))

    class_names = [0,1]
    plot_confusion_matrix(cnf_matrix,
                          classes=class_names,
                          title='Threshold>=%s'%i)
plt.show()

在這裏插入圖片描述

參考:唐宇迪python實戰課;周志華《機器學習》

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