模型改写,多层感知机训练,dataset改写数据,划分数据集验证集,添加正确率

数据处理

读入数据

import torch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
data = pd.read_csv('./HR.csv')
data.head()

image

data.info()

image

数据字符类型处理

然后我们发现data中的part和salary是object类型,所以我们将这两个打印看看都有那些类型

data.part.unique()
# array(['sales', 'accounting', 'hr', 'technical', 'support', 'management',
#       'IT', 'product_mng', 'marketing', 'RandD'], dtype=object)

data.salary.unique()

# array(['low', 'medium', 'high'], dtype=object)

image
然后我们将这两个类型转化成one-hot编码,我们用pd.get_dummies()方法。

pandas.get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False, columns=None, sparse=False, drop_first=False, dtype=None)

prefix:str, list of str, 或 dict of str, 默认为 None
用于追加DataFrame列名称的字符串。
 
prefix_sep:str, 默认为 ‘_’
如果附加前缀,则使用分隔符/分隔符。或者像这样传递列表或字典prefix。
 
dummy_na:bool, 默认为 False
如果忽略False NaN。
 
columns:list-like, 默认为 None
要编码的DataFrame中的列名。如果columns为None,则所有具有的列object或者categorydtype将被转换。
 
sparse:bool, 默认为 False
dummy-encoded列是否应由a支持SparseArray(True)或常规NumPy数组(False)。
 
drop_first:bool, 默认为 False
是否通过删除第一个级别从k个分类级别中获取k-1个虚拟对象。

用法举例:

data = pd.DataFrame({"学号":[1,2,3,4],
                    "录取":["清华","北大","清华","蓝翔"],
                    "学历":["本科","本科","本科","专科"]})
pd.get_dummies(data)

image
然后我们在data中将partsalary进行处理
我们先加入这些行pd.get_dummies(data.part)pd.get_dummies(data.salary)

data = data.join(pd.get_dummies(data.part)).join(pd.get_dummies(data.salary))

data.head()

image
然后我们将原数据中的partsalary删掉

data.drop(columns=['part', 'salary'], inplace=True)

X,Y数据划分

我们需要预测的是这个left这一行,看是否会离职,0是留下,1是离职
先打印一下这一行的具体信息

data.left.value_counts()
0    11428
1     3571
Name: left, dtype: int64

Y

注意如果是一行的话一定要.reshape(-1,1),然后再变成tensor类型

Y_data = data.left.values.reshape(-1, 1)
Y = torch.from_numpy(Y_data).type(torch.FloatTensor)
Y.shape
# torch.Size([14999, 1])

X

这个X就是将原数据中去除掉left这一列的数据,我们可以使用.drop(),或者下面这个方法。

[c for c in data.columns if c != 'left']

X_data = data[[c for c in data.columns if c != 'left']].values

X = torch.from_numpy(X_data).type(torch.FloatTensor)

X.shape

# torch.Size([14999, 20])

image

创建模型

class Logistic(nn.Module):
    def __init__(self):
        super().__init__()
        self.lin_1 = nn.Linear(20, 64)
        self.lin_2 = nn.Linear(64, 64)
        self.lin_3 = nn.Linear(64, 1)
        self.activate = nn.ReLU()
        self.sigmoid = nn.Sigmoid()
    def forward(self, input):
        x = self.lin_1(input)
        x = self.activate(x)
        x = self.lin_2(x)
        x = self.activate(x)
        x = self.lin_3(x)
        x = self.sigmoid(x)
        return x

或者我们改进一下,写的更简单一点

import torch.nn.functional as F

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.liner_1 = nn.Linear(20, 64)
        self.liner_2 = nn.Linear(64, 64)
        self.liner_3 = nn.Linear(64, 1)
    def forward(self, input):
        x = F.relu(self.liner_1(input))
        x = F.relu(self.liner_2(x))
        x = torch.sigmoid(self.liner_3(x))
        return x
model=Model()
model

输出

Model(
  (liner_1): Linear(in_features=20, out_features=64, bias=True)
  (liner_2): Linear(in_features=64, out_features=64, bias=True)
  (liner_3): Linear(in_features=64, out_features=1, bias=True)
)

优化器

lr = 0.0001

def get_model():
    model = Model()
    opt=torch.optim.Adam(model.parameters(), lr=lr)#这里因为我们继承自nn.Module模组,所以可以导入model.parameters()
    return model, opt

这里主要优化的是model中的parameters()参数,之所以可以调用model.parameters()是因为这个model继承自nn.model
image

损失函数

loss_fn = nn.BCELoss()

模型和优化器

model, optim = get_model()

划分barch

len(data)
# 14999
batch = 64
no_of_batches = len(data)//batch # 定义全部的批次
epochs = 100

训练

注意这里的with torch.no_grad():这里我们做预测所以,不需要进行梯度更新,然后就用这个

for epoch in range(epochs):
    for i in range(no_of_batches):
        start = i * batch
        end = start + batch
        x = X[start: end]
        y = Y[start: end]
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optim.zero_grad()
        loss.backward()
        optim.step()
    with torch.no_grad():
        print('epoch:', epoch,   'loss:', loss_fn(model(X), Y).data.item())

image

Dataset和DataLoader

使用Dataset进行重构数据集

PyTorch有一个抽象的Dataset类。Dataset可以是任何具有__len__函数和__getitem__作为对其进行索引的方法的函数。 本教程将通过示例将自定义HRDataset类创建为的Dataset的子类。
PyTorch的TensorDataset 是一个包装张量的Dataset。通过定义索引的长度和方式,这也为我们提供了沿张量的第一维进行迭代,索引和切片的方法。这将使我们在训练的同一行中更容易访问自变量和因变量。

