神经网络进行气温预测-学习笔记

部署运行你感兴趣的模型镜像

引言:

气温是气象预测中的一个关键指标,它不仅影响人类的日常生活,还对农业、能源管理和环境监测等领域具有重要意义。准确的气温预测可以帮助人们更好地应对极端天气变化,优化资源利用,并提高生活质量。

在这篇博客中,我们将基于PyTorch实现了一种气温预测模型,通过对历史气温数据的学习与训练,模型能够对未来的气温进行精确预测。

本篇博客是对唐宇迪ai的学习笔记。

环境介绍:

cuda 12.3

python 3.9.2

pytorch 2.3.1 stable

1. 导入各类库函数和包

import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt
import torch
import torch.optim as optim
import warnings
warnings.filterwarnings("ignore")
%matplotlib inline
#可以在jupyter notebook里进行单元格显示图片

#numpy是多维数组处理库
#pandas是结构化数据处理库,例如结构化数据(表格),非结构化数据(时间序列)
#matplotlib为数据可视化库
#torch为深度学习模型库,提供深度学习的的操作,torch.optim为优化器模块
#matplotlib

2. 读取数据

features = pd.read_csv('temps.csv')
#read.csv()是panda库的一个函数,用于读取.csv文件,并将其存储在名为features的Dataframe对象中
#Pandas Dataframe是一种数据结构,可以理解为一个二位数组表格,具有行/列索引值,并且支持异构数据类型,例如数字,字符串等

features.head()
#读取前五行

#features.tail()读取后五行
#print(features.head()),print打印的是字符串的形式

3. 用Matplotlib库展示图像

# 处理时间数据
import datetime


years = features['year']
months = features['month']
days = features['day']
#分别得到年,月,日
#xxx=features['xxx']选择了features dataframe中选中xxx列,并将其存储在xxx变量中

# datetime格式
dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)]
#字符串拼接起来,'str1'+'str2'+'str3'
#[表达式 for 迭代变量 in 可迭代对象]是一个列表推导式:这个生成器表达式会在遍历 for 循环的同时,一边生成表达式的结果,一边将它们添加到最终的列表中

dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in dates]
#datetime.datetime.strptime() 是 Python 标准库 datetime 模块中的一个方法。它的作用是将一个字符串形式的日期时间转换为 datetime.datetime 对象
#datetime.datetime.strptime()的用法
date_string = "2022-01-01 00:00:00"
date_format = "%Y-%m-%d %H:%M:%S"
#date_format 字符串说明了data_string的格式

date_time = datetime.datetime.strptime(date_string, date_format)
print(date_time)
#zip的用法
a=(1,2,3)
b=(4,5,6)
c=(7,8,9)
d=zip(a,b,c)
print(list(d))

#按照索引将a,b,c打包成一个元组,并返回一个可迭代的对象,list将其转化为列表,此时输出的是由元组构成的列表
dates[:5]
#输出前五个元素

#print(len(dates)),输出348

# 准备画图

plt.style.use('fivethirtyeight')
#设置了默认的图片样式


fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, figsize = (10,10))
#创建了一个2*2的网格图像,子图大小为10*10,fig为整个图形变量,ax1-4为子图变量
fig.autofmt_xdate(rotation = 45)
#x轴标签旋转45度

# 标签值
ax1.plot(dates, features['actual'])
#绘制折线图,横坐标为'dates',纵坐标为'actual'

ax1.set_xlabel(''); ax1.set_ylabel('Temperature'); ax1.set_title('Max Temp')
#横坐标标签为'空',纵坐标标签为'Temperature',标题为'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')

plt.tight_layout(pad=3)
#调整子图间距

4. 数据预处理

# 独热编码
features = pd.get_dummies(features)
features.head(5)

#对类别型变量进行编码,如果有N种类型进行N位编码,并且只有一位有效
#将字符型变量转化为数字型变量,并且不设置为1-7是避免数值大小对week偏重的影响

#标签
labels = np.array(features['actual'])

# 在特征中去掉标签
features= features.drop('actual', axis = 1)

# 名字单独保存一下,以备后患
feature_list = list(features.columns)

# 转换成合适的格式
features = np.array(features)

#这一步的目标是为了将dataframe变量转化为numpy的数组变量
print(features.shape)
features

from sklearn import preprocessing
input_features = preprocessing.StandardScaler().fit_transform(features)

