任务背景
利用年、月、日、周几、前天的最高温度值、昨天的最高温度值、历史这天平均最高温度值来预测当天的实际温度值,数据如下:
气温预测数据集
一、导入库
# 矩阵计算库
import numpy as np
# 数据基本处理库,可读取csv文件
import pandas as pd
# 画图展示库
import matplotlib.pyplot as plt
# pytorch框架
import torch
# 优化器
import torch.optim as optim
# 处理时间数据
import datetime
# 归一化数据
from sklearn import preprocessing
# 警告
import warnings
warnings.filterwarnings("ignore")
二、处理数据集
# 更改为自己的文件夹路径
features = pd.read_csv('D:/咕泡人工智能-配套资料/配套资料/4.第四章 深度学习核⼼框架PyTorch/第二,三章:神经网络实战分类与回归任务/神经网络实战分类与回归任务/temps.csv')
# print(features.head())
'''
year month day week temp_2 temp_1 average actual friend
0 2016 1 1 Fri 45 45 45.6 45 29
1 2016 1 2 Sat 44 45 45.7 44 61
2 2016 1 3 Sun 45 44 45.8 41 56
3 2016 1 4 Mon 44 41 45.9 40 53
4 2016 1 5 Tues 41 40 46.0 44 41
year,moth,day,week分别表示的具体的时间
temp_2:前天的最高温度值
temp_1:昨天的最高温度值
average:在历史中,每年这一天的平均最高温度值
actual:这就是我们的标签值了,当天的真实最高温度
friend:这一列可能是凑热闹的,你的朋友猜测的可能值,咱们不管它就好了
'''
# print(features.shape) #(348, 9)
# 获取年月日数据
years = features['year']
months = features['month']
days = features['day']
# 转换为datatime格式,年-月-日
dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)]
dates = [datetime.datetime.strptime(date, '%Y-%m-%d')for date in dates]
# print(dates[:1]) #[datetime.datetime(2016, 1, 1, 0, 0)] 2016.1.1
三、数据展示
# 画图,设置图像风格
plt.style.use('fivethirtyeight')
# 设置布局
# 2行2列10*10图像布局,ax1,ax2, ax3, ax4四个子图
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, figsize=(10, 10))
# x轴标签倾斜45度
fig.autofmt_xdate(rotation=45)
# 标签值
ax1.plot(dates, features['actual'])
ax1.set_xlabel('')
ax1.set_ylabel('Temperature')
ax1.set_title('Max Temp')
# 昨天
ax2.plot(dates, features['temp_1'])
ax2.set_xlabel('')
ax2.set_ylabel('Temperature')
ax2.set_title('Previous Max Temp')
# 前天
ax3.plot(dates, features['temp_2'])
ax3.set_xlabel('Date')
ax3.set_ylabel('Temperature')
ax3.set_title('Two Days Prior Max Temp')
# 朋友预测(无用数据)
ax4.plot(dates, features['friend'])
ax4.set_xlabel('Date')
ax4.set_ylabel('Temperature')
ax4.set_title('Friend Estimate')
# 子图间隔为3
plt.tight_layout(pad=3)
# 画图
plt.show()
数据展示图:
四、数据预处理
# 独热编码
# week列数据均为字符串类型,将week列字符串转变为七位编码,如周一:1000000、周二:0100000
features = pd.get_dummies(features)
# print(features.head(5))
'''
year month day temp_2 ... week_Sun week_Thurs week_Tues week_Wed
0 2016 1 1 45 ... False False False False
1 2016 1 2 44 ... False False False False
2 2016 1 3 45 ... True False False False
3 2016 1 4 44 ... False False False False
4 2016 1 5 41 ... False False True False
'''
# 即将进行标准化操作,预先将数据中x,y提出
# 提出标签-y
labels = np.array(features['actual'])
# print(labels)
# 去除标签列-y,只剩特征x
features = features.drop('actual', axis=1)
# print(features)
# 名单单独保存备份
features_list = list(features.columns)
# 转换为数组格式
features = np.array(features)
# print(features.shape) #(348, 14)
# 特征数据取值范围不同,数值差异较大,神经网络具有数值越大认为越重要的特性,因此要进行标准化
# 标准化操作:(x-均值)/标准差 去均值(数据以原点为中心)--->去标准差(数据x、y方向分布均衡,以原点中心对称)
input_features = preprocessing.StandardScaler().fit_transform(features)
# print(type(input_features), input_features.shape, input_features[0])
'''
<class 'numpy.ndarray'> , (348, 14) [ 0. -1.5678393 -1.65682171 -1.48452388 -1.49443549 -1.3470703
-1.98891668 2.44131112 -0.40482045 -0.40961596 -0.40482045 -0.40482045
-0.41913682 -0.40482045]
'''
五、构建网络模型
#数据转换为tensor格式
x = torch.tensor(input_features, dtype=float)
y = torch.tensor(labels, dtype=float)
#得到输入特征个数
input_size = input_features.shape[1]
#隐藏层输出尺寸
hidden_size = 128
#神经网络输出尺寸
output_size = 1
#一轮计算batch_size个数据,提高计算速率
batch_size = 16
#Sequential序列模块顺序执行,全连接层14*128--->激活函数sigmoid--->全连接层128*1
my_nn = torch.nn.Sequential(
#隐藏层
torch.nn.Linear(input_size, hidden_size),
#隐藏层-激活函数
torch.nn.Sigmoid(),
#输出层
torch.nn.Linear(hidden_size, output_size),
)
#MSELoss损失计算函数,reduction='mean'以平均的形式计算损失
cost = torch.nn.MSELoss(reduction='mean')
#优化器模块,Adam优化器,my_nn.parameters():my_nn中的所有参数都需要进行更新,学习率lr=0.001
optimizer = torch.optim.Adam(my_nn.parameters(), lr=0.001)
# 训练网络
losses = []
for i in range(1000):
batch_loss = []
# MINI-Batch方法来进行训练
#选取start-end区间的数据进行训练
for start in range(0, len(input_features), batch_size):
#防止end选取越界
end = start + batch_size if start + batch_size < len(input_features) else len(input_features)
#选取一个batch_size数据进行训练
xx = torch.tensor(input_features[start:end], dtype=torch.float, requires_grad=True)
yy = torch.tensor(labels[start:end], dtype=torch.float, requires_grad=True)
prediction = my_nn(xx)
#计算损失值
loss = cost(prediction, yy)
#梯度归零
optimizer.zero_grad()
#反向传播计算
loss.backward(retain_graph=True)
#更新权重参数和偏执参数
optimizer.step()
batch_loss.append(loss.data.numpy())
# 打印损失,每1001轮打印一次
if i % 100 == 0:
losses.append(np.mean(batch_loss))
print(i, np.mean(batch_loss))
运行结果:
六、真实值与预测值比对
#预测训练结果
x = torch.tensor(input_features, dtype = torch.float)
#预测值转为ndarray格式,为画图做准备
predict = my_nn(x).data.numpy()
# 转换日期格式
dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)]
dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in dates]
# 创建一个表格来存日期和其对应的标签数值
true_data = pd.DataFrame(data = {'date': dates, 'actual': labels})
# 同理,再创建一个来存日期和其对应的模型预测值
months = features[:, feature_list.index('month')]
days = features[:, feature_list.index('day')]
years = features[:, feature_list.index('year')]
test_dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)]
test_dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in test_dates]
predictions_data = pd.DataFrame(data={'date': test_dates, 'prediction': predict.reshape(-1)})
# 真实值
plt.plot(true_data['date'], true_data['actual'], 'b-', label = 'actual')
# 预测值
plt.plot(predictions_data['date'], predictions_data['prediction'], 'ro', label='prediction')
#x轴标签倾斜60度
plt.xticks(rotation=60)
#图中标明每个曲线代表含义
plt.legend()
# x标签、y轴标签、图名
plt.xlabel('Date'); plt.ylabel('Maximum Temperature (F)'); plt.title('Actual and Predicted Values');
plt.show()
运行结果: