事前  :

kaggle地址:ML2021Spring-hw1 | Kaggle

我的git地址: https://github.com/xiaolilaoli/lihongyi2022homework/tree/main/hw1_covidpred

当然作为新手,我也是参考的其他大神的。参考的过多,我就不一一放地址了,在这里谢过各位大佬。如果和我一样的新手,调试代码看张量流动绝对是一个好用的方法。

作业介绍: 说的是啊 这个美国,好像是有40个州, 这四十个州呢 ,统计了连续三天的新冠阳性人数,和每天的一些社会特征,比如带口罩情况, 居家办公情况等等。现在有一群人比较坏,把第三天的数据遮住了,我们就要用前两天的情况以及第三天的特征,来预测第三天的阳性人数。但幸好的是,我们还是有一些数据可以作为参考的,就是我们的训练集。

  一: 数据读取。

(第一步引用的包:)

import numpy as np
from torch.utils.data import Dataset,DataLoader
import csv
import torch
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

先从kaggle上把数据下下来看看。点那个data就找到下载的地方了。下载好数据第一步先观察train的数据是什么样子的。如下图,可以看到有很多列,每一列都是一类特征,每一行都是一个样本。黄红蓝是第1,2,3天的测试阳性数据。蓝色的就是我们要预测的值啦。

我们再细看数据: 可以看到第一行是没有用的,他只是标签的名称。然后第一列也是没有用处的,因为他只是标注样本是第几个样本。等会处理数据时都要处理掉。 然后我们可以注意到前40列的数据和后面五十多列是不一样的,一般是一列全1 其他列全0 ,表示的是1所在的那个州,地点标识而已。

看清楚数据的结构,下面我们开始读入数据。csv数据和其他数据的读法差不多。比如你可以选择下面的文件式读法。

with open(r'covid.train.csv', 'r') as f:
train_data = f.readlines() train_data = [line.split('\n') for line in train_data][1:] #分行之后不要第一行
train_data = [each[0].split(',') for each in train_data] #对于每一行 去掉后面的空格
print(len(train_data[0]))
train_data = np.array(train_data) #转换成numpy的矩阵 train_x = train_data[:,1:-1] # x是数据,y是标签 。第一个冒号表示所有行,第二个冒号表示
train_y = train_data[:,-1] #列。所以x就是第2列到倒数第二列。y就是倒数第一列。

也可以选择csv的专门读取excel表格的函数

with open(path,'r') as f:
csv_data = list(csv.reader(f))
column = csv_data[0] #0行是标题
csv_data = np.array(csv_data[1:])[:,1:].astype(float) #连环操作 先取行 转numpy
#再取列 转float

然后这里要介绍一个取最相关列的操作。 上面的数据我们知道有95列,可是,这90多列,每一列都与结果是相关的吗? 恐怕不一定,肯定有些特征卵用没有。所以我们这里可以找到那些相关的列,用这些特征来预测结果。找特征有很多方法,大家可以百度特征选择,有很多介绍。这里用的是SelectKBest 函数。顺便定义了一个挑特征的函数。column是第一行的特征名称,我传入是为了打印看看是哪些特征重要,要不然他挑了半天我也不知道啊 。k是挑多少个特征。


def get_feature_importance(feature_data, label_data, k =4,column = None):
"""
此处省略 feature_data, label_data 的生成代码。
如果是 CSV 文件,可通过 read_csv() 函数获得特征和标签。
"""
model = SelectKBest(chi2, k=k)#选择k个最佳特征
X_new = model.fit_transform(feature_data, label_data)
#feature_data是特征数据,label_data是标签数据,该函数可以选择出k个特征
print('x_new', X_new)
scores = model.scores_
# 按重要性排序,选出最重要的 k 个
indices = np.argsort(scores)[::-1] #找到重要K个的下标
if column:
k_best_features = [column[i+1] for i in indices[0:k].tolist()]
print('k best features are: ',k_best_features)
return X_new, indices[0:k]

找好特征后。我们还需要进行训练集和验证集的划分。 我们知道,kaggle下下来只有训练集和测试集,所以我们需要从训练集里分出来一个验证集来作为模型评价。 方法可以是直接截一段,也可以是逢几个挑一个,也可以是随机的。我这里是逢5挑1

            if mode == 'train':
indices = [i for i in range(len(csv_data)) if i % 5 != 0]
self.y = torch.LongTensor(csv_data[indices,-1])
elif mode == 'val':
indices = [i for i in range(len(csv_data)) if i % 5 == 0]
# data = torch.tensor(csv_data[indices,col_indices])
self.y = torch.LongTensor(csv_data[indices,-1])
else:
indices = [i for i in range(len(csv_data))]
#这是测试数据 不需要标签 也没有标签

取完数据后,一般还要有一个归一化的步骤,防止各个特征的数量级相差过于大。这里用的是Z-score标准化方法。减均值除以标准差

self.data = (self.data - self.data.mean(dim=0,keepdim=True))
/self.data.std(dim=0,keepdim=True) #这里将数据归一化。

综上所述,我们可以写出我们的dataset函数了。基本上大部分神经网络都是需要读数据这部分的,过程就是把数据从本地文件,读入dataset中去。dataset中一般有三个函数,第一个是初始化__init__:  一般负责把数据从文件取出来。第二个获取数据__getitem__, 负责读第几个数据。第三个获取长度__len__: 负责返回数据集的长度。

一个完整的从csv到可以用的dataset的 代码如下图所示。 这一部分被我放在model——utils的data模块里。

完整代码:

import numpy as np
from torch.utils.data import Dataset,DataLoader
import csv
import torch
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2 def get_feature_importance(feature_data, label_data, k =4,column = None):
"""
此处省略 feature_data, label_data 的生成代码。
如果是 CSV 文件,可通过 read_csv() 函数获得特征和标签。
"""
model = SelectKBest(chi2, k=k)#选择k个最佳特征
X_new = model.fit_transform(feature_data, label_data)
#feature_data是特征数据,label_data是标签数据,该函数可以选择出k个特征
print('x_new', X_new)
scores = model.scores_
# 按重要性排序,选出最重要的 k 个
indices = np.argsort(scores)[::-1] #找到重要K个的下标
if column:
k_best_features = [column[i+1] for i in indices[0:k].tolist()]
print('k best features are: ',k_best_features)
return X_new, indices[0:k] class covidDataset(Dataset):
def __init__(self, path, mode, feature_dim):
with open(path,'r') as f:
csv_data = list(csv.reader(f))
column = csv_data[0]
train_x = np.array(csv_data)[1:][:,1:-1]
train_y = np.array(csv_data)[1:][:,-1]
_,col_indices = get_feature_importance(train_x,train_y,feature_dim,column)
col_indices = col_indices.tolist() #得到重要列的下标
csv_data = np.array(csv_data[1:])[:,1:].astype(float)
if mode == 'train': #如果读的是训练数据 就逢5取4 indices是数据下标
indices = [i for i in range(len(csv_data)) if i % 5 != 0]
self.y = torch.LongTensor(csv_data[indices,-1])
elif mode == 'val': #如果读的是验证数据 就逢5取1 indices是数据下标
indices = [i for i in range(len(csv_data)) if i % 5 == 0]
# data = torch.tensor(csv_data[indices,col_indices])
self.y = torch.LongTensor(csv_data[indices,-1])
else: #如果读的是测试数据 就全取了
indices = [i for i in range(len(csv_data))]
data = torch.tensor(csv_data[indices,:]) #取行
self.data = data[:,col_indices] #取列
self.mode = mode
self.data = (self.data - self.data.mean(dim=0,keepdim=True)) /self.data.std(dim=0,keepdim=True) #这里将数据归一化。
assert feature_dim == self.data.shape[1] print('Finished reading the {} set of COVID19 Dataset ({} samples found, each dim = {})'
.format(mode, len(self.data), feature_dim)) def __getitem__(self, item):
if self.mode == 'test':
return self.data[item].float()
else :
return self.data[item].float(), self.y[item]
def __len__(self):
return len(self.data)

二 模型设计。

数据都读完了,接下来肯定是模型了 。当然这里是一个简单的回归模型我用两个全连接实现的,中间加了一个relu。inDim是传入的参数 ,就是上面我们挑选的重要特征的数量啦。这部分比较简单,一般模型都是包括这两个部分 __init__和forward  也就是初始化和前向传播。初始化中会定义前向传播里需要的模型模块。前向传播里就是输入到输出的流动了 。x是输入的张量,最后输出模型计算结果。 模型也非常简单。

注意网络一般都是按batch大小计算的。我举个例子。 假如我挑了4个特征,那么模型输入长度就是4,输出长度就是1(回归值) 。假如我16个数据1批次, 输入大小就是(16,4) 输出就是(16,1) 这都是自动的 不用我们担心。这一部分被我放在model_utils的model模块里。

完整代码:

import torch.nn as nn

class myNet(nn.Module):
def __init__(self,inDim):
super(myNet,self).__init__()
self.fc1 = nn.Linear(inDim, 64)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(64,1) def forward(self, x):
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
if len(x.size()) > 1:
return x.squeeze(1) #如果批量大小不为1 这里才需要展平。
else:
return x

三   训练步骤。

训练函数推荐大家自己定义一个的,这样以后面对大部分问题都可以通用。

这个是训练的过程 都是很常规的步骤。

   for i in range(epoch):
start_time = time.time()
model.train() #开启训练
train_loss = 0.0
val_loss = 0.0
for data in trainloader:
optimizer.zero_grad()
x , target = data[0].to(device), data[1].to(torch.float32).to(device)
#从loader里取一批数据
pred = model(x) #经过模型预测
bat_loss = loss(pred, target, model) #计算loss
bat_loss.backward() #梯度回传
optimizer.step() #计算
train_loss += bat_loss.detach().cpu().item() #记录loss值 注意要从gpu上取下来
#再从张量里取出来 plt_train_loss . append(train_loss/trainset.__len__()) #记录

每一个epoch里还有验证步骤。参照训练可以看到每一步的作用。多了一个保存模型的步骤。保存loss最低时的那个模型。

        model.eval()
with torch.no_grad():
for data in valloader:
val_x , val_target = data[0].to(device), data[1].to(device)
val_pred = model(val_x)
val_bat_loss = loss(val_pred, val_target, model)
val_loss += val_bat_loss
val_rel.append(val_pred)
if val_loss < min_val_loss:
min_val_loss = val_loss
torch.save(model, save_) plt_val_loss . append(val_loss/valloader.__len__())

还有绘图: 画出loss的变化情况。

    plt.plot(plt_train_loss)
plt.plot(plt_val_loss)
plt.title('loss')
plt.legend(['train', 'val'])
plt.show()

完整的训练代码:这一部分被我放在model_utils的train模块里。


import torch
import time
import matplotlib.pyplot as plt def train_val(model, trainloader, valloader,optimizer, loss, epoch, device, save_): # trainloader = DataLoader(trainset,batch_size=batch,shuffle=True)
# valloader = DataLoader(valset,batch_size=batch,shuffle=True)
model = model.to(device)
plt_train_loss = []
plt_val_loss = []
val_rel = []
min_val_loss = 100000 for i in range(epoch):
start_time = time.time()
model.train()
train_loss = 0.0
val_loss = 0.0
for data in trainloader:
optimizer.zero_grad()
x , target = data[0].to(device), data[1].to(torch.float32).to(device)
pred = model(x)
bat_loss = loss(pred, target, model)
bat_loss.backward()
optimizer.step()
train_loss += bat_loss.detach().cpu().item() plt_train_loss . append(train_loss/trainloader.__len__()) model.eval()
with torch.no_grad(): #验证时 不计算梯度
for data in valloader:
val_x , val_target = data[0].to(device), data[1].to(device)
val_pred = model(val_x)
val_bat_loss = loss(val_pred, val_target, model)
val_loss += val_bat_loss
val_rel.append(val_pred)
if val_loss < min_val_loss:
torch.save(model, save_)
min_val_loss = val_loss
plt_val_loss . append(val_loss/valloader.__len__()) print('[%03d/%03d] %2.2f sec(s) TrainLoss : %3.6f | valLoss: %3.6f' % \
(i, epoch, time.time()-start_time, plt_train_loss[-1], plt_val_loss[-1])
) plt.plot(plt_train_loss)
plt.plot(plt_val_loss)
plt.title('loss')
plt.legend(['train', 'val'])
plt.show()

四:测试和保存步骤 。

测试和验证时很相似的。 少的是预测值和真值的比较,因为没有真值 ,多的是预测值得保存。按照kaggle要求保存在csv里 。这一部分被我放在model_utils的evaluate模块里。

完整代码:

import numpy as np
import torch
from torch.utils.data import DataLoader import csv def evaluate(model_path, testset, rel_path ,device):
model = torch.load(model_path).to(device)
testloader = DataLoader(testset,batch_size=1,shuffle=False) #放入loader 其实可能没必要 loader作用就是把数据形成批次而已
val_rel = []
model.eval()
with torch.no_grad():
for data in testloader:
x = data.to(device)
pred = model(x)
val_rel.append(pred.item())
print(val_rel)
with open(rel_path, 'w') as f:
csv_writer = csv.writer(f) #百度的csv写法
csv_writer.writerow(['id','tested_positive'])
for i in range(len(testset)):
csv_writer.writerow([str(i),str(val_rel[i])])

五 : 主函数。

万事俱备,只欠东风。就像人的四肢脑袋都齐了,就差个body把他们连起来了,起这个作用的 就是main函数。

调包第一步 除了系统包 还有自己写的

from model_utils.model import myNet
from model_utils.data import covidDataset
from model_utils.train import train_val
from model_utils.evaluate import evaluate
from torch import optim
import torch.nn as nn
import torch
from torch.utils.data import Dataset,DataLoader

路径和设备 以及一些超参。 在这里 我尝试将一些超参放入字典中。

device = 'cuda' if torch.cuda.is_available() else 'cpu'  #设备一般gpu 没有就cpu
train_path = 'covid.train.csv' #训练数据路径
test_path = 'covid.test.csv' #测试数据路径 feature_dim = 6 #重要的特征数
trainset = covidDataset(train_path,'train',feature_dim=feature_dim)
valset = covidDataset(train_path,'val',feature_dim=feature_dim)
testset = covidDataset(test_path,'test',feature_dim=feature_dim)
#对照数据部分 读取了三个数据set config = {
'n_epochs': 2000, # maximum number of epochs
'batch_size': 270, # mini-batch size for dataloader
'optimizer': 'SGD', # optimization algorithm (optimizer in torch.optim)
'optim_hparas': { # hyper-parameters for the optimizer (depends on which optimizer you are using)
'lr': 0.0001, # learning rate of SGD
'momentum': 0.9 # momentum for SGD
},
'save_path': 'model_save/model.pth', # your model will be saved here
} #一些超参数 比如epoch batchsize lr 等等。

定义loss  这里采用了mseloss 然后还加上了正则化

def getLoss(pred, target, model):
loss = nn.MSELoss(reduction='mean')
''' Calculate loss '''
regularization_loss = 0
for param in model.parameters():
# 使用L2正则项
regularization_loss += torch.sum(param ** 2)
return loss(pred, target) + 0.00075 * regularization_loss loss = getLoss

定义model和优化器 以及数据传入loader 前面说过这是为了批量处理

model = myNet(feature_dim).to(device)
optimizer = optim.SGD(model.parameters(), lr=0.001,momentum=0.9) trainloader = DataLoader(trainset,batch_size=config['batch_size'],shuffle=True)
valloader = DataLoader(valset,batch_size=config['batch_size'],shuffle=True)

训练和测试


train_val(model, trainloader,valloader,optimizer, loss, config['n_epochs'],device,save_=config['save_path'])
evaluate(config['save_path'], testset, 'pred.csv',device)

完整代码:

from model_utils.model import myNet
from model_utils.data import covidDataset
from model_utils.train import train_val
from model_utils.evaluate import evaluate
from torch import optim
import torch.nn as nn
import torch
from torch.utils.data import Dataset,DataLoader device = 'cuda' if torch.cuda.is_available() else 'cpu'
train_path = 'covid.train.csv'
test_path = 'covid.test.csv' feature_dim = 6
trainset = covidDataset(train_path,'train',feature_dim=feature_dim)
valset = covidDataset(train_path,'val',feature_dim=feature_dim)
testset = covidDataset(test_path,'test',feature_dim=feature_dim) config = {
'n_epochs': 2000, # maximum number of epochs
'batch_size': 270, # mini-batch size for dataloader
'optimizer': 'SGD', # optimization algorithm (optimizer in torch.optim)
'optim_hparas': { # hyper-parameters for the optimizer (depends on which optimizer you are using)
'lr': 0.0001, # learning rate of SGD
'momentum': 0.9 # momentum for SGD
},
'early_stop': 200, # early stopping epochs (the number epochs since your model's last improvement)
'save_path': 'model_save/model.pth', # your model will be saved here
} def getLoss(pred, target, model):
loss = nn.MSELoss(reduction='mean')
''' Calculate loss '''
regularization_loss = 0
for param in model.parameters():
# TODO: you may implement L1/L2 regularization here
# 使用L2正则项
# regularization_loss += torch.sum(abs(param))
regularization_loss += torch.sum(param ** 2)
return loss(pred, target) + 0.00075 * regularization_loss loss = getLoss model = myNet(feature_dim).to(device)
optimizer = optim.SGD(model.parameters(), lr=0.001,momentum=0.9) trainloader = DataLoader(trainset,batch_size=config['batch_size'],shuffle=True)
valloader = DataLoader(valset,batch_size=config['batch_size'],shuffle=True) train_val(model, trainloader,valloader,optimizer, loss, config['n_epochs'],device,save_=config['save_path'])
evaluate(config['save_path'], testset, 'pred.csv',device)

事后:

运行主函数 我们将得到 pred.csv。这就是我们得预测结果啦。打开kaggle网址项目所在页, 注册,点击late submission 提交你的pred.csv文件吧。 这也是我第一次用kaggle。 好像我的得分也很低。大家如果想得一个比较高得分,可以多调调超参和模型。fighting!!!

李宏毅老师前年课程的第一个作业也是回归,不过不是新冠。当时我啥都不会写,把网上得copy下来,一步一步调试才慢慢懂一点点。 这次第二次做回归,只能说比第一次熟练了很多,虽然还是不能全部一个人写下来。 写这个文章,与大家共勉。

2022李宏毅作业hw1—新冠阳性人员数量预测。的更多相关文章

  1. Python小白的数学建模课-A3.12 个新冠疫情数模竞赛赛题与点评

    新冠疫情深刻和全面地影响着社会和生活,已经成为数学建模竞赛的背景帝. 本文收集了与新冠疫情相关的的数学建模竞赛赛题,供大家参考,欢迎收藏关注. 『Python小白的数学建模课 @ Youcans』带你 ...

  2. 参加Folding@Home(FAH)项目,为战胜新冠肺炎贡献出自己的一份力量

    鉴于新冠病毒(COVID-19)在全球范围内的大规模传播,PCMR和NVIDIA呼吁全球PC用户加入Folding@home项目贡献自己闲置的GPU计算力,协助抗击新冠状病毒疫情. 目前全球有超过40 ...

  3. 数据、人工智能和传感器按COVID-19新冠流感排列

    数据.人工智能和传感器按COVID-19新冠流感排列 Data, AI and sensors arrayed against COVID-19 各国政府.卫生保健专业人士和工业界争先恐后地应对Cov ...

  4. Python小白的数学建模课-B6. 新冠疫情 SEIR 改进模型

    传染病的数学模型是数学建模中的典型问题,常见的传染病模型有 SI.SIR.SIRS.SEIR 模型. SEIR 模型考虑存在易感者.暴露者.患病者和康复者四类人群,适用于具有潜伏期.治愈后获得终身免疫 ...

  5. SIR模型预测新冠病毒肺炎发病数据

    大家还好吗? 背景就不用多说了吧?本来我是初四上班的,现在延长到2月10日了.这是我工作以来时间最长的一个假期了.可惜哪也去不了.待在家里,没啥事,就用python模拟预测一下新冠病毒肺炎的数据吧.要 ...

  6. iMX287A基于嵌入式Qt的新冠肺炎疫情监控平台

    目录 1.前言 2.数据接口的获取 3.Qt界面的实现 4.在开发板上运行Qt程序 5.最终效果 6.代码下载 @ 1.前言 之前我使用在桌面版本Qt实现了肺炎疫情监控平台:基于Qt的新冠肺炎疫情数据 ...

  7. 面试刷题26:新冠攻击人类?什么攻击java平台?

    可恶的新冠病毒攻击人类,搞得IT就业形势相当不好?好在有钟南山院士带领我们提前开展好了防护工作! java作为基础平台安装在各种移动设备,PC,小型机,分布式服务器集群,各种不同的操作系统上.所以,对 ...

  8. Python模块---制作新冠疫情世界地图()

    目录 pyecharts模块 简介 安装pyecharts 测试pyecharts模块 pyecharts实战:绘制新冠肺炎疫情地图 需求分析 请求数据 提取数据 处理数据 制作可视化地图 设置可视化 ...

  9. python画新冠肺炎国内和世界各国累计确诊数量热图

    新冠肺炎国内疫情基本控制住,很多地方都开始摘下口罩了.但是国外的疫情依然处于爆发期,特别是美国,截止目前其累计确诊数量已突破110w.五一节北京柳絮杨絮满天飞,不适合外出.在家心血来潮,献丑画一下各地 ...

随机推荐

  1. leetcode 206. 反转链表 及 92. 反转链表 II

    206. 反转链表 问题描述 反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1-> ...

  2. 【刷题-LeetCode】204. Count Primes

    Count Primes Count the number of prime numbers less than a non-negative number, *n*. Example: Input: ...

  3. 【刷题-LeetCode】154 Find Minimum in Rotated Sorted Array II

    Find Minimum in Rotated Sorted Array II Suppose an array sorted in ascending order is rotated at som ...

  4. visual studio进行机器学习与python编写

    visual studio里的python安装之后自带一个虚拟环境 1.anaconda有些包版本无法到最新. 2.包管理器在安装卸载,强制停止后,包管理器会出问题,一直卸不掉那个包. 在卸载pyth ...

  5. Cesium入门4 - 创建Cesium Viewer

    Cesium入门4 - 创建Cesium Viewer Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ 任何Ce ...

  6. java有四种访问权限

    Java面向对象的封装性是通过对成员变量和方法进行访问控制实现的,访问控制分为4个等级:私有.默认.保护和公有,具体规则如下表:

  7. go get失败解决办法

    go get时由于防火墙的原因,会导致失败.目前可以通过修改GOPROXY的方法解决该问题. 无论是在win下还是linux,macos下,只需要将环境变量GOPROXY设置成https://gopr ...

  8. TF-IDF计算相似度为什么要对稀疏向量建立索引?

    TF-IDF的向量表示的稀疏问题 之前在看tf-idf代码时候思考了一个问题,不知道对于初学的大部分同学有没有这样一个疑惑,用tf-idf值构成的向量,维度可能跟词表的大小有关,那么对于一句话来说,这 ...

  9. Python 序列类型小结

    序列是python中最基本的数据结构. 序列中每一个元素都有其对应的索引,索引是从0开始,0,1,2......依次类推 python中的序列类型有:字符串str.列表list.元组tuple.Uni ...

  10. 深入学习python内存管理

    深入Python的内存管理   作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 语言的内存管理是语言设计的一个重要方面.它是决定语 ...