邏輯迴歸實現信用卡欺詐預測

使用的數據集爲creditcard.csv,先使用pandas讀取數據集並查看下數據集的內容。

# 讀取數據集並查看數據屬性
data = pd.read_csv("creditcard.csv")
print(data.head())

圖一

觀察上面的數據後,由於這是一個分類問題,所以說我們需要查看數據的類別分佈是否是均衡的,如果不均衡則會影響分類的結果。由於繪製的圖形不是很難,所以使用pandas自帶的繪圖API即可(series.plot)。

# 作爲一個二分類問題,先查看下樣本分佈是否均衡
count_classes = pd.value_counts(data['Class'], sort=True).sort_index()
print(type(count_classes))
# 繪製分佈圖
count_classes.plot(kind = 'bar')
plt.title("Fraud class histogram")
plt.xlabel("Class")
plt.ylabel("Frequency")
plt.show()

由圖像可以看出,數據集的類別分佈十分不均勻,大部分都是0類(正常用戶),而1類用戶(欺詐用戶)是筆記少的,所以我們需要對數據進行處理,這裏的話可以採用兩種方式,向上採樣和向下採樣,向上採樣的意思是對於不足的類別進行生成(最簡單的辦法每個屬性分佈使用其屬性的均值即可),向下採樣(數量多的樣本選取出一定數目的樣本用於訓練,使其數目和數量少的樣本保持一致)。

而再處理向上採樣和向下採樣之前,我們需要先對數據進行一些預處理。由圖一可以看出,數據集中Amount屬性的分佈十分不均勻,或大或小,而且和其他屬性的值相差過大,這樣對於大部分模型來說,會讓算法誤以爲這個屬性十分重要,但是這個是不一定的,所以我們需要對這個屬性進行預處理,一般來說是使用歸一化或者標準化即可,在這裏我們使用標準化。而time屬性很明顯是一個無關的屬性,所以我們選擇直接捨棄這個屬性。

# 由於Amount屬性不均衡,所以對其進行歸一化處理
data['normAmount'] = StandardScaler().fit_transform(data['Amount'].reshape(-1, 1))
data = data.drop(['Time', 'Amount'], axis=1)
print(data.head())

下面對數據進行向下採樣

# 採用向下採樣
# 計算1類數目
number_records_fraud = len(Y[Y.Class == 1])
# 分別取出0、1類數據索引
fraud_indices = np.array(data[data.Class == 1].index)
normal_indices = data[data.Class == 0].index

# 隨機選取出和1類數據相同的0類數據樣本索引
random_normal_indices = np.random.choice(normal_indices, number_records_fraud, replace=False)

# 和並採樣好的0、1類樣本索引
under_sample_indices = np.concatenate([fraud_indices, random_normal_indices])
# 根據所以生成數據
under_sample_data = data.iloc[under_sample_indices, :]
# 劃分採樣好的數據以便訓練
X_undersample = under_sample_data.ix[:, under_sample_data.columns != 'Class']
y_undersample = under_sample_data.ix[:, under_sample_data.columns == 'Class']
# 查看採樣後類別分佈
print("Percentage of normal transactions: ",len(under_sample_data[under_sample_data.Class == 0]) / len(under_sample_data))
print("Percentage of fraud transactions: ",len(under_sample_data[under_sample_data.Class == 1]) / len(under_sample_data))
print("Total number of transactions in resampled data: ", len(under_sample_data))

接下來要開始訓練模型了,在訓練模型之前需要先了解交叉驗證,以及模型評估。畢竟只有瞭解了這個,才能清楚的更好的訓練模型,已經評估什麼模型是好的。

什麼是交叉驗證呢,交叉驗證的原理來自概率論課本的驗證章節,這裏就不多介紹了。這裏我們使用通俗的語言來介紹什麼是交叉驗證。交叉驗證的目標就是讓模型的泛化能力更好,因爲如果一直使用相同的數據做訓練集的話,模型很容易造成過擬合問題,爲了解決這個問題,交叉驗證的做法是,首先把模型分成n個部分,一個部分做測試集,剩下的n-1個部分做訓練集,然後每次選用不同的部分來做測試集,訓練n次,這樣做的話,就可以讓模型的泛化能力更好,因爲他提取了更多數據的特徵。

