機器學習項目實戰----信用卡欺詐檢測(一)

 1、任務基礎

數據集包含由歐洲人於2013年9月使用信用卡進行交易的數據。此數據集顯示兩天內發生的交易,其中284807筆交易中有492筆被盜刷。數據集很是不平衡,正例(被盜刷)佔全部交易的0.172%。,這是由於因爲保密問題,咱們沒法提供有關數據的原始功能和更多背景信息。特徵V1,V2,... V28是使用PCA得到的主要組件,沒有用PCA轉換的惟一特徵是「Class」和「Amount」。特徵'Time'包含數據集中每一個刷卡時間和第一次刷卡時間之間通過的秒數。特徵'Class'是響應變量,若是發生被盜刷,則取值1,不然爲0。python

任務目的是完成數據集中正常交易數據和異常交易數據的分類,並對測試數據進行預測。app

數據集連接:https://pan.baidu.com/s/1GTeCYPhDEan_8c5t7Si_qw 提取碼:b93f dom

首先導入須要使用的庫機器學習

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

讀取數據集文件,查看數據集前5行數據函數

data = pd.read_csv("creditcard.csv")
data.head()

在上圖中Class標籤表明數據分類,0表明正常數據,1表明欺詐數據。 學習

這裏是作信用卡數據的欺詐檢測。在整個數據裏面,有正常的數據,也有問題的數據。對於通常狀況來講,有問題的數據確定只佔了極少部分。測試

下面繪出柱狀圖能夠直觀顯示正常數據與異常數據的數量差別。  this

count_classes = pd.value_counts(data['Class'], sort=True).sort_index()
count_classes.plot(kind='bar') # 使用pandas能夠繪製一些簡單的圖
# 欺詐類別柱狀圖
plt.title("Fraud class histogram")
plt.xlabel("Class")
# 頻率
plt.ylabel("Frequency")

  

從輸出的結果能夠看出正常的樣本0大概有28萬個,異常的樣本1很是少,從圖中不太容易看出來,可是其實是存在的,大概只有那麼幾百個。spa

由於Amount這列的數據浮動太大,在作機器學習的過程當中,須要保證特徵值差別不能過大,因而須要對Amount進行預處理,標準化數據3d

Time這一列自己沒有多大用處,Amount這一列被標準化後的數據代替。全部刪除這兩列的數據。

# 預處理  標準化數據
from sklearn.preprocessing import StandardScaler
# norm 標準  -1表示自動判斷X維度  對比源碼 這裏要加上.values
# 加上新的特徵列 data['normAmount'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1, 1)) data = data.drop(['Time', 'Amount'], axis=1) data.head()

2、樣本數據分佈不均衡解決方案

上面說到數據集裏面正常數據和異常數據數量差別極大,對於這種樣本數據不均衡問題,通常有如下兩種策略:

(1)下采樣策略:以前統計的結果能夠看出0的樣本有28萬個,而1的樣本只有幾百個。如今將0的數據也變成幾百個就能夠了。下采樣,是使樣本的數據一樣少
(2)過採樣策略:以前統計的結果能夠看出0的樣本有28萬個,而1的樣本只有幾百個。0比較多1比較少,對1的樣本數據進行生成數列,讓生成的數據與0的樣本數據同樣多。

下面首先採用下采樣策略

# loc 基於標籤索引  iloc 基於行號索引
# ix 基於行號和標籤索引都行  可是已被放棄

# X = data.ix[:, data.columns != 'Class']
# # print(X)
# y = data.ix[:, data.columns == 'Class']

X = data.iloc[:, data.columns != 'Class'] # 特徵數據
# print(X)
y = data.iloc[:, data.columns == 'Class'] # 

# Number of data points in the minority class 選取少部分異常數據集
number_records_fraud = len(data[data.Class == 1])
fraud_indices = np.array(data[data.Class == 1].index)

# Picking the indices of the normal classes 選取正常類的索引
normal_indices = data[data.Class == 0].index

# Out of the indices we picked, randomly select "x" number (number_records_fraud)
# 從正常類的索引中隨機選取 X 個數據  replace 代替的意思
random_normal_indices = np.random.choice(normal_indices,
                                         number_records_fraud,
                                         replace=False)
random_normal_indices = np.array(random_normal_indices)

# Appending the 2 indices
under_sample_indices = np.concatenate([fraud_indices, random_normal_indices])

# Under sample dataset
under_sample_data = data.iloc[under_sample_indices, :]

X_undersample = under_sample_data.iloc[:, under_sample_data.columns != 'Class']
y_undersample = under_sample_data.iloc[:, under_sample_data.columns == 'Class']

# Showing ratio   transactions:交易
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))
Percentage of normal transactions: 0.5
Percentage of fraud transactions: 0.5
Total number of transactions in resampled data: 984

能夠看出通過下采樣策略事後,正常數據與異常數據各佔50%,而且總樣本數也只有少部分。

下面對原始數據集和下采樣後的數據集分別進行切分操做。

# sklearn更新後在執行如下代碼時可能會出現這樣的問題:
# from sklearn.cross_validation import train_test_split
# ModuleNotFoundError: No module named 'sklearn.cross_validation'
# 緣由新版本已經不支持 改成如下代碼
from sklearn.model_selection import train_test_split

# Whole dataset  test_size 表示訓練集測試集的比例  
X_train, X_test, y_train, y_test = train_test_split(X,
                                                    y,
                                                    test_size=0.3,
                                                    random_state=0)

print("Number transactions train dataset:", len(X_train))
print("Number transactions test dataset:", len(X_test))
print("Total number of transactions:", len(X_train) + len(X_test))

# Undersampled dataset
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("")
print("Number transactions train dataset:", len(X_train_undersample))
print("Number transactions test dataset:", len(X_test_undersample))
print("Total number of transactions:", len(X_train_undersample) + len(X_test_undersample))
Number transactions train dataset: 199364
Number transactions test dataset: 85443
Total number of transactions: 284807

Number transactions train dataset: 688
Number transactions test dataset: 296
Total number of transactions: 984

3、模型評估方法:

假設有1000個病人的數據,有990我的不患癌症,10我的是患癌症。用一個最多見的評估標準,比方說精度,就是真實值與預測值之間的差別,真實值用y來表示,預測值用y1來表示。y真實值1,2,3...10,共有10個樣本,y1預測值1,2,3...10,共有10個樣本,精度就是看真實值y與預測值y1是否同樣的,要麼都是0,要麼都是1,若是是一致,就用「=」表示,好比1號真實值樣本=預測值的1號樣本,若是不相等就用不等號來表示。若是等號出現了8個,那麼它的精確度爲8/10=80%,從而肯定模型的精度。

990我的不患癌症,10我的是患癌症創建一個模型,全部的預測值都會創建一個正樣本。對1000個樣本輸入到模型,它的精確度是多少呢?990/1000=99%。這個模型把全部的值都預測成正樣本,可是沒有獲得任何一個負樣本。在醫院是想獲得癌症的識別,可是檢查出來的結果是0個,雖然精度達到了99%,但這個模型是沒有任何的含義的,由於一個癌症病人都找不出來。在創建模型的時候必定要想好一件事,模型雖然很容易創建出來,那麼難點是應該怎麼樣去評估這樣的模型呢?

剛纔提到了用精度去評估模型,可是精度有些時候是騙人的。尤爲是在樣本數據不均衡的狀況下。接下來要講到一個知識點叫recall,叫召回率或叫查全率。recall有0或者1,咱們的目標是找出患有癌症的那10我的。所以根據目標制定衡量的標準,就是有10個癌症病人,可以檢測出來有幾個?若是檢測0個癌症病人,那麼recall值就是0/10=0。若是檢測2個癌症病人,那麼recall值就是2/10=20%。用recall檢測模型的效果更科學一些。創建模型無非是選擇一些參數,recall的表示也並不是那麼容易.在統計學中會常常提到的4個詞,分別以下:

  
# Recall = TP/(TP+FN) Recall(召回率或查全率)
from sklearn.linear_model import LogisticRegression  # 使用邏輯迴歸模型
# from sklearn.cross_validation import KFold, cross_val_score  版本更新這行代碼也再也不支持
from sklearn.model_selection import KFold, cross_val_score  # fold:摺疊 KFold 表示切分紅幾分數據進行交叉驗證
from sklearn.metrics import confusion_matrix, recall_score, classification_report

