第一步 数据加载与观察
①导包
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
②加载数据
features = pd.read_csv("temps.csv")#观察数据
features.head()
③整合日期,统一格式
import datetimeyears = features["year"]
months = features["month"]
days = features["day"]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]
④绘图(主要用于观察数据走向)
# 绘图
plt.style.use("fivethirtyeight")
plt.rcParams['font.sans-serif'] = ['SimHei']# 设置布局
fig,((ax1,ax2),(ax3,ax4)) = plt.subplots(nrows=2,ncols=2,figsize=(10,10))
fig.autofmt_xdate(rotation=45)# 标签值
ax1.plot(dates,features["actual"])
ax1.set_xlabel("")
ax1.set_ylabel("Temperature")
ax1.set_title("当天真实最大温度")ax2.plot(dates,features["temp_1"])
ax2.set_xlabel("")
ax2.set_ylabel("Temperature")
ax2.set_title("昨日最大温度")ax3.plot(dates,features["temp_2"])
ax3.set_xlabel("Date")
ax3.set_ylabel("Temperature")
ax3.set_title("前日最大温度")ax4.plot(dates,features["friend"])
ax4.set_xlabel("Date")
ax4.set_ylabel("Temperature")
ax4.set_title("朋友预测最大温度")plt.tight_layout(pad=2)
注1:值得一提的是,如果日期没有转换为datetime类型,而是简单的字符串,在绘图的时候是无法正确显示的
即缺失本句:
dates = [datetime.datetime.strptime(date,"%Y-%m-%d") for date in dates]
注2:
除了 `plot()` 方法,matplotlib 的 Axes 对象还提供了多种其他方法来创建不同类型的图表。以下是一些常见的方法:
1. **scatter(x, y, [s], [c])**: 创建散点图。`x` 和 `y` 分别是数据点的横坐标和纵坐标,`s` 是可选参数,用于指定点的大小,`c` 也是可选参数,用于指定点的颜色。
2. **bar(x, height)** 或 **barh(y, width)**: 创建条形图。`bar()` 创建垂直条形图,而 `barh()` 创建水平条形图。
3. **hist(x, bins)**: 创建直方图。`x` 是一个连续型变量的数据集,`bins` 参数指定了直方图中的柱数或区间范围。
4. **step(x, y)**: 创建阶梯图。与线图类似,但是值之间的连接是水平和垂直线段构成的台阶状。
5. **fill_between(x, y1, [y2])**: 在两条曲线之间填充颜色。`y1` 和 `y2` 分别定义了上下边界,默认情况下 `y2=0`。
6. **stackplot(x, y)**: 创建堆叠区域图。
7. **errorbar(x, y, [yerr], [xerr])**: 创建带误差棒的线图。`yerr` 和 `xerr` 分别指定了每个点在y轴和x轴方向上的误差范围。
8. **stem(x, y)**: 创建茎叶图,显示离散序列相对于x的位置。
9. **pie(sizes, [labels])**: 创建饼图。`sizes` 指定各部分的大小,`labels` 是可选参数,用来标记饼图中的各个扇区。
10. **imshow(X)**: 显示图像数据。`X` 是一个二维数组,表示图像的像素值。
11. **contour([X, Y,] Z)** 或 **contourf([X, Y,] Z)**: 创建等高线图或填充的等高线图。`Z` 是一个二维数组,表示高度值;`X` 和 `Y` 可选,提供坐标的网格。
这些只是 matplotlib 提供的一部分绘图方法,每种方法都有自己的参数选项,可以进一步定制图表的外观。对于更复杂或特定领域的图表,还可以使用 seaborn、plotly 等高级绘图库,它们基于 matplotlib 并扩展了其功能。
第二步 预处理
①独热编码
features = pd.get_dummies(features)
features.head()
注1:
pd.get_dummies(features)
是 Pandas 库中的一个函数,用于将分类变量(categorical variable)转换为哑变量(dummy variables),也称为 one-hot 编码。这样做是为了让机器学习算法能够处理非数值型数据,因为大多数机器学习算法需要输入的数据是数值形式的。
这行代码会创建一个新的 DataFrame features
,其中原来的分类变量被替换为多个二进制(0 或 1)的列,每个新列代表原始分类变量的一个类别。如果一个样本属于某个类别,则对应的新列为 1;否则为 0。
例如,如果你有一个特征 "color" 包含三个类别:"Red", "Green", 和 "Blue",那么调用 pd.get_dummies()
后会生成三列:color_Red
, color_Green
, 和 color_Blue
,并且每个样本在这三列中只会有一个值为 1,其余为 0。
②处理数据和预测值
labels = np.array(features["actual"])features = features.drop("actual",axis=1)feature_list = list(features.columns)features = np.array(features)
注1:features = np.array(features)
本句将features从Pandas DataFrame的形式转换为Numpy数组,以便后续操作
③标准化数据
from sklearn import preprocessing
input_features = preprocessing.StandardScaler().fit_transform(features)
注1:
-
preprocessing.StandardScaler()
创建了一个StandardScaler
的实例。StandardScaler
是一个类,它实现了对数据进行标准化的功能。 -
.fit_transform(features)
方法执行了两个操作:-
fit: 计算训练数据的均值和标准差。这些统计信息将被用来标准化数据。
-
transform: 使用计算出的均值和标准差来标准化数据,即将每个特征减去其均值并除以其标准差,得到新的特征值。
-
第三步 构建神经网络模型
x = torch.tensor(input_features,dtype=float)
y = torch.tensor(labels,dtype=float)# 权重参数初始化
weights1 = torch.randn((14,128),dtype=float,requires_grad = True)
biases1 = 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)learning_rate=0.001
losses=[]for i in range(1000):# 计算隐藏层hidden = x.mm(weights1)+biases1# 加入激活函数hidden = torch.relu(hidden)# 预测结果predictions = hidden.mm(weights2)+biases2# 计算损失loss = torch.mean((predictions - y)**2)losses.append(loss.data.numpy())if i % 100 ==0:print("loss:",loss)# 反向传播计算loss.backward()# 更新参数weights1.data.add_(-learning_rate * weights1.grad.data)biases1.data.add_(-learning_rate * biases1.grad.data)weights2.data.add_(-learning_rate * weights2.grad.data)biases2.data.add_(-learning_rate * biases2.grad.data)# 每次迭代完清空weights1.grad.data.zero_()biases1.grad.data.zero_()weights2.grad.data.zero_()biases2.grad.data.zero_()
第四步 优化构建神经网络模型的方法
①构建模型
input_size = input_features.shape[1]
hidden_size = 128
output_size = 1
batch_size = 16my_nn = 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)
这段代码创建了一个简单的两层神经网络,定义了损失函数为均方误差,并选择了 Adam 作为优化器。Sequential
模块简化了模型构建的过程,使得代码更加简洁易读。此外,通过设置批量大小、隐藏层大小、输出大小等超参数,你可以灵活地调整模型以适应不同的任务需求。
要完成这个模型的训练过程,还需要编写一个训练循环,在其中进行前向传播、计算损失、反向传播以及参数更新。如果你想要进一步提升模型性能或复杂度,还可以考虑添加更多层、选择不同的激活函数、调整优化器及其参数等。
②训练模型
# 训练网络
losses = []
for i in range(1000):batch_loss = []#MINI-Batch方法来进行训练for start in range(0,len(input_features),batch_size):end = start+batch_size if start+batch_size<len(input_features) else len(input_features)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 =a my_nn(xx)loss = cost(prediction,yy)optimizer.zero_grad()loss.backward(retain_graph=True)optimizer.step()batch_loss.append(loss.data.numpy())if i%100==0:losses.append(np.mean(batch_loss))print(i,np.mean(batch_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})# 创建表格来村日期和其对应的模拟预测值
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)})
注1:
-
features
是一个二维数组或类似结构(如 NumPy 数组),其中每一行代表一个样本,每一列代表一个特征。 -
:
表示选取所有行。 -
feature_list.index("month")
返回的是要选择的列的索引。 -
因此,
features[:, feature_list.index("month")]
将选取features
中对应于"month"
列的所有元素,形成一个新的一维数组,这个数组包含了所有样本的月份信息。
注2:
predict.reshape(-1)
的具体含义如下:
-
reshape()
方法:这是 NumPy 数组的一个方法,用于改变数组的形状而不改变其数据。 -
-1
参数:当你传递-1
作为参数时,NumPy 会自动计算该维度的大小,以确保新数组的总元素数量保持不变。换句话说,它会根据其他维度的大小来推断出合适的长度。例如,如果你有一个形状为(n, 1)
的二维数组,并调用.reshape(-1)
,结果将是一个形状为(n,)
的一维数组。
在你的例子中,假设 predict
是一个形状为 (n, 1)
的二维数组,那么 predict.reshape(-1)
会将其转换为一个形状为 (n,)
的一维数组。这样做是为了确保 predictions_data
中的 prediction
列是一维的,从而与 date
列匹配,并且使得每个日期对应一个预测值。
③绘图
# 真实值
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")
plt.title("Actual and Predicted Values")
注1:
plt.legend()
:在图表中添加一个图例,显示之前定义的标签(如 "actual"
和 "prediction"
),以便区分不同系列的数据。
注2:
"b-"
:指定线条样式为蓝色实线(b
表示蓝色,-
表示实线)。
"ro"
:指定标记样式为红色圆点(r
表示红色,o
表示圆形标记)。
至此,构建神经网络模型实现气温预测已完成。