Python中用PyTorch機器學習神經網絡分類預測銀行客戶流失模型

原文連接:http://tecdat.cn/?p=8522

分類問題屬於機器學習問題的類別,其中給定一組特徵,任務是預測離散值。分類問題的一些常見示例是,預測腫瘤是否爲癌症,或者學生是否可能經過考試。在本文中,鑑於銀行客戶的某些特徵,咱們將預測客戶在6個月後是否可能離開銀行。客戶離開組織的現象也稱爲客戶流失。所以,咱們的任務是根據各類客戶特徵預測客戶流失。python

$ pip install pytorch

數據集

讓咱們將所需的庫和數據集導入到咱們的Python應用程序中:web

import torch
import torch.nn as nn
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

咱們可使用pandas庫的read_csv()方法來導入包含咱們的數據集的CSV文件。數組

dataset = pd.read_csv(r'E:Datasetscustomer_data.csv')

讓咱們輸出數據集 :網絡

dataset.shape

輸出:python爬蟲

(10000, 14)

輸出顯示該數據集具備1萬條記錄和14列。咱們可使用head()數據框的方法來輸出數據集的前五行。機器學習

dataset.head()

輸出:函數

您能夠在咱們的數據集中看到14列。根據前13列,咱們的任務是預測第14列的值,即Exited性能

探索性數據分析

讓咱們對數據集進行一些探索性數據分析。咱們將首先預測6個月後實際離開銀行並使用餅圖進行可視化的客戶比例。讓咱們首先增長圖形的默認繪圖大小:學習

fig_size = plt.rcParams["figure.figsize"]
fig_size[0] = 10
fig_size[1] = 8
plt.rcParams["figure.figsize"] = fig_size

如下腳本繪製該Exited列的餅圖。測試

dataset.Exited.value_counts().plot(kind='pie', autopct='%1.0f%%', colors=['skyblue', 'orange'], explode=(0.05, 0.05))

輸出:

輸出顯示,在咱們的數據集中,有20%的客戶離開了銀行。這裏1表明客戶離開銀行的狀況,0表明客戶沒有離開銀行的狀況。讓咱們繪製數據集中全部地理位置的客戶數量:

輸出顯示,幾乎一半的客戶來自法國,而西班牙和德國的客戶比例分別爲25%。

如今,讓咱們繪製來自每一個惟一地理位置的客戶數量以及客戶流失信息。咱們可使用庫中的countplot()函數seaborn來執行此操做。

輸出顯示,儘管法國客戶總數是西班牙和德國客戶總數的兩倍,但法國和德國客戶離開銀行的客戶比例是相同的。一樣,德國和西班牙客戶的總數相同,可是離開銀行的德國客戶數量是西班牙客戶的兩倍,這代表德國客戶在6個月後離開銀行的可能性更大。

數據預處理

在訓練PyTorch模型以前,咱們須要預處理數據。若是查看數據集,您將看到它具備兩種類型的列:數值列和分類列。數字列包含數字信息。CreditScoreBalanceAge等。相似地,GeographyGender是分類列,由於它們含有分類信息,如客戶的位置和性別。有幾列能夠視爲數字列和類別列。例如,該HasCrCard列的值能夠爲1或0。可是,那HasCrCard列包含有關客戶是否擁有信用卡的信息。

讓咱們再次輸出數據集中的全部列,並找出哪些列能夠視爲數字列,哪些列應該視爲類別列。columns數據框的屬性顯示全部列名稱:

Index(['RowNumber', 'CustomerId', 'Surname', 'CreditScore', 'Geography', 'Gender', 'Age', 'Tenure', 'Balance', 'NumOfProducts', 'HasCrCard', 'IsActiveMember', 'EstimatedSalary', 'Exited'], dtype='object')

從咱們的數據列,咱們將不使用的RowNumberCustomerId以及Surname列,由於這些列的值是徹底隨機的,並與輸出無關。例如,客戶的姓氏對客戶是否離開銀行沒有影響。其中列的其他部分,GeographyGenderHasCrCard,和IsActiveMember列能夠被視爲類別列。讓咱們建立這些列的列表: 除該列外,其他全部列都可視爲數字列。

numerical_columns = ['CreditScore', 'Age', 'Tenure', 'Balance', 'NumOfProducts', 'EstimatedSalary']

最後,輸出(Exited列中的值)存儲在outputs變量中。

