【机器学习】根据特征预测序列-2022李宏毅作业HW1

记录一个pytorch训练机器学习模型的代码,代码内容包括:数据库建立、数据预处理、特征分析与提取、神经模型定义、模型训练与验证、模型拟合结果输出等部分,模拟效果见下图。

在这里插入图片描述


一、数据介绍

数据长度为116列2699行,记录了美国各州与新冠相关的一些特征。前一部分为各州编码,后一部分为5天的特征数据。

在这里插入图片描述


在这里插入图片描述

二、构建数据库与数据预处理

为了方便后续数据调用,因此在数据库构建的同时将数据处理成需要的格式。数据预处理十分重要,预处理的方式与模型结构有关。
为了能更直观地看到模型验证结果,选择最后100行数据作为验证数据集,其他数据作为训练数据集。
数据格式为csv文件,因此用csv.reader函数可以很方便地读取数据。读取后,删掉无关地数据,精简数据。
在模型训练时,将最后一列作为标签,用前面列的特征数据来对最后一列进行预测。但是特征数据有115个,因此必然需要筛选出哪些是与标签数据有关的数据。本文采用SelectKBest方法筛选特征数据。
数据库构建代码如下:

class MyDatasets(Dataset):
    def __init__(self, path, feature_num, method):
        with open(path, 'r') as f:
            csv_data = list(csv.reader(f))
            csv_title = csv_data[0][1:]
            csv_data = np.array(csv_data[1:])[:, 1:].astype(float)  # 删除数据第一行(title)和第一列(id)
            feature_list = feature_get(feature_num)
            b = np.zeros((2699, len(feature_list) + 1))
            for idx in range(len(feature_list)):
                b[:, idx] = csv_data[:, feature_list[idx]]
            b[:, -1] = csv_data[:, -1]
            csv_data = b
            self.csv_title = csv_title
            if method == 'train':
                self.csv_data = csv_data[:-100]
            elif method == 'test':
                self.csv_data = csv_data[-100:]

    def __getitem__(self, idx):
        data_cov = self.csv_data[idx][:-1]
        title_cov = self.csv_data[idx][-1]
        return data_cov, title_cov

    def __len__(self):
        return len(self.csv_data)

特征数据筛选代码如下:

import csv
import numpy as np
from sklearn.feature_selection import SelectKBest, chi2


def feature_get(k):		# k:需要筛选出的特征数量
    with open('covid.train_new.csv', 'r') as f:
        csv_data = list(csv.reader(f))
        csv_title = csv_data[0][1:]
        csv_data = np.array(csv_data[1:])[:, 1:].astype(float)
    # 生成数据
    labels_list = []
    data_list = []
    for i in csv_data:
        labels_list.append(i[-1])
        data_list = np.append(data_list, i[:-1])
    data_list = data_list.reshape(2699, -1)
    labels_list = np.array(labels_list)

    model = SelectKBest(chi2, k=k)
    x_new = model.fit_transform(data_list, labels_list.astype('int32'))

    data_list = data_list.transpose()
    x_new = x_new.transpose()

    feature_list = []
    for i in x_new:
        for j in range(len(data_list) - 1):
            if i[10] == data_list[j][10]:
                feature_list.append(j)
    return feature_list

数据库建立后,在导入模型前还需要进行归一化操作

scaler = MinMaxScaler(feature_range=(-1, 1))
train_dataset.csv_data = scaler.fit_transform(train_dataset.csv_data)
test_dataset.csv_data = scaler.transform(test_dataset.csv_data)

三、模型定义

模型由三层全链接层构成

class MyNet(nn.Module):
    def __init__(self, input_dim):
        super(MyNet, self).__init__()
        # 一个简单的三层全链接层的神经网络模型
        self.layers = nn.Sequential(
            nn.Linear(input_dim, 16),  # 全连接层
            nn.ReLU(),  # 激活函数
            nn.Linear(16, 8),
            nn.ReLU(),
            nn.Linear(8, 1)
        )

    def forward(self, x):
        x = self.layers(x)
        x = x.squeeze(1)  # (B, 1) -> (B)
        return x

四、模型训练与验证

模型训练与验证过程较简单,只需注意输入维度、输出维度、数据格式等方面。这里的输入维度(input_dim)为输入的特征数据个数。

mod = MyNet(input_dim)
loss_fn = nn.MSELoss()
learning_rate = 1e-1
optimizer = torch.optim.SGD(mod.parameters(), lr=learning_rate)

loss_list = []
total_train_step = 0
epoch = 200
mod.train()
total_loss = 0
for i in range(epoch):
    print('第{}轮训练开始'.format(i + 1))
    for data in train_dataloader:
        cov_data, target = data
        output = mod(cov_data.to(torch.float32))
        loss = loss_fn(output, target.to(torch.float32))
        total_loss += loss.item()
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_train_step = total_train_step + 1
    print('训练次数:{},loss:{}'.format(total_train_step, total_loss))
    loss_list.append(total_loss)
    total_loss = 0
# torch.save(mod, 'mod2.pth')
print('*' * 25 + '训练完成' + '*' * 25)

mod.eval()
output_list = []
total_test_loss = 0
with torch.no_grad():
    for data in test_dataloader:
        cov_data, target = data
        output = mod(cov_data.to(torch.float32))
        output_list = np.append(output_list, output)
        loss = loss_fn(output, target.to(torch.float32))
        total_test_loss = total_test_loss + loss.item()
    print('整体测试集loss:{}'.format(total_test_loss))

五、模型结果输出

在输出绘图时,需要对输出数据进行逆归一化,还原数据。在进行逆归一化前,需要将数据大小还原成归一化以前的大小。逆归一化完成后,需要将数据拉伸为一维数据,与标签数据的大小保持一致,方便绘图。

output_list = scaler.inverse_transform(output_list.reshape(-1, feature_num + 1))
output_list = output_list.reshape(1, -1)[0]

模型超参数数据与绘图代码详见完整代码部分。

六、完整代码

import csv
import numpy as np
import torch
from matplotlib import pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from torch.utils.data import Dataset, DataLoader
from MyFeature import feature_get
import torch.nn as nn
import time


class MyDatasets(Dataset):
    def __init__(self, path, feature_num, method):
        with open(path, 'r') as f:
            csv_data = list(csv.reader(f))
            csv_title = csv_data[0][1:]
            csv_data = np.array(csv_data[1:])[:, 1:].astype(float)  # 删除数据第一行(title)和第一列(id)
            feature_list = feature_get(feature_num)
            b = np.zeros((2699, len(feature_list) + 1))
            for idx in range(len(feature_list)):
                b[:, idx] = csv_data[:, feature_list[idx]]
            b[:, -1] = csv_data[:, -1]
            csv_data = b
            self.csv_title = csv_title
            if method == 'train':
                self.csv_data = csv_data[:-100]
            elif method == 'test':
                self.csv_data = csv_data[-100:]

    def __getitem__(self, idx):
        data_cov = self.csv_data[idx][:-1]
        title_cov = self.csv_data[idx][-1]
        return data_cov, title_cov

    def __len__(self):
        return len(self.csv_data)


class MyNet(nn.Module):
    def __init__(self, input_dim):
        super(MyNet, self).__init__()
        # 一个简单的三层全链接层的神经网络模型
        self.layers = nn.Sequential(
            nn.Linear(input_dim, 16),  # 全连接层
            nn.ReLU(),  # 激活函数
            nn.Linear(16, 8),
            nn.ReLU(),
            nn.Linear(8, 1)
        )

    def forward(self, x):
        x = self.layers(x)
        x = x.squeeze(1)  # (B, 1) -> (B)
        return x


start_time = time.time()
feature_num = 4
train_dataset = MyDatasets('covid.train_new.csv', feature_num, 'train')
test_dataset = MyDatasets('covid.train_new.csv', feature_num, 'test')

labels_list = []
for i in test_dataset.csv_data:
    labels_list.append(i[-1])

scaler = MinMaxScaler(feature_range=(-1, 1))
train_dataset.csv_data = scaler.fit_transform(train_dataset.csv_data)
test_dataset.csv_data = scaler.transform(test_dataset.csv_data)
batch_size = 16
train_dataloader = DataLoader(train_dataset, batch_size, drop_last=False)
test_dataloader = DataLoader(test_dataset, batch_size, drop_last=False)

test_data_size = len(test_dataset.csv_data)

# input_dim = len(train_dataset.csv_data[0])-1
input_dim = feature_num
mod = MyNet(input_dim)
loss_fn = nn.MSELoss()
learning_rate = 1e-1
optimizer = torch.optim.SGD(mod.parameters(), lr=learning_rate)

loss_list = []
total_train_step = 0
epoch = 200
mod.train()
total_loss = 0
for i in range(epoch):
    print('第{}轮训练开始'.format(i + 1))
    for data in train_dataloader:
        cov_data, target = data
        output = mod(cov_data.to(torch.float32))
        loss = loss_fn(output, target.to(torch.float32))
        total_loss += loss.item()
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_train_step = total_train_step + 1
    print('训练次数:{},loss:{}'.format(total_train_step, total_loss))
    loss_list.append(total_loss)
    total_loss = 0
# torch.save(mod, 'mod2.pth')
print('*' * 25 + '训练完成' + '*' * 25)

mod.eval()
output_list = []
total_test_loss = 0
with torch.no_grad():
    for data in test_dataloader:
        cov_data, target = data
        output = mod(cov_data.to(torch.float32))
        output_list = np.append(output_list, output)
        loss = loss_fn(output, target.to(torch.float32))
        total_test_loss = total_test_loss + loss.item()
    print('整体测试集loss:{}'.format(total_test_loss))
    # 输出结果

output_list = scaler.inverse_transform(output_list.reshape(-1, feature_num + 1))  # 对output进行维度转换

output_list = output_list.reshape(1, -1)[0]  # 将矩阵变成一维,和label_list保持一致

cor = np.corrcoef(np.vstack((labels_list, output_list)))[1, 0]  # 数组合成,求相关系数
cor = round(cor, 4)  # 保留两位小数
total_test_loss = round(total_test_loss, 4)
end_time = round((time.time() - start_time), 4)
print('训练次数{},学习率{},批尺寸{},耗时{}秒,'.format(epoch, learning_rate, batch_size, end_time))
print('相关系数{},测试集损失{}'.format(cor, total_test_loss))
with open('模型训练情况.txt', 'a', encoding='utf-8') as f:
    f.write('训练次数' + str(epoch) + ' ')
    f.write('学习率' + str(learning_rate) + ' ')
    f.write('批尺寸' + str(batch_size) + ' ')
    f.write('相关系数' + str(cor) + ' ')
    f.write('测试集损失' + str(total_test_loss) + ' ')
    f.write('特征数量' + str(feature_num) + ' ')
    f.write('耗时' + str(end_time) + ' ')
    f.write('\n')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# plt.figure(1)
# plt.title('loss变化', fontsize=16)
# plt.plot(loss_list)
# plt.figure(2)
plt.title('模拟情况  ' + '相关系数:' + str(cor), fontsize=16)
plt.plot(output_list, label='模拟')
plt.plot(labels_list, label='实测')
plt.legend()
plt.show()

七、部分运行结果展示

在这里插入图片描述

八、参考资料

【李宏毅《机器学习》2022】作业1:COVID 19 Cases Prediction (Regression)

2022李宏毅作业hw1—新冠阳性人员数量预测。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340