分类问题属于机器学习问题的类别,其中给定一组特征,任务是预测离散值。分类问题的一些常见示例是,预测肿瘤是否为癌症,或者学生是否可能经过考试。在本文中,鉴于银行客户的某些特征,咱们将预测客户在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模型以前,咱们须要预处理数据。若是查看数据集,您将看到它具备两种类型的列:数值列和分类列。数字列包含数字信息。CreditScore
,Balance
,Age
等。相似地,Geography
和Gender
是分类列,由于它们含有分类信息,如客户的位置和性别。有几列能够视为数字列和类别列。例如,该HasCrCard
列的值能够为1或0。可是,那HasCrCard
列包含有关客户是否拥有信用卡的信息。
让咱们再次输出数据集中的全部列,并找出哪些列能够视为数字列,哪些列应该视为类别列。columns
数据框的属性显示全部列名称:
Index(['RowNumber', 'CustomerId', 'Surname', 'CreditScore', 'Geography', 'Gender', 'Age', 'Tenure', 'Balance', 'NumOfProducts', 'HasCrCard', 'IsActiveMember', 'EstimatedSalary', 'Exited'], dtype='object')
从咱们的数据列,咱们将不使用的RowNumber
,CustomerId
以及Surname
列,由于这些列的值是彻底随机的,并与输出无关。例如,客户的姓氏对客户是否离开银行没有影响。其中列的其他部分,Geography
,Gender
,HasCrCard
,和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
您能够看到Geography
和Gender
列的类型是object,HasCrCard
和IsActive
列的类型是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数组建立张量,您只需将数组传递给模块的tensor
类torch
。
输出:
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_data
和numerical_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_matrix
,accuracy_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库对表格数据进行分类。
最受欢迎的看法
3.r语言文本挖掘tf-idf主题建模,情感分析n-gram建模研究
4.python主题建模可视化lda和t-sne交互式可视化