咱們已經建立了分類,數字和輸出列的列表。可是,目前,分類列的類型不是分類的。您可使用如下腳本檢查數據集中全部列的類型:
輸出:

RowNumber            int64
CustomerId           int64
Surname             object
CreditScore          int64
Geography           object
Gender              object
Age                  int64
Tenure               int64
Balance            float64
NumOfProducts        int64
HasCrCard            int64
IsActiveMember       int64
EstimatedSalary    float64
Exited               int64
dtype: object

您能夠看到GeographyGender列的類型是object,HasCrCardIsActive列的類型是int64。咱們須要將分類列的類型轉換爲category。咱們可使用astype()函數來作到這一點,

如今,若是再次繪製數據集中各列的類型,您將看到如下結果:

輸出量

RowNumber             int64
CustomerId            int64
Surname              object
CreditScore           int64
Geography          category
Gender             category
Age                   int64
Tenure                int64
Balance             float64
NumOfProducts         int64
HasCrCard          category
IsActiveMember     category
EstimatedSalary     float64
Exited                int64
dtype: object

如今讓咱們查看Geography列中的全部類別:

Index(['France', 'Germany', 'Spain'], dtype='object')

當您將列的數據類型更改成類別時,該列中的每一個類別都會分配一個惟一的代碼。例如,讓咱們繪製列的前五行,Geography並輸出前五行的代碼值:

輸出:

0    France
1     Spain
2    France
3    France
4     Spain
Name: Geography, dtype: category
Categories (3, object): [France, Germany, Spain]

如下腳本在該列的前五行中繪製了值的代碼Geography

輸出:

0    0
1    2
2    0
3    0
4    2
dtype: int8

輸出顯示法國已編碼爲0,西班牙已編碼爲2。

將分類列與數字列分開的基本目的是,能夠將數字列中的值直接輸入到神經網絡中。可是,必須首先將類別列的值轉換爲數字類型。分類列中的值的編碼部分地解決了分類列的數值轉換的任務。

因爲咱們將使用PyTorch進行模型訓練,所以須要將分類列和數值列轉換爲張量。首先讓咱們將分類列轉換爲張量。在PyTorch中,能夠經過numpy數組建立張量。咱們將首先將四個分類列中的數據轉換爲numpy數組,而後將全部列水平堆疊,如如下腳本所示:

geo = dataset['Geography'].cat.codes.values
...

上面的腳本輸出分類列中前十條記錄。輸出以下:輸出:

array([[0, 0, 1, 1],
       [2, 0, 0, 1],
       [0, 0, 1, 0],
       [0, 0, 0, 0],
       [2, 0, 1, 1],
       [2, 1, 1, 0],
       [0, 1, 1, 1],
       [1, 0, 1, 0],
       [0, 1, 0, 1],
       [0, 1, 1, 1]], dtype=int8)

如今要從上述numpy數組建立張量,您只需將數組傳遞給模塊的tensortorch

輸出:

tensor([[0, 0, 1, 1],
        [2, 0, 0, 1],
        [0, 0, 1, 0],
        [0, 0, 0, 0],
        [2, 0, 1, 1],
        [2, 1, 1, 0],
        [0, 1, 1, 1],
        [1, 0, 1, 0],
        [0, 1, 0, 1],
        [0, 1, 1, 1]])

在輸出中,您能夠看到類別數據的numpy數組如今已轉換爲tensor對象。一樣,咱們能夠將數值列轉換爲張量:

numerical_data = np.stack([dataset[col].values for col in numerical_columns], 1)
...

輸出:

tensor([[6.1900e+02, 4.2000e+01, 2.0000e+00, 0.0000e+00, 1.0000e+00, 1.0135e+05],
        [6.0800e+02, 4.1000e+01, 1.0000e+00, 8.3808e+04, 1.0000e+00, 1.1254e+05],
        [5.0200e+02, 4.2000e+01, 8.0000e+00, 1.5966e+05, 3.0000e+00, 1.1393e+05],
        [6.9900e+02, 3.9000e+01, 1.0000e+00, 0.0000e+00, 2.0000e+00, 9.3827e+04],
        [8.5000e+02, 4.3000e+01, 2.0000e+00, 1.2551e+05, 1.0000e+00, 7.9084e+04]])

在輸出中,您能夠看到前五行,其中包含咱們數據集中六個數字列的值。最後一步是將輸出的numpy數組轉換爲tensor對象。輸出:

tensor([1, 0, 1, 0, 0])

如今,讓咱們繪製分類數據,數值數據和相應輸出的形狀: 輸出:

torch.Size([10000, 4])
torch.Size([10000, 6])
torch.Size([10000])

在訓練模型以前,有一個很是重要的步驟。咱們將分類列轉換爲數值,其中惟一值由單個整數表示。例如,在該Geography列中,咱們看到法國用0表示,德國用1表示。咱們可使用這些值來訓練咱們的模型。可是,更好的方法是以N維向量的形式表示分類列中的值,而不是單個整數。

咱們須要爲全部分類列定義矢量大小。關於維數沒有嚴格的規定。定義列的嵌入大小的一個好的經驗法則是將列中惟一值的數量除以2(但不超過50)。例如,對於該Geography列,惟一值的數量爲3。該Geography列的相應嵌入大小將爲3/2 = 1.5 = 2(四捨五入)。如下腳本建立一個元組,其中包含全部類別列的惟一值數量和維度大小:

categorical_column_sizes = [len(dataset[column].cat.categories) for column in categorical_columns]
...

輸出:

[(3, 2), (2, 1), (2, 1), (2, 1)]

使用訓練數據對監督型深度學習模型(例如咱們在本文中開發的模型)進行訓練,並在測試數據集上評估模型的性能。所以,咱們須要將數據集分爲訓練集和測試集,如如下腳本所示:

total_records = 10000
....

咱們的數據集中有1萬條記錄,其中80%的記錄(即8000條記錄)將用於訓練模型,而其他20%的記錄將用於評估模型的性能。注意,在上面的腳本中,分類和數字數據以及輸出已分爲訓練集和測試集。爲了驗證咱們已正確地將數據分爲訓練和測試集:

print(len(categorical_train_data))
print(len(numerical_train_data))
print(len(train_outputs))

print(len(categorical_test_data))
print(len(numerical_test_data))
print(len(test_outputs))

輸出:

8000
8000
8000
2000
2000
2000

建立預測模型

咱們將數據分爲訓練集和測試集,如今是時候定義訓練模型了。爲此,咱們能夠定義一個名爲的類Model,該類將用於訓練模型。看下面的腳本:

class Model(nn.Module):

    def __init__(self, embedding_size, num_numerical_cols, output_size, layers, p=0.4):
        super().__init__()
        self.all_embeddings = nn.ModuleList([nn.Embedding(ni, nf) for ni, nf in embedding_size])
        self.embedding_dropout = nn.Dropout(p)
        self.batch_norm_num = nn.BatchNorm1d(num_numerical_cols)



        return x

接下來,要查找輸入層的大小,將類別列和數字列的數量加在一塊兒並存儲在input_size變量中。以後,for循環迭代,並將相應的層添加到all_layers列表中。添加的層是:

  • Linear:用於計算輸入和權重矩陣之間的點積
  • ReLu:用做激活函數
  • BatchNorm1d:用於對數字列應用批量歸一化
  • Dropout:用於避免過擬合

在後for循環中,輸出層被附加到的層的列表。因爲咱們但願神經網絡中的全部層都按順序執行,所以將層列表傳遞給nn.Sequential該類。

接下來,在該forward方法中,將類別列和數字列都做爲輸入傳遞。類別列的嵌入在如下幾行中進行。

`embeddings = []
...`

數字列的批量歸一化可經過如下腳本應用:

x_numerical = self.batch_norm_num(x_numerical)

最後,將嵌入的分類列x和數字列x_numerical鏈接在一塊兒,並傳遞給sequence layers

訓練模型

要訓​​練模型,首先咱們必須建立Model在上一節中定義的類的對象。

您能夠看到咱們傳遞了分類列的嵌入大小,數字列的數量,輸出大小(在咱們的例子中爲2)以及隱藏層中的神經元。您能夠看到咱們有三個分別具備200、100和50個神經元的隱藏層。
讓咱們輸出模型並查看:

print(model)

輸出:

Model(
  (all_embeddings): ModuleList(
 ...
  )
)

您能夠看到,在第一線性層中,in_features變量的值爲11,由於咱們有6個數字列,而且類別列的嵌入維數之和爲5,所以6 + 5 = 11。out_features的值爲2,由於咱們只有2個可能的輸出。

在實際訓練模型以前,咱們須要定義損失函數和將用於訓練模型的優化器。如下腳本定義了損失函數和優化器:

loss_function = nn.CrossEntropyLoss()

如今,咱們訓練模型。如下腳本訓練模型:

epochs = 300
aggregated_losses = []