那麼怎樣進行模型評估呢,由於欺詐樣本再全部樣本中所佔的比例比較小,所以我們不能僅僅使用準確率來判斷模型的好壞,因爲就算全部判斷爲0類,準確率也有百分之九十以上,所以再這裏我們要使用召回率也就是查全率來對模型進行評估,公式爲recall=TP/(TP + FN),其中TP意思是正類判斷爲正類,FP負類判斷爲正類,FN正類判斷爲負類,TN負類判斷爲負類。

還有一種增加模型泛化能力的方法就是添加正則化參數,接下來我們就使用交叉驗證的方法選取出最合適的正則化參數,評價的標準爲召回率

# 劃分原始數據,用作測試
X_train, X_test, y_train, y_test = train_test_split(X , Y, test_size=0.3, random_state=0)
# 劃分下采樣數據集,用作訓練
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)

# 訓練出最佳的正則化參數
# 結果爲0.01
# best_c = printing_Kfold_scores(X_train_undersample, y_train_undersample)
best_c = 0.01
def printing_Kfold_scores(x_train_data, y_train_data):
    '''
    :param x_train_data: 訓練集
    :param y_train_data: 測試集
    :return: 最佳正則化參數
    '''

    # 交叉驗證數據集劃分
    fold = KFold(5, shuffle=False)

    # 多個正則化參數用於調參使用
    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_param in c_param_range:
        # 尋找較好的正則化參數
        print('-------------------------------------------')
        print('C parameter: ', c_param)
        print('-------------------------------------------')
        print('')

        recall_accs = []
        for iteration, indices in enumerate(fold.split(x_train_data), start=1):
            # 創建邏輯迴歸模型
            lr = LogisticRegression(C=c_param, penalty='l1')
            # the k-fold will give 2 lists: train_indices = indices[0], test_indices = indices[1]
            # 寫入訓練數據
            lr.fit(x_train_data.iloc[indices[0], :], y_train_data.iloc[indices[0], :].values.ravel())
            # 預測結果
            y_pred_undersample = lr.predict(x_train_data.iloc[indices[1], :].values)
            recall_acc = recall_score(y_train_data.iloc[indices[1], :].values, y_pred_undersample)
            # 計算召回率
            recall_accs.append(recall_acc)
            print('Iteration ', iteration, ': recall score = ', recall_acc)

        results_table.ix[j, 'Mean recall score'] = np.mean(recall_accs)
        j += 1
        print('')
        print('Mean recall score ', np.mean(recall_accs))
        print('')

    # 選擇召回率最高的正則化參數返回
    best_c = results_table.loc[results_table['Mean recall score'].idxmax()]['C_parameter']

    # Finally, we can check which C parameter is the best amongst the chosen.
    print('*********************************************************************************')
    print('Best model to choose from cross validation is with C parameter = ', best_c)
    print('*********************************************************************************')

    return best_c

選取出了最合適的正則化參數後,我們可視化下混淆矩陣,混淆矩陣的作用就是讓召回率更加清楚的展現給我們看

# 繪製混淆矩陣圖像
def plot_confusion_matrix(cm, classes,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    """
    This function prints and plots the confusion matrix.
    """
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    # 將標籤印在x軸座標上
    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],
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')
# 查看混淆矩陣
lr = LogisticRegression(C=best_c, penalty='l1')
lr.fit(X_train_undersample, y_train_undersample.values.ravel())
y_pred_undersample = lr.predict(X_test_undersample.values)

# 計算混淆矩陣
cnf_matrix = confusion_matrix(y_test_undersample, y_pred_undersample)
# 設置輸出精度爲2
np.set_printoptions(precision=2)
# 計算找回率Recall = TP/(TP+FN)
print("Recall metric in the testing dataset: ", cnf_matrix[1, 1] / (cnf_matrix[1, 0] + cnf_matrix[1, 1]))
# 繪製混淆矩陣
class_names = [0, 1]
plt.figure()
plot_confusion_matrix(cnf_matrix
                          , classes=class_names
                          , title='Confusion matrix')
plt.show()

由此的話,使用邏輯迴歸對信用卡欺詐預測就已經完成了。

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