4、正則化懲罰:

好比有A模型的權重參數:θ一、θ二、θ3...θ10,好比還有B模型的權重參數:θ一、θ二、θ3...θ10,這兩個模型的recall值都是等於90%。若是兩個模型的recall值都是等於90%,是否是隨便選一個均可以呢?
可是假如A模型的參數浮動比較大,具體如截圖:

  

B模型的參數浮動較小,如截圖所示:

  

雖然兩個模型的recall值都是等於90%,可是A模型的浮動範圍太大了,咱們但願模型更加穩定一些,不光知足訓練的數據,還要儘量的知足測試數據。所以但願模型的浮動差別更小一些,差別小可使過分擬合的風險更小一些。

過分擬合的意思是在訓練集表達效果很好,可是在測試集表達效果不好,所以這組模型發生了過擬合。過擬合是很是常見的現象,很大程度上是由於權重參數浮動較大引發的,所以但願獲得B模型,由於B模型的浮動差別比較小。那麼怎麼樣可以獲得B模型呢?從而就引入了正則化的東西,懲罰模型參數θ,由於模型的數據有時候分佈大,有時候分佈小。但願大力度懲罰A模型,小力度懲罰B模型。咱們能夠利用正則化找到更爲簡潔的描述方式的量化過程,咱們將損失函數改造爲:

  

C0表示未引入正則化懲罰以前的損失函數,C表示引入正則化懲罰後新的損失函數,w表明權重參數值。上面這個式子表達的是L1正則化。對於A模型,w值浮動比較大,若是計算|w|的話,這樣的話計算的目標損失函數的值就會更大。全部就加上λ參數來懲罰這個權重值。下面還有一種L2正則化

  

因而最主要就是須要設置當前懲罰的力度到底有多大?能夠設置成0.1,那麼懲罰力度就比較小,也能夠設置懲罰力度爲1,也能夠設置懲罰力度爲10。可是懲罰力度等於多少的時候,效果比較好呢?具體多少也不知道,須要經過交叉驗證,去評估一下什麼樣的參數達到更好的效果。C_param_range = [0.01,0.1,1,10,100]這裏就是前面提到的λ參數。須要將這5個參數不斷的嘗試。

5、交叉驗證  

好比有個集合叫data,一般創建機器模型的時候,先對數據進行切分或者選擇,取前面80%的數據當成訓練集,取20%的數據當成測試集。80%的數據是來創建一個模型,剩下的20%的數據是用來測試模型。所以第一步是將數據進行切分,切分紅訓練集以及測試集。這部分操做是必需要作的。第二步還要在訓練集進行平均切分,好比平均切分紅3份,分別是數據集1,2,3。

在創建模型的時候,無論創建什麼樣的模型,這個模型伴隨着不少參數,有不一樣的參數進行選擇,這個參數選擇大比較好,仍是選擇小比較好一些?從經驗值角度來講,確定沒辦法很準的,怎麼樣去肯定這個參數呢?只能經過交叉驗證的方式。

那什麼又叫交叉驗證呢?

第一次:將數據集1,2分別創建模型,用數據集3在當前權重下去驗證當前模型的效果。數據集3是個驗證集,驗證集是訓練集的一部分。用驗證集去驗證模型是好仍是壞。
第二次:將數據集1,3分別創建模型,用數據集2在當前權重下去驗證當前模型的效果。
第三次:將數據集2,3分別創建模型,用數據集1在當前權重下去驗證當前模型的效果。

若是隻是求一次的交叉驗證,這樣的操做會存在風險。好比只作第一次交叉驗證,會使3驗證集偏簡單一些。會使模型效果偏高,此外模型有些數據是錯誤值以及離羣值,若是把這些不太好的數據當成驗證集,會使模型的效果偏低的。模型固然是不但願偏高也不但願偏低,那就須要多作幾回交叉驗證模型,求平均值。這裏有1,2,3分別做驗證集,每一個驗證集都有評估的標準。最終模型的效果將1,2,3的評估效果加在一塊兒,再除以3,就能夠獲得模型一個大體的效果。