from torch.utils.data import TensorDataset
HRdataset = TensorDataset(X, Y)
HRdataset

image

对于这种dataset:
我们可以用img0,target0=dataset[0];img1,target1=dataset[1]
image
然后我们看看怎么访问它:

HRdataset[1]
(tensor([  0.8000,   0.8600,   5.0000, 262.0000,   6.0000,   0.0000,   0.0000,
           0.0000,   0.0000,   0.0000,   0.0000,   0.0000,   0.0000,   0.0000,
           1.0000,   0.0000,   0.0000,   0.0000,   0.0000,   1.0000]),
 tensor([1.]))

这个就是第一组数据

len(HRdataset)
# 14999

然后有14999组,这是由对于每一个batches访问的时候就是HRdataset[i * batch: i * batch + batch]

model, optim = get_model()
for epoch in range(epochs):
    for i in range(no_of_batches):
        x, y = HRdataset[i * batch: i * batch + batch]
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optim.zero_grad()
        loss.backward()
        optim.step()
    with torch.no_grad():
        print('epoch:', epoch,   'loss:', loss_fn(model(X), Y).data.item())

image

使用DataLoader类进行重构

Pytorch DataLoader负责管理批次。
DataLoader从Dataset创建。
DataLoader使遍历批次变得更容易。DataLoader会自动为我们提供每个小批量。
无需使用 HRdataset[i * batch: i * batch + batch]
对于这个

DataLoader(dataset, batch_size=1, shuffle=False)
必备参数:
dataset:要加载的数据集
常用参数:
batch_size:必须是整数,每个batch里有多少个samples
shuffle = True就会在每个epoch中打乱数据 ,False则不打乱

from torch.utils.data import DataLoader

HR_ds = TensorDataset(X, Y)
HR_dl = DataLoader(HR_ds, batch_size=batch,shuffle=True)

现在,我们的循环更加简洁了,因为(xb,yb)是从数据加载器自动加载的:

for x,y in HR_dl:
pred = model(x)

for epoch in range(epochs):
    for x, y in HR_dl:
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optim.zero_grad()
        loss.backward()
        optim.step()
    with torch.no_grad():
        print('epoch:', epoch,   'loss:', loss_fn(model(X), Y).data.item())

image

添加验证

了解过拟合和欠拟合

过拟合:对于训练数据过度拟合,对于未来数据预测很差

欠拟合:对于训练数据拟合不够,对于未来数据预测很差

前面我们只是试图建立一个合理的训练循环以用于我们的训练数据。实际上,您始终还应该具有一个验证集,以识别您是否过度拟合。

训练数据的乱序(shuffle)对于防止批次与过度拟合之间的相关性很重要。另一方面,无论我们是否乱序验证集,验证损失都是相同的。由于shufle需要额外的开销,因此shuffle验证数据没有任何意义。

我们将为验证集使用批大小,该批大小是训练集的两倍。这是因为验证集不需要反向传播,因此占用的内存更少(不需要存储梯度)。我们利用这一优势来使用更大的批量,并更快地计算损失。

train_x, test_x, train_y, test_y = train_test_split(X_data, Y_data, test_size, random_state, shuffle)
train_x:划分的训练集数据
test_x:划分的测试集数据
train_y:划分的训练集标签
test_y:划分的测试集标签
X_data:还未划分的数据集
Y_data:还未划分的标签
test_size:分割比例,默认为0.25,即测试集占完整数据集的比例
random_state:随机数种子,应用于分割前对数据的洗牌。可以是int,RandomState实例或None,默认值=None。设成定值意味着,对于同一个数据集,只有第一次运行是随机的,随后多次分割只要rondom_state相同,则划分结果也相同。
shuffle:是否在分割前对完整数据进行洗牌(打乱),默认为True,打乱

我们划分测试集和验证集

from sklearn.model_selection import train_test_split
train_x, test_x, train_y, test_y = train_test_split(X_data, Y_data)

train_x.shape, train_y.shape, test_x.shape, test_y.shape

# ((11249, 20), (11249, 1), (3750, 20), (3750, 1))
train_ds = TensorDataset(train_x, train_y)
train_dl = DataLoader(train_ds, batch_size=batch, shuffle=True)

test_ds = TensorDataset(test_x, test_y)
test_dl = DataLoader(test_ds, batch_size=batch)

定义计算正确率函数

def accuracy(y_pred, y_true):
    y_pred = (y_pred>0.5).type(torch.int32)
    acc=(y_pred == y_true).float().mean()
    return acc
model, optim = get_model()
for epoch in range(epochs):
    for x, y in train_dl:
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optim.zero_grad()
        loss.backward()
        optim.step()
    with torch.no_grad():
        epoch_accuracy=accuracy(model(train_x),train_y)
        epoch_loss=loss_fn(model(train_x),train_y).data
        epoch_test_accuracy=accuracy(model(test_x),test_y)
        epoch_test_loss=loss_fn(model(test_x),test_y).data
        print('epoch:', epoch,   
              'loss:', epoch_loss.item(),
              'accuracy',epoch_accuracy.item(),
              'test_loss:', epoch_test_loss.item(),
              'test_accuracy',epoch_test_accuracy.item()
             )

image

posted @ 2023-10-15 20:38  lipu123  阅读(99)  评论(0)    收藏  举报