#sklearn一个机器学习库,提供数据预处理,以及各种任务的实现
#fit():作用是计算特征的均值和标准差,用于后续的标准化操作,它仅仅是计算并保存了数据的统计特性,并不对数据进行任何变换。
#transform():作用是使用之前通过fit()计算得到的均值和标准差,对输入的数据进行标准化处理,它会将输入的数据减去均值,然后除以标准差,得到标准化后的数据。
#fit_transform():这是fit()和transform()的组合操作,它先计算数据的统计特性,然后立即对数据进行标准化处理,返回标准化后的结果。

#这一步就是计算了features每一列的均值和标准差,并进行标准化放入input_features变量中

#进行标准化的目的是为了让不同的特征在同一尺度下进行学习,目的是确保每个特征在模型训练和预测过程中对结果具有相等的影响力
#例如,Feature1 和 Feature2 的数值范围相差很大,计算距离的时候Feature1的影响会被掩盖

input_features[:2]

5. 构建神经网络模型

5.1 手动构建神经网络模型

#构建网络模型(自己手动定义)
x = torch.tensor(input_features, dtype = float)

y = torch.tensor(labels, dtype = float)
#将与特征和标签转化为tensor格式


weights = torch.randn((14, 128), dtype = float, requires_grad = True) 
biases = torch.randn(128, dtype = float,requires_grad = True ) 
weights2 = torch.randn((128, 1), dtype = float, requires_grad = True) 
biases2 = torch.randn(1, dtype = float, requires_grad = True) 
#权重参数初始化
#这里设置了两个隐层,我们输入数据为348*14,代表有348个样本,14个特征
#h1层为14*128,代表了一个样本的输入输出,经过隐层,会输出128个特征,biases为偏置,个数为输出特征的数量
#h2层为128*1,代表最终会有一个输出,也就是最后的预测温度

#要使张量进行梯度计算,需要设置requires_grad = True

learning_rate = 0.001 
losses = []

for i in range(1000):
#迭代1000次    

    hidden = x.mm(weights) + biases
    # 计算隐层,w*x+b
    
    hidden = torch.relu(hidden)
    # 加入激活函数,relu函数会将负的特征置0
    
    predictions = hidden.mm(weights2) + biases2
    # 预测结果,通常输出层不需要经过relu函数
    
    loss = torch.mean((predictions - y) ** 2) 
    # 定义了一个损失函数,计算了平均平方误差,
    
    losses.append(loss.data.numpy())
    #losses.append在对应数组之后加入元素,计算每一次的损失值
    #tensor.data是一个不包含梯度信息的张量,后续不参与求导,会直接访问底层数据
    #loss.data.numpy会将tensor格式转化为array
    
    if i % 100 == 0:
        print('loss:', loss)
    # 打印损失值,每100次打印一次损失值
    
    loss.backward()
    #进行反向传播,计算梯度
    #在调用 loss.backward()时候,pytorch会开始反向遍历计算图,计算每一个参与变量关于loss的梯度,并且会将梯度累计保存在.grad中
    #其中计算梯度的方式是根据链式法则进行的
    
    #在进行前向传播的时,PyTorch 记录所有操作以构建计算图:
    #例如y=x+2,z=x^2,y 和 z 都是通过对 x 的操作得到的张量,计算图会记录这些操作
    
    weights.data.add_(- learning_rate * weights.grad.data)  
    biases.data.add_(- learning_rate * biases.grad.data)
    weights2.data.add_(- learning_rate * weights2.grad.data)
    biases2.data.add_(- learning_rate * biases2.grad.data)
    #更新参数
    #在执行了,loss.backward()之后,weights.grad表示weights关于loss的梯度
    #深度学习中,反向传播是逐层更新参数的,例如 输出层-h2层,需要计算loss对w2,b2的偏导数,再进行参数更新,h2层-h1层同理
    #因为我们要进行梯度下降,所以要乘一个 - 号,意味梯度的反方向,损失函数下降最快
    #weights.data.add_()是一个原地加法操作,将更新的变量加到weights.data上,如果多次调用 .backward(),梯度将会累积而不会被覆盖

    
    weights.grad.data.zero_()
    biases.grad.data.zero_()
    weights2.grad.data.zero_()
    biases2.grad.data.zero_()
    #每次迭代都得记得清空,torch中会自动累加
    #PyTorch等深度学习框架提供了自动求导功能,能够自动跟踪计算图中的操作,并计算梯度

