河南省建设监理协会官方网站,东莞效果好的网站建设,中铁建设集团门户网登,关于网站建设的论文题目基于LSTM的一维数据拟合扩展
一、引(fei)言(hua)
我在做Sri Lanka生态系统服务价值计算时#xff0c;中间遇到了一点小问题。从世界粮农组织(FAO)上获得Sri Lanka主要农作物产量和价格数据时#xff0c;其中的主要作物Sorghum仅有2001-2006年的数据#xff0c;而Millet只有…基于LSTM的一维数据拟合扩展
一、引(fei)言(hua)
我在做Sri Lanka生态系统服务价值计算时中间遇到了一点小问题。从世界粮农组织(FAO)上获得Sri Lanka主要农作物产量和价格数据时其中的主要作物Sorghum仅有2001-2006年的数据而Millet只有2001-2005,2020-2021这样的间断数据。虽然说可以直接剔除这种过分缺失的数据但这无疑会对生态因子的计算造成重大影响。所以我想要不要整个函数把他拟合一下刚好Maize和Rice有2001-2021的完备数据于是这个文档就这样诞生了。 二、数据
数据来自FAO考虑到可能有同学想要跟着尝试一下这里给出用到的数据。
作物产量
作物价格
2.1 数据探查
我们读取数据并进行简单的统计量查看。如果要进一步深入研究数据分布及可视化可以看看我的这篇文章
import pandas as pdpathrYourPathyield_pd.read_csv(pathr\yield.csv)
pp_pd.read_csv(pathr\Producer Prices.csv)yield_.head()需要用到的属性只有Item,Year,Unit,Value
所以我们做这样的处理
yield_yield_[[Item,Year,Unit,Value]]可以看到有些数据是从1961年开始的太旧了就不用了我们从2001年开始。
yield_yield_[yield_[Year]2000]同样我们来看看pp_的情况
pp_.head()pp_pp_[[Item,Year,Value,Element]]
pp_pp_[pp_[Year]2000]实际上在这个数据里产量已经没有问题了。我们只需要做一个简单的处理
yield_.groupby(Item).mean()[Value]/10 #转为千克便可拿到每种作物近二十年的平均产量。
好了现在大问题出现在价值上我们从下往上看就知道了
pp_.tail(10)高粱只有2006年的那有没有办法利用现成的数据将其扩展呢
实际上这类拟合问题有很多种解决方案但是本问题涉及到时间之前时间段的因子以及可能的周期性都会增加拟合的复杂性。所以在这里我们采用LSTM来填充数据。 三、模型构建
在本小节我们将比较传统一维CNN与RNN在结果上的异同。
一般做一维RNN时可以指定一个时间窗口比如用2006,2007,2008年的数据推理2009年的数据用2007,2008,2009年推理2010年。
我们现在要用之前处理好的pp_c数据中的玉米产量来预测高粱产量。所以第一步就是将其转化为torch接受的格式。
别忘记导入模块
import torch
import torch.nn as nn
from torch.nn import functional as Fxpp_c[pp_c[Item]Maize (corn)][Value]
xtorch.FloatTensor(x)之前写数据迭代器的时候除了可以继承自torch.utils.data.DataLoader也可以是任意的可迭代对象。这里我们可以简单的设置一个类
# 设置迭代器
class MyDataSet(object):def __init__(self,seq,ws6):# ws是滑动窗口大小self.ori[i for i in seq[:ws]]self.label[i for i in seq[ws:]]self.reset()self.wswsdef set(self,dpi):# 添加数据self.x.append(dpi)def reset(self):# 初始化self.xself.ori[:]def get(self,idx):return self.x[idx:idxself.ws],self.label[idx]def __len__(self):return len(self.x)哦这边提一下有两种方式一种是用原始数据做预测一种是用预测数据做预测可能有点抽象下面举个例子。
假设 A [ a 1 , a 2 , a 3 , a 4 , a 5 , a 6 ] A[a1,a2,a3,a4,a5,a6] A[a1,a2,a3,a4,a5,a6]时间窗口大小为3。
用原始数据做预测那么输入值为 a 1 , a 2 , a 3 a1,a2,a3 a1,a2,a3得到的结果将与 a 4 a4 a4做比较。下一轮输入为 a 2 , a 3 , a 4 a2,a3,a4 a2,a3,a4得到的结果将与 a 5 a5 a5做比较。
而用预测的数据做预测第一轮输入值为 a 1 , a 2 , a 3 a1,a2,a3 a1,a2,a3得到的结果是 b 4 b4 b4在与 a 4 a4 a4做比较后下一轮的输入为 a 2 , a 3 , b 4 a2,a3,b4 a2,a3,b4会出现如下情况
输入数据为 b 4 , b 5 , b 6 b4,b5,b6 b4,b5,b6。
我们现在举的例子是用预测的数据做预测。当然最后也会给出一个用原始数据做预测的版本那个版本相对简单。
ws6 # 全局时间窗口
train_dataMyDataSet(x,ws)网络的架构如下 class Net3(nn.Module):def __init__(self,in_features54,n_hidden1128,n_hidden2256,n_hidden3512,out_features7):super(Net3, self).__init__()self.flattennn.Flatten()self.hidden1nn.Sequential(nn.Linear(in_features,n_hidden1,False),nn.ReLU())self.hidden2nn.Sequential(nn.Linear(n_hidden1,n_hidden2),nn.ReLU())self.hidden3nn.Sequential(nn.Linear(n_hidden2,n_hidden3),nn.ReLU())self.outnn.Sequential(nn.Linear(n_hidden3,out_features))def forward(self,x):xself.flatten(x)xself.hidden2(self.hidden1(x))xself.hidden3(x)return self.out(x)class CNN(nn.Module):def __init__(self, output_dim1,ws6):super(CNN, self).__init__()self.relu nn.ReLU(inplaceTrue)self.conv1 nn.Conv1d(ws, 64, 1)self.lr nn.LeakyReLU(inplaceTrue)self.conv2 nn.Conv1d(64, 128, 1)self.bn1, self.bn2 nn.BatchNorm1d(64), nn.BatchNorm1d(128)self.bn3, self.bn4 nn.BatchNorm1d(1024), nn.BatchNorm1d(128)self.flatten nn.Flatten()self.lstm1 nn.LSTM(128, 1024)self.lstm2 nn.LSTM(1024, 256)self.lstm3nn.LSTM(256,512)self.fc nn.Linear(512, 512)self.fc4nn.Linear(512,256)self.fc1 nn.Linear(256, 64)self.fc3 nn.Linear(64, output_dim)staticmethoddef reS(x):return x.reshape(-1, x.shape[-1], x.shape[-2])def forward(self, x):x self.reS(x)x self.conv1(x) x self.lr(x)x self.conv2(x) x self.lr(x)x self.flatten(x)# LSTM部分x, h self.lstm1(x)x, h self.lstm2(x)x,hself.lstm3(x)x, _ hx self.fc(x.reshape(-1, ))x self.relu(x)x self.fc4(x)x self.relu(x)x self.fc1(x)x self.relu(x)x self.fc3(x)return x
Net3主要是一维卷积CNN加入了LSTM结构。至于名字是随便取的…跟内容并无关系。 def Train(model,train_data,seed1):devicecuda if torch.cuda.is_available() else cpumodelmodel.to(device)Mloss100000pathrYourPath\%s.pth%seed# 设置损失函数,这里使用的是均方误差损失criterion nn.MSELoss()# 设置优化函数和学习率lroptimizertorch.optim.Adam(model.parameters(),lr1e-5,betas(0.9,0.99),eps1e-07,weight_decay0)# 设置训练周期epochs 3000criterioncriterion.to(device)model.train()for epoch in range(epochs):total_loss0for i in range(len(x)-ws):# 每次更新参数前都梯度归零和初始化seq,y_traintrain_data.get(i) # 从我们的数据集中拿出数据seq,y_traintorch.FloatTensor(seq),torch.FloatTensor([y_train])seqseq.unsqueeze(dim0)seq,y_trainseq.to(device),y_train.to(device)optimizer.zero_grad()# 注意这里要对样本进行reshape# 转换成conv1d的input sizebatch size, channel, series lengthy_pred model(seq)loss criterion(y_pred, y_train)loss.backward()train_data.set(y_pred.to(cpu).item()) # 再放入预测数据optimizer.step()total_losslosstrain_data.reset()if total_loss.tolist()Mloss:Mlosstotal_loss.tolist()torch.save(model.state_dict(),path)print(Saving)print(fEpoch: {epoch1:2} Mean Loss: {total_loss.tolist()/len(train_data):10.8f})return model正常训练就OK
dCNN(wsws)
Train(d,train_data,4)平均损失在10点左右还有很大优化空间。当然我们这里只是举个非常简单的例子就是个baseline
checkpointtorch.load(rYourPath\4.pth)
d.load_state_dict(checkpoint) # 加载最佳参数
d.to(cpu)四、结果可视化
我们这里用到Pyechart进行可视化。
from pyecharts.charts import *
from pyecharts import options as opts
from pyecharts.globals import CurrentConfigpre,ppre[i.item() for i in x[:ws]],[]
# pre 是用原始数据做预测
# ppre 用预测数据做预测
for i in range(len(x)-ws1):ppre.append(d(torch.FloatTensor(x[i:iws]).unsqueeze(dim0)))pre.append(d(torch.FloatTensor(pre[-ws:]).unsqueeze(dim0)).item())lLine()
l.add_xaxis([i for i in range(len(x))])
l.add_yaxis(Original Data,x.tolist())
l.add_yaxis(Pred Data(Using Raw Datas),x[:ws].tolist()[i.item() for i in ppre])
l.add_yaxis(Pred Data(Using Pred Datas),pre)
l.set_series_opts(label_optsopts.LabelOpts(is_showFalse))
l.set_global_opts(title_optsopts.TitleOpts(titleLSTM CNN))l.render_notebook()根据时间窗口的不同可以得到不同的结果。
ws4 ws5 ws6 从结果上来看时间窗口越大越好。但是这里我们只能到六了再大就不礼貌了。(高粱只有六个节点的数据)。
至于验证我们可以选Rice做验证
xtorch.FloatTensor(pp_c[pp_c[Item]Rice][Value].tolist())
pre,ppre[i.item() for i in x[:ws]],[]
for i in range(len(x)-ws1):ppre.append(d(torch.FloatTensor(x[i:iws]).unsqueeze(dim0)))pre.append(d(torch.FloatTensor(pre[-ws:]).unsqueeze(dim0)).item())
lLine()
l.add_xaxis([i for i in range(len(x))])
l.add_yaxis(Original Data,x.tolist())
l.add_yaxis(Pred Data(Using Raw Datas),x[:ws].tolist()[i.item() for i in ppre])
l.add_yaxis(Pred Data(Using Pred Datas),pre)
l.set_series_opts(label_optsopts.LabelOpts(is_showFalse))
l.set_global_opts(title_optsopts.TitleOpts(titleLSTM CNN))l.render_notebook()可以发现用预测做预测的结果基本上不会差太多那也就意味着我们可以对高粱进行预测啦不过在这之前我们可以看看用原始数据做训练的结果 时间窗口一样为6可以看到在黑线贴合的非常好但是面对大量缺失的数据精度就远不如用预测数据做预测的结果了。
此外这是用CNN做的结果 我们可以发现LSTM的波动要比CNN好CNN后面死水一潭应该是梯度消失导致的前面信息没有了后面信息又是自个构造的这就导致了到后面变成了线性情况。
那么最后的最后就是预测高粱产量了
pre_datapp_c[pp_c[Item]Sorghum][Value].tolist()
lpre_data[:]
for i in range(len(x)-ws1):l.append(d(torch.FloatTensor(l[-ws:]).unsqueeze(dim0)).item())
LLine()
L.add_xaxis([i for i in range(len(x))])
L.add_yaxis(Pred,l)
L.set_series_opts(label_optsopts.LabelOpts(is_showFalse))
L.set_global_opts(title_optsopts.TitleOpts(titlesorghum production forecasts))L.render_notebook()
l.to_csv(path)