for i in range(epochs):


print(f'epoch: {i:3} loss: {single_loss.item():10.10f}')

神經元元數設置爲300,這意味着要訓練模型,完整的數據集將使用300次。for爲每次迭代期間循環的執行方式,損失是使用損耗函數來計算。每次迭代過程當中的損失將添加到aggregated_loss列表中。

上面腳本的輸出以下:

`epoch: 1 loss: 0.71847951
epoch: 26 loss: 0.57145703
epoch: 51 loss: 0.48110831
epoch: 76 loss: 0.42529839
epoch: 101 loss: 0.39972275
epoch: 126 loss: 0.37837571
epoch: 151 loss: 0.37133673
epoch: 176 loss: 0.36773482
epoch: 201 loss: 0.36305946
epoch: 226 loss: 0.36079505
epoch: 251 loss: 0.35350436
epoch: 276 loss: 0.35540250
epoch: 300 loss: 0.3465710580`

如下腳本繪製了各個時期的損失函數:

`plt.plot(range(epochs), aggregated_losses)
plt.ylabel('Loss')
plt.xlabel('epoch');`

輸出:

輸出顯示,最初損失函數迅速下降。在250個步長以後,損失幾乎沒有減小。

作出預測

最後一步是對測試數據進行預測。爲此,咱們只須要將categorical_test_datanumerical_test_data傳遞給model該類。而後能夠將返回的值與實際測試輸出值進行比較。如下腳本對測試類進行預測,並輸出測試數據的交叉熵損失。

with torch.no_grad():
...

輸出:

Loss: 0.36855841

測試集上的損失爲0.3685,比訓練集上得到的0.3465略多,這代表咱們的模型有些過擬合。因爲咱們指定輸出層將包含2個神經元,所以每一個預測將包含2個值。例如,前5個預測值以下所示:

print(y_val[:5])

輸出:

tensor([[ 1.2045, -1.3857],
        [ 1.3911, -1.5957],
        [ 1.2781, -1.3598],
        [ 0.6261, -0.5429],
        [ 2.5430, -1.9991]])

這種預測的思想是,若是實際輸出爲0,則索引0處的值應大於索引1處的值,反之亦然。咱們可使用如下腳本檢索列表中最大值的索引:

y_val = np.argmax(y_val, axis=1)

輸出:如今讓咱們再次輸出y_val列表的前五個值:

print(y_val[:5])

輸出:

tensor([0, 0, 0, 0, 0])

因爲在最初預測的輸出列表中,對於前五個記錄,零索引處的值大於第一索引處的值,所以能夠在已處理輸出的前五行中看到0。

最後,咱們可使用從sklearn.metrics模塊confusion_matrixaccuracy_score以及classification_report類找到了準確度,精密度和召回值,混淆矩陣。

`from sklearn.metrics import classification_report, confusion_matrix, accuracy_score

print(confusion_matrix(test_outputs,y_val))
print(classification_report(test_outputs,y_val))
print(accuracy_score(test_outputs, y_val))`

輸出:

`[[1527 83]
[ 224 166]]

precision    recall  f1-score   support

       0       0.87      0.95      0.91      1610
       1       0.67      0.43      0.52       390

micro avg 0.85 0.85 0.85 2000
macro avg 0.77 0.69 0.71 2000
weighted avg 0.83 0.85 0.83 2000

0.8465`

輸出結果代表,咱們的模型達到了84.65%的精度,考慮到咱們隨機選擇神經網絡模型的全部參數這一事實,這很是使人印象深入。我建議您嘗試更改模型參數,例如訓練/測試比例,隱藏層的數量和大小等,以查看是否能夠得到更好的結果。

結論

PyTorch是Facebook開發的經常使用深度學習庫,可用於各類任務,例如分類,迴歸和聚類。本文介紹瞭如何使用PyTorch庫對錶格數據進行分類。


最受歡迎的看法

1.探析大數據期刊文章研究熱點

2.618網購數據盤點-剁手族在關注什麼

3.r語言文本挖掘tf-idf主題建模,情感分析n-gram建模研究

4.python主題建模可視化lda和t-sne交互式可視化

5.疫情下的新聞數據觀察

6.python主題lda建模和t-sne可視化

7.r語言中對文本數據進行主題模型topic-modeling分析

8.主題模型:數據聆聽人民網留言板的那些「網事」

9.python爬蟲進行web抓取lda主題語義數據分析

相關文章
相關標籤/搜索