#打印结果
print(predictions.data[:4])
print(predictions[:4])
predictions[:4]

5.2 内置函数构建神经网络模型(更加方便)

#构建神经网络模型(内置函数定义)
input_size = input_features.shape[1]
hidden_size = 128
output_size = 1
batch_size = 16
my_nn = torch.nn.Sequential(
#torch.nn.Sequential用于顺序定义线性的神经网络层    

    torch.nn.Linear(input_size, hidden_size),
    #隐层
    
    torch.nn.Sigmoid(),
    #通常经过一个参数计算,也就是应该一个隐层,通常需要经过一次非线性计算
    
    torch.nn.Linear(hidden_size, output_size),
    #输出层
)
cost = torch.nn.MSELoss(reduction='mean')
#定义一个均方误差损失函数

optimizer = torch.optim.Adam(my_nn.parameters(), lr = 0.001)
#定义一个Admam优化器,Adam的效果很好并且效率很快,容易找到w的最优解,效果比SGD好
#根据四边形合成方向,更加容易找到最优解
# 训练网络
losses = []
for i in range(1000):
#循环迭代次数
    
    batch_loss = []
    #初始化一个批次损失表,用来记录每个批次训练的损失值
    
    for start in range(0, len(input_features), batch_size):
    # MINI-Batch方法来进行训练
    #遍历整个数据集,每次训练batch_size个样本数据,目的是训练更快
    
        end = start + batch_size if start + batch_size < len(input_features) else len(input_features)
        #条件表达式A if condition else B,如果表达式为真,返回A;否则,返回B
        
        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)
        #从 input_features 和 labels 中提取当前批次的数据,并转换为 PyTorch 的张量,设置 requires_grad=True 以便在反向传播时计算梯度
        
        prediction = my_nn(xx)
        #预测值
        
        loss = cost(prediction, yy)
        #损失值
        
        optimizer.zero_grad()
        #pytorch中梯度是累加的,需要在反向传播前梯度清零,+
        
        loss.backward(retain_graph=True)
        #开启反向传播,计算梯度,retain_graph=True 表示保留计算图
        
        optimizer.step()
        #更新参数
        
        batch_loss.append(loss.data.numpy())
        #将loss的数据转化为array格式,并将当前批次的损失值添加到 batch_loss 列表中
    
    # 打印损失
    if i % 100==0:
        losses.append(np.mean(batch_loss))
        #np.mean(batch_loss) 计算当前迭代中所有批次损失的平均值,并加入到losses这个表中
        
        print(i, np.mean(batch_loss))

6. 结果展示

x = torch.tensor(input_features, dtype = torch.float)
#x为tensor格式的输入数据

predict = my_nn(x).data.numpy()
#predict为array格式的预测值
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]
#转换日期格式
#将years,months,days三个元素配对(zip)在一起,每次迭代循环返回一个三元组
#将元组格式转化为“year-month-day”的格式

#列表推导式 [datetime.datetime.strptime(date, '%Y-%m-%d') for date in dates]:将每个日期字符串转换为 datetime 对象,格式为 '%Y-%m-%d'

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')]
#同理,再创建一个来存日期和其对应的模型预测值
#其中,“:”代表所有行,“feature_list.index('month')”找到month索引所在的列

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)}) 
#创建一个表格来存预测值,predict.reshape(-1):将 predict 转换为一维数组,以确保数据框的格式正确
predictions_data

# 真实值
plt.plot(true_data['date'], true_data['actual'], 'b-', label = 'actual')

# 预测值
plt.plot(predictions_data['date'], predictions_data['prediction'], 'ro', label = 'prediction')
plt.xticks(rotation = 60); 
plt.legend()

# 图名
plt.xlabel('Date'); plt.ylabel('Maximum Temperature (F)'); plt.title('Actual and Predicted Values');

#plt.plot(x, y, format, label)
#plt.xticks(rotation = 60),将 X 轴的刻度标签旋转 60 度
#plt.legend()添加图例

结语:

其实可以发现,预测值和真实温度之间还是具有差别,我们可以设置隐层数量和增加迭代次数来提升模型的学习能力,增加隐层是为了让模型学习到更深层的特征表示。

整体流程就是这样,这是一个线性的神经网络,大家要充分理解标准化的操作和神经网络的搭建流程。

本人也是在学习AI的道路上,欢迎大家提出问题和分享答案。

您可能感兴趣的与本文相关的镜像

PyTorch 2.5

PyTorch 2.5

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值