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") # 版本不同忽略警告
features = pd.read_csv('temps.csv')
# 看看数据长什么样子,head( )函数只能读取前五行数据
print(features.head())
'''
数据表中
year,moth,day,week分别表示的具体的时间
temp_2:前天的最高温度值
temp_1:昨天的最高温度值
average:在历史中,每年这一天的平均最高温度值
actual:这就是我们的标签值了,当天的真实最高温度
friend:你的朋友猜测的可能值
'''
print('数据维度:', features.shape)
# 处理时间数据
import datetime
# 分别得到年,月,日
years = features['year']
months = features['month']
days = features['day']
plt.style.use('fivethirtyeight')
# 解决week英文编码问题
features = pd.get_dummies(features)
print(features.head(1))
# 标签,将Y取出来
labels = np.array(features['actual'])
# 在特征中去掉标签
features = features.drop('actual', axis=1)
# 名字单独保存一下,以备后患
feature_list = list(features.columns)
# 转换成合适的格式
features = np.array(features)
from sklearn import preprocessing
input_features = preprocessing.StandardScaler().fit_transform(features)
'''
使用了sklearn库中的preprocessing模块。这段代码的功能是对一个名为features的数据集进行标准化处理。
标准化处理是一种数据预处理方法,它可以去除数据的均值,使其具有零均值,然后除以数据的标准差,使其具有单位方差。
这样做的目的是让数据符合标准正态分布,从而提高一些机器学习算法的性能。
这段代码的具体步骤是:
• 首先,导入preprocessing模块,它提供了一些常用的数据预处理函数和类
• 然后,创建一个StandardScaler类的实例,它是一个用于标准化数据的转换器。
这里没有指定参数,所以使用默认值,即copy=True, with_mean=True, with_std=True。
• 接着,调用StandardScaler类的fit_transform方法,对features数据集进行拟合和转换。这个方法会先计算features数据集的均值和标准差,
然后使用这些统计量对features数据集进行标准化处理,最后返回一个标准化后的数据集,赋值给input_features变量。
'''
# 简易模型 层数越多,提取的特征越多,就越容易过拟合
input_size = input_features.shape[1] # 输入特征个数,input_features为348*14,input_features.shape[1]=14
hidden_size_1 = 32
hidden_size_2 = 64
hidden_size_3 = 128
hidden_size_4 = 256
hidden_size_5 = 512
output_size = 1
batch_size = 16
'''
神经网络训练中的batch是指每次用于更新模型参数的一组训练数据。batch的大小(batch size)是指每个batch包含的数据样本的数量。
batch的作用主要有以下几点:
• 使用batch可以提高训练速度,因为可以利用并行计算的优势,同时处理多个数据样本。
• 使用batch可以更好地逃离鞍点和局部最优,因为每次更新参数时,损失函数的梯度是由不同的数据样本近似得到的,这样可以增加梯度的随机性和多样性。
• 使用batch可以节省内存或显存,因为不需要一次性加载全部的训练数据,而是分批次加载和处理。
当然,batch的大小也会影响训练的效果,一般来说,batch size越小,训练损失下降得越快,泛化能力越强,但是训练时间越长,收敛速度越慢;
batch size越大,训练损失下降得越慢,泛化能力越弱,但是训练时间越短,收敛速度越快。因此,需要根据具体的任务和数据集来选择合适的batch size。
'''
my_nn = torch.nn.Sequential(
torch.nn.Linear(input_size, hidden_size_1),
torch.nn.Sigmoid(), # 指定激活函数,可以自己决定
torch.nn.Linear(hidden_size_1,hidden_size_2),
torch.nn.ReLU(),
torch.nn.Linear(hidden_size_2,hidden_size_3),
torch.nn.ReLU(),
torch.nn.Linear(hidden_size_3, hidden_size_4),
torch.nn.Sigmoid(),
torch.nn.Linear(hidden_size_4, hidden_size_5),
torch.nn.ReLU(),
torch.nn.Linear(hidden_size_5, output_size),
)
'''
这段代码中,my_nn模型包含三个层:
• 第一个层是torch.nn.Linear类的一个实例,它表示一个全连接层或者密集层。
这个层的功能是对输入(input)进行线性变换,即乘以一个权重矩阵(weight matrix)并加上一个偏置向量(bias vector)。
这个层的参数是input_size和hidden_size,它们分别表示输入的维度(dimension)和输出的维度。
例如,如果input_size是10,hidden_size是20,那么这个层的权重矩阵的形状(shape)是(20, 10),偏置向量的形状是(20,)。
• 第二个层是torch.nn.Sigmoid类的一个实例,它表示一个Sigmoid激活函数。
这个层的功能是对输入(input)进行非线性变换,即将输入映射到0和1之间的一个值。这个层没有参数,它的输入和输出的维度相同。
• 第三个层也是torch.nn.Linear类的一个实例,它表示另一个全连接层(fully-connected layer)。
这个层的功能和第一个层相同,只是参数是hidden_size和output_size,它们分别表示输入的维度和输出的维度。
例如,如果hidden_size是20,output_size是5,那么这个层的权重矩阵的形状是(5, 20),偏置向量的形状是(5,)。
'''
cost = torch.nn.MSELoss(reduction='mean')
'''reduction='mean'是一个可选的参数(argument),它指定了损失函数的输出形式。
reduction参数有三个可选的值:'none','mean'和'sum'。
'none'表示不对损失函数的输出进行任何处理,返回一个与输入形状相同的张量(tensor);
'mean'表示对损失函数的输出求均值,返回一个标量(scalar);
'sum'表示对损失函数的输出求和,返回一个标量(scalar)
'''
optimizer = torch.optim.Adam(my_nn.parameters(), lr = 0.001) # 效率比SGD更高
'''
这段代码的功能是使用torch.optim.Adam类创建一个优化器(optimizer)对象,命名为optimizer。
优化器是一种用于更新模型参数(parameter)的工具,它可以根据损失函数和梯度来调整参数的值,使得模型性能提升。
这段代码中,optimizer对象的优化算法是Adam,它是一种常用的优化算法,它能够自适应地调整每个参数的学习率,从而更加高效地进行模型训练。
这段代码中,my_nn.parameters()是一个返回模型my_nn的所有参数的迭代器(iterator),它是optimizer对象的第一个参数,表示需要优化的参数集合。
my_nn是一个神经网络(neural network)模型,它由多个层(layer)组成,每个层都包含一些参数和激活函数。
这段代码中,lr = 0.001是一个可选的关键字参数(keyword argument),它指定了优化器的全局学习率(learning rate)。
学习率是一个正数,它控制了参数更新的步长(step size),即每次迭代(iteration)参数变化的幅度。
'''
# 训练网络
losses = [] # 定义了一个空列表losses,用于存储每个epoch的平均损失(loss)
for i in range(1000): # 循环次数为1000,表示训练1000个epoch。每个epoch是对整个训练数据集的一次完整的遍历(pass)。
batch_loss = [] # 定义了一个空列表batch_loss,用于存储每个batch的损失(loss)
# MINI-Batch方法来进行训练
for start in range(0, len(input_features), batch_size):
'''
开始了一个内层循环,循环的范围是从0到len(input_features),步长是batch_size。input_features是一个表示训练数据的特征的张量,
len(input_features)表示训练数据的样本数量,batch_size表示每个batch的样本数量。这个循环的作用是将训练数据分成多个batch,每次处理一个batch的数据。
'''
end = start + batch_size if start + batch_size < len(input_features) else len(input_features)
'''
计算了每个batch的结束位置end,它等于开始位置start加上batch_size,但是如果超过了len(input_features),就取len(input_features)作为结束位置。
这是为了防止最后一个batch的样本数量不足batch_size的情况。
'''
xx = torch.tensor(input_features[start:end], dtype=torch.float, requires_grad=True)
'''
创建了一个新的张量(tensor)xx,它是input_features的一个切片(slice),从start到end的位置。
xx的数据类型(dtype)是torch.float,表示32位浮点数,xx的梯度(gradient)需要被计算,所以requires_grad参数设为True。xx表示一个batch的输入(input)。
'''
yy = torch.tensor(labels[start:end], dtype=torch.float, requires_grad=True)
'''
创建了一个新的张量(tensor)yy,它是labels的一个切片(slice),从start到end的位置。
labels是一个表示训练数据的标签(label)或目标(target)的张量(tensor),yy的数据类型(dtype)和梯度(gradient)的设置与xx相同。
yy表示一个batch的输出(output)。
'''
prediction = my_nn(xx)
'''
调用了模型my_nn的__call__方法,对xx进行预测(prediction),得到一个新的张量(tensor)prediction,
它表示模型对一个batch的输入(input)的预测值(prediction value)。
'''
loss = cost(prediction, yy)
'''
调用了损失函数(loss function)对象cost的__call__方法,对prediction和yy进行计算,得到一个标量(scalar)loss,
它表示模型对一个batch的输出(output)的损失值(loss value)。
'''
optimizer.zero_grad() # 清零、反向传播、更新
'''
调用了优化器(optimizer)对象optimizer的zero_grad方法,将模型参数(parameter)的梯度(gradient)清零,为下一次更新做准备。
'''
loss.backward(retain_graph=True)
'''
调用了loss的backward方法,对损失函数进行反向传播,计算模型参数(parameter)的梯度(gradient)。
retain_graph参数设为True,表示保留计算图(computational graph),以便下一次使用。
'''
optimizer.step()
'''
调用了优化器(optimizer)对象optimizer的step方法,根据模型参数(parameter)的梯度(gradient)更新参数的值。
'''
batch_loss.append(loss.data.numpy())
'''
将loss的数值(data)转换成NumPy数组(array),并添加到batch_loss列表中,用于记录每个batch的损失值(loss value)。
'''
# 打印损失
if i % 100 == 0:
losses.append(np.mean(batch_loss)) # 将batch_loss列表中的元素求均值(mean),并添加到losses列表中,用于记录每个epoch的平均损失(loss)。
print(i, np.mean(batch_loss)) # 打印出当前的epoch数和平均损失(loss)。
# 训练完模型后,做出预测
x = torch.tensor(input_features, dtype = torch.float)
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})
'''
这段代码的功能是使用pd.DataFrame函数创建一个数据框(dataframe)对象,命名为predictions_data。
数据框(dataframe)是一种用于存储和处理表格数据的数据结构,它由行(row)和列(column)组成,类似于Excel表格或数据库表。
这段代码中,pd.DataFrame函数的参数是一个字典(dictionary),它表示数据框(dataframe)的数据源。
这段代码中,字典(dictionary)的键(key)是'date'和'prediction',它们表示数据框(dataframe)的列名(column name)。
字典(dictionary)的值(value)是test_dates和predict.reshape(-1),它们表示数据框(dataframe)的列值(column value)。
这段代码中,test_dates是一个表示测试数据的日期的张量(tensor),predict是一个表示模型预测值(prediction value)的张量(tensor),
predict.reshape(-1)是一个对predict进行重塑(reshape)的操作,它将predict变成一个一维(1D)的张量(tensor)。
reshape方法的参数-1表示自动推断张量(tensor)的形状(shape),使得张量(tensor)的元素个数不变
'''
# 同理,再创建一个来存日期和其对应的模型预测值
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')
plt.xticks(rotation=45);
plt.legend()
# 图名
plt.xlabel('Date'); plt.ylabel('Maximum Temperature (F)'); plt.title('Actual and Predicted Values');
plt.show()
训练次数:
预测结果如下: