from datetime import datetime
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import DataFrame
from pandas import concat
from torch import nn
import torch
from sklearn.feature_selection import mutual_info_regression
from sklearn.preprocessing import LabelEncoder, MinMaxScaler
from torch.nn import Sigmoid, ReLU, Dropout, MaxPool2d, Conv2d
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
n_vars = 1 if type(data) is list else data.shape[1]
df = DataFrame(data)
cols, names = list(), list()
for i in range(n_in, 0, -1):
cols.append(df.shift(i))
names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
for i in range(0, n_out):
cols.append(df.shift(-i))
if i == 0:
names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
else:
names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
agg = concat(cols, axis=1)
agg.columns = names
if dropnan:
agg.dropna(inplace=True)
return agg
def parse(x):
return datetime.strptime(x, '%Y %m %d %H')
df=pd.read_csv("pollution_small.csv",index_col= "datetime", parse_dates = {"datetime":['year', 'month', 'day', 'hour']}, date_parser=parse) #读取数据并拼接时间
df=df.drop(labels=["No"],axis=1)
df.rename(columns={"DEWP":"dew","TEMP":"tem","PRES":"press","cbwd":"wnd_dir","Iws":"wnd_spd","Is":"snow","Ir":"rain"},inplace=True)
df.dropna(subset = ['pm2.5'], inplace = True) #去掉pm25为空的行
print(df)
print(df.shape)
values = df.values #数值特征变量
groups = [0, 1, 2, 3, 5, 6, 7]
i = 1
plt.figure() #新建画布
for group in groups:
plt.subplot(len(groups), 1, i) #子图
plt.plot(values[:, group]) #折线图
plt.title(df.columns[group], y = 0.5, fontsize = 10, loc = "right") #取字段为子图标题
i +=1
plt.show()
df[['pm2.5']].plot()
plt.ylabel("concentration")
plt.xlabel("times")
plt.show()
train_data_size=round(len(df)*0.8)
test_data_size=round(len(df)*0.2)
print("训练数据集的长度为:{}".format(train_data_size))
print("测试数据集的长度为:{}".format(test_data_size))
values = df.values
#对风向字段进行编码
encoder = LabelEncoder()
values[:,4] = encoder.fit_transform(values[:,4])
# 确保所有变量都是实数型
values = values.astype('float32')
#对数据进行标准化出来
scaler = MinMaxScaler(feature_range=(0, 1))
scaled = scaler.fit_transform(values)
# 将时间序列数据转换成监督学习数据
reframed = series_to_supervised(scaled, 1, 1)
# 删除那些不需要预测的列
reframed.drop(reframed.columns[[9,10,11,12,13,14,15]], axis=1, inplace=True)
print(reframed.head())
print(list(reframed))
data=reframed.drop(labels=["var1(t-1)"],axis=1)
values=data.values
data = data.astype('float32')
print(data)
print(list(data))
class cnn_lstm(nn.Module):
def __init__(self,window_size,feature_number):
super(cnn_lstm, self).__init__()
self.window_size=window_size
self.feature_number=feature_number
self.conv1 = Conv2d(in_channels=1, out_channels=128, kernel_size=3, stride=1, padding=1)
self.relu1 = ReLU()
self.maxpooling1 = MaxPool2d(3, stride=1,padding=1)
self.dropout1 = Dropout(0.3)
self.lstm1 = nn.LSTM(input_size=128 * feature_number, hidden_size=128, num_layers=1, batch_first=True)
self.lstm2 = nn.LSTM(input_size=128, hidden_size=64, num_layers=1, batch_first=True)
self.fc = nn.Linear(in_features=64, out_features=32)
self.relu2 = nn.ReLU()
self.head = nn.Linear(in_features=32, out_features=1)
def forward(self, x):
x = x.reshape([x.shape[0], 1, self.window_size, self.feature_number])
# x = x.transpose(-1, -2)
x = self.conv1(x)
x = self.relu1(x)
x = self.maxpooling1(x)
x = self.dropout1(x)
x = x.reshape([x.shape[0], self.window_size, -1])
# x = x.transpose(-1, -2) #
x, (h, c) = self.lstm1(x)
x, (h, c) = self.lstm2(x)
x = x[:, -1, :] # 最后一个LSTM只要窗口中最后一个特征的输出
x = self.fc(x)
x = self.relu2(x)
x = self.head(x)
return x
# 创建两个列表,用来存储数据的特征和标签
data_feat, data_target = [],[]
# 设每条数据序列有20组数据
seq = 20
for index in range(len(data) - seq):
# 构建特征集
data_feat.append(data[["var2(t-1)","var3(t-1)","var4(t-1)",'var5(t-1)', 'var6(t-1)', 'var7(t-1)', 'var8(t-1)']][index: index + seq].values)
# 构建target集
data_target.append(data['var1(t)'][index:index + seq])
# 将特征集和标签集整理成numpy数组
data_feat = np.array(data_feat)
data_target = np.array(data_target)
# 这里按照8:2的比例划分训练集和测试集
test_set_size = int(np.round(0.2*data.shape[0])) # np.round(1)是四舍五入,
train_size = data_feat.shape[0] - (test_set_size)
print(test_set_size) # 输出测试集大小
print(train_size) # 输出训练集大小
trainX = torch.from_numpy(data_feat[:train_size].reshape(-1,seq,7)).type(torch.Tensor)
testX = torch.from_numpy(data_feat[train_size:].reshape(-1,seq,7)).type(torch.Tensor)
trainY = torch.from_numpy(data_target[:train_size].reshape(-1,seq,1)).type(torch.Tensor)
testY = torch.from_numpy(data_target[train_size:].reshape(-1,seq,1)).type(torch.Tensor)
print('x_train.shape = ',trainX.shape)
print('y_train.shape = ',trainY.shape)
print('x_test.shape = ',testX.shape)
print('y_test.shape = ',testY.shape)
model=cnn_lstm(20,7)
optimiser = torch.optim.Adam(model.parameters(), lr=0.01) # 使用Adam优化算法
loss_fn = torch.nn.MSELoss(size_average=True) # 使用均方差作为损失函数
# 设定数据遍历次数
num_epochs = 100
# 打印模型结构
print(model)
# 打印模型各层的参数尺寸
for i in range(len(list(model.parameters()))):
print(list(model.parameters())[i].size())
# train model
hist = np.zeros(num_epochs)
for t in range(num_epochs):
# Initialise hidden state
# Don't do this if you want your LSTM to be stateful
# model.hidden = model.init_hidden()
# Forward pass
y_train_pred = model(trainX)
loss = loss_fn(y_train_pred, trainY)
if t % 10 == 0 and t != 0: # 每训练十次,打印一次均方差
print("Epoch ", t, "MSE: ", loss.item())
hist[t] = loss.item()
# Zero out gradient, else they will accumulate between epochs 将梯度归零
optimiser.zero_grad()
# Backward pass
loss.backward()
# Update parameters
optimiser.step()
# 计算训练得到的模型在训练集上的均方差
y_train_pred = model(trainX)
loss_fn(y_train_pred, trainY).item()
# make predictions
y_test_pred = model(testX)
loss_fn(y_test_pred, testY).item()
"训练集效果图"
pred_value = y_train_pred.detach().numpy()[:,-1,0]
true_value = trainY.detach().numpy()[:,-1,0]
plt.plot(pred_value, label="Preds",color='r') # 预测值
plt.plot(true_value, label="Data",color="g") # 真实值
plt.legend()
plt.show()
这是我cnn-lstm 模型 数据的维度是:
x_train.shape = torch.Size([19841, 20, 7])
y_train.shape = torch.Size([19841, 20, 1])
x_test.shape = torch.Size([4965, 20, 7])
y_test.shape = torch.Size([4965, 20, 1])
报错的代码时:loss = loss_fn(y_train_pred, trainY)
原因是:RuntimeError: The size of tensor a (19841) must match the size of tensor b (20) at non-singleton dimension 1
不知道是哪里出了问题 请求指教
维度问题,参考这篇博客,https://blog.csdn.net/weixin_41041772/article/details/123296659?spm=1001.2014.3001.5506
y的维度应该是19841