def printing_Kfold_scores(x_train_data,y_train_data):
    fold = KFold(5,shuffle=False)
    
    # Different C parameters
    c_param_range = [0.01,0.1,1,10,100]
    
    result_table = pd.DataFrame(index=range(len(c_param_range),2),columns=['C_parameter','Mean recall score'])
    result_table['C_parameter'] = c_param_range
    
    # the k-fold will give 2 lists:train_indices=indices[0],test_indices = indices[1]
    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)):
            
            # 使用特定的C參數調用邏輯迴歸模型
            # Call the logistic regression model with a certain C parameter
            # 參數 solver=’liblinear’ 消除警告
            # 出現警告:模型未能收斂 ,請增長收斂次數
            #  ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.
            #  "the number of iterations.", ConvergenceWarning)
            #  增長參數 max_iter 默認1000
            lr = LogisticRegression(C = c_param, penalty='l1', solver='liblinear',max_iter=10000)
            # Use the training data to fit the model. In this case, we use the portion
            # of the fold to train the model with indices[0], We then predict on the
            # portion assigned as the 'test cross validation' with indices[1]
            lr.fit(x_train_data.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())
            
            # Predict values using the test indices in the training data
            y_pred_undersample = lr.predict(x_train_data.iloc[indices[1],:].values)
            
            # Calculate the recall score and append it to a list for recall scores 
            # representing the current c_parameter
            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)
            
        # the mean value of those recall scores is the metric we want to save and get
        # hold of.
        result_table.loc[j,'Mean recall score'] = np.mean(recall_accs)
        j += 1
        print('')
        print('Mean recall score ',np.mean(recall_accs))
        print('')
        
    # 注意此處報錯  源代碼沒有astype('float64')
    best_c = result_table.loc[result_table['Mean recall score'].astype('float64').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

使用下采樣數據集調用上面這個函數  

best_c = printing_Kfold_scores(X_train_undersample,y_train_undersample)

 輸出結果:

-------------------------------------------
C parameter: 0.01
-------------------------------------------

Iteration  0 : recall score =  0.958904109589041
Iteration  1 : recall score =  0.9178082191780822
Iteration  2 : recall score =  1.0
Iteration  3 : recall score =  0.9864864864864865
Iteration  4 : recall score =  0.9545454545454546

Mean recall score  0.9635488539598128

-------------------------------------------
C parameter: 0.1
-------------------------------------------

Iteration  0 : recall score =  0.8356164383561644
Iteration  1 : recall score =  0.863013698630137
Iteration  2 : recall score =  0.9322033898305084
Iteration  3 : recall score =  0.9459459459459459
Iteration  4 : recall score =  0.8939393939393939

Mean recall score  0.8941437733404299

-------------------------------------------
C parameter: 1
-------------------------------------------

Iteration  0 : recall score =  0.8493150684931506
Iteration  1 : recall score =  0.863013698630137
Iteration  2 : recall score =  0.9830508474576272
Iteration  3 : recall score =  0.9459459459459459
Iteration  4 : recall score =  0.9090909090909091

Mean recall score  0.9100832939235539

-------------------------------------------
C parameter: 10
-------------------------------------------

Iteration  0 : recall score =  0.863013698630137
Iteration  1 : recall score =  0.863013698630137
Iteration  2 : recall score =  0.9830508474576272
Iteration  3 : recall score =  0.9324324324324325
Iteration  4 : recall score =  0.9242424242424242

Mean recall score  0.9131506202785514

-------------------------------------------
C parameter: 100
-------------------------------------------

Iteration  0 : recall score =  0.863013698630137
Iteration  1 : recall score =  0.863013698630137
Iteration  2 : recall score =  0.9830508474576272
Iteration  3 : recall score =  0.9459459459459459
Iteration  4 : recall score =  0.9242424242424242

Mean recall score  0.9158533229812542

*********************************************************************************
Best model to choose from cross validation is with C parameter 0.01
*********************************************************************************

根據上面結果能夠看出,當正則化參數爲0.01時,recall的值最高。

未完待續。。。

相關文章
相關標籤/搜索