1.训练数据的准备
登录Kaggle平台,搜索house price,选择Datasets数据集标签,选择House price prediction这份数据下载下来。
这份数据中,删除与房价预测无关和过于稀疏的列,(包括data、waterfront、view、street、country),最后会保留12个标签和一个price标签。
数据处理
python
import pandas as pd # 用于处理表格
# 读取数据文件,得到data对象
data = pd.read_csv('E:/LearningBio/archive/data.csv')
# 使用drop函数,输出data、waterfront、view、street、country这五列
data = data.drop(columns=['date', 'waterfront', 'view', 'street', 'country'])
# 因为city和statazip这两列是tag特征
# 所以需要使用cat.codes,将他们转为整数形式
data['city'] = data['city'].astype('category').cat.codes
data['statezip'] = data['statezip'].astype('category').cat.codes
# 获取除了price剩下的12列的特征
features = data.columns.difference(['price'])
# 对所有特征进行标准化处理
data[features] = (data[features] - data[features].mean()) / data[features].std()
# 将房价price缩小10000倍,使用万作为价格单元
data['price'] = data['price'] / 10000
++部分解释:++
1.在 Pandas 中,
cat.codes
用于将分类数据(categorical data)转换为整数编码2.在 Python 的 Pandas 库中,
mean()
函数用于计算均值。data[features].mean()
:计算 3.features
列中每一列的均值。结果是一个包含各列均值的Series
,每列的均值会用于该列数据的标准化。
4.data[features].std()
:计算features
列中每一列的标准差,得到一个包含各列标准差的Series
。
5
.(data[features] - data[features].mean()) / data[features].std()
:将中心化的每列数据除以对应列的标准差,使每列数据的标准差为1。6.特征缩放使用均值标准化:
拆分数据
python
from sklearn.model_selection import train_test_split
# 使用train_test_split函数
# 将数据data拆分成训练数据train_data和test_data
train_data, test_data = train_test_split(data, test_size=0.15, random_state=42)
# 使用to_excel将两份数据保存到文件中
train_data.to_excel('E:/LearningBio/archive/train.xlsx', index=False)
test_data.to_excel('E:/LearningBio/archive/text.xlsx', index=False)
2.多元线性回归模型的设计
设计一个多元线性回归模型,用于房价预测,包括12个特征。
线性层的大小由输入数据的个数和输出数据个数所决定。
模型设计
python
import torch
from torch import nn
# 定义模型类LinearRegression,他继承了Pytorch的nn.Module类
# nn.Module是所有模型的基类,它包括模型的基本功能
class LinearRegression(nn.Module):
# init函数用于初始化模型的结构参数
def __init__(self):
super().__init__()
# 对于房价预测这个问题,有12个输入特征和一个输出结果
self.layer = nn.Linear(12, 1)
# forward函数用于定义模型前向传播的计算逻辑
def forward(self, x):
# 输入的特征向量是x,将x传入至layer进行计算
# 这个过程相当于计算线性回归的方程h(x)
return self.layer(x)
测试代码
python
if __name__ == '__main__':
model = LinearRegression() # 创建模型
print(model) # 打印model,可以看到模型的结构
print("")
# 使用循环,遍历模型中的参数
for name, param in model.named_parameters():
# 打印参数名称和初始值
# 他们就是线性回归模型中12个w参数,和一个b参数
print(f"{name} : {param.data}")
# 定义一个100*12大小的张量
# 代表100个数据,每个数据有12个特征值
x = torch.zeros(100, 12)
h = model(x) # 将x输入值模型model,得到预测结果h
print(f"x:{x.shape}")
print(f"h:{h.shape}")
运行结果
python
LinearRegression(
(layer): Linear(in_features=12, out_features=1, bias=True)
)
layer.weight : tensor([[ 0.0191, 0.1262, -0.0705, 0.0321, 0.1766,
-0.1595, 0.1702, 0.0083, 0.1219, 0.2356, -0.1838,
0.0656]])
layer.bias : tensor([0.2869])
x:torch.Size([100, 12])
h:torch.Size([100, 1])
++部分解释:++
1
.nn
是 PyTorch 中专门用于构建和定义神经网络的模块,其中包含各种神经网络层、激活函数、损失函数等工具,帮助用户方便地创建深度学习模型。2.在 PyTorch 中,
named_parameters()
方法用于获取模型中所有参数的名称和值。模型的初始参数(权重和偏置)是在定义模型时自动初始化的3
.forward
是 PyTorch 中定义神经网络模型时的一个关键方法,用于定义模型的前向传播过程。它规定了输入数据如何经过各层得到最终输出。前向传播是指数据从输入层经过各神经网络层到输出层的传递过程。
forward
方法的用法定义模型结构 :在定义神经网络模型时,需要继承
nn.Module
类,并重写forward
方法。
输入参数 :
forward
方法通常接收一个输入张量x
。输出 :
forward
方法返回网络的输出结果。
3.模型的训练和测试
训练代码
对训练集中的样本,分别转化为两组张量
python
# 模型训练代码
import pandas as pd
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import r2_score
if __name__ == '__main__':
# 使用read.excel,读取训练数据train.xlsx
df = pd.read_excel("E:/LearningBio/archive/train.xlsx")
# 获取训练数据的特征
features_names = [col for col in df.columns if col not in ['price']]
# 打印特征的数量
print(f'Features num: {len(features_names)}')
# 将输入特征,转换为张量x
x = torch.Tensor(df[features_names].values)
# 训练标签,转换为张量y
y = torch.Tensor(df['price'].values).unsqueeze(1)
# 打印训练数据的张量
print(f'Training samples: {len(x)}')
++运行结果++
Features num: 12
Training samples: 3910
++部分解释:++
df.columns
:获取 DataFramedf
的所有列名,返回一个包含所有列名的索引对象。列表推导式 :
[col for col in df.columns if col not in ['price']]
是一种Python语法,用于创建一个新列表。它会遍历df.columns
中的每一个列名col
。条件判断 :
if col not in ['price']
过滤条件,用于排除price
列。也就是说,只有当col
不在['price']
中时,它才会被包含在新列表中。在 PyTorch 中,
unsqueeze(1)
是用于增加张量维度的方法。具体来说,unsqueeze
方法会在指定的位置插入一个维度。这里将一维张量转换为二维张量,方便在进行计算时与其他二维张量(如特征矩阵)进行操作,比如用于线性回归模型的输入。
创建对象
训练模型时需要创建对象,包括这三个必须的步骤:
1.模型本身
2.优化器优化参数
3.损失函数
python
# 在使用Pytorch训练模型时,需要创建三个对象
# 第一个是模型本身model,他就是我们设计的线性回归模型
model = LinearRegression()
# 第二个是优化器optimizer,它用来优化模型中的参数
# 最常使用的时Adam优化器
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
# 第三个是损失函数criterion,对于回归问题,使用MSELoss,均方误差
criterion = nn.MSELoss()
批量梯度下降
使用批量梯度下降算法,循环迭代得到训练的参数12个w参数和1个b参数,使模型收敛,循环包括以下五个步骤,这5个步骤是pytorch框架训练模型的定式:
1.计算模型预测值
2.计算预测值和样本y之间的损失
3.使用backward计算梯度
4.使用optimizer.step更新参数
5.将梯度清零
python
# 进入模型的迭代循环,使用的是批量梯度下降算法
# 每次迭代,都会基于全部样本计算损失值,执行梯度下降
# 这里循环的轮数为2万,可以是模型达到收敛
for epoch in range(20000):
# 在循环中,包括5个步骤
h = model(x) # 1.计算模型的预测值
loss = criterion(h, y) # 2.计算预测值和标签y之间的损失loss
loss.backward() # 3.使用backward计算梯度
optimizer.step() # 4.使用optimizer.step更新参数
optimizer.zero_grad() # 5.将梯度清空
# 这5步是使用pytorch框架训练模型的定式
# 每迭代1000次打印一次模型的损失,用于观察训练过程
if (epoch + 1) % 1000 == 0:
# 打印迭代轮数和损失
print(f'After{epoch + 1} iterations, Train Loss: {loss.item():.3f}')
h_np = h.detach().numpy()
y_np = y.detach().numpy()
# 打印MSE、MAE和R2这三个回归指标
mse = mean_squared_error(y_np, h_np)
mae = mean_absolute_error(y_np, h_np)
r2 = r2_score(y_np, h_np)
print(f'\tMean squared error: {mse:.3f}')
print(f'\tMean absolute error: {mae:.3f}')
print(f'\tR2 score: {r2:.3f}')
# 打印模型训练出的参数
print(model.state_dict())
# 将模型参数保存到文件lr.pth中
# model..pth就是我们最终训练得到的模型
torch.save(model.state_dict(), 'E:/LearningBio/archive/model.pth')
++部分解释:++
- h_np = h.detach().numpy()
和
y_np = y.detach().numpy()
这两行代码将模型的输出h
和真实标签y
转换为 NumPy 数组,方便后续处理或可视化。- MSE:均方误差是预测值与真实值之间差的平方的平均值。它可以反映模型预测的准确性,越小越好。
- MAE:平均绝对误差是预测值与真实值之间差的绝对值的平均值,表示预测值的偏差程度。(一元线性回归中有提及)
- 分数:也称为决定系数,衡量模型解释的方差比例。值域在0到1之间,越接近1表示模型对数据的解释能力越强。为负值时,表示模型的表现比简单的平均值还要差。
其中 :是第i个样本的真实值,是第i个样本的预测值 , 是所有样本真实值的均值。
分子:表示真实值与预测值之间的平方差,反映模型的误差。
分母:表示真实值与均值之间的平方差,反映真实数据的整体变异性。
model.state_dict()
是 PyTorch 中用于获取模型参数和缓冲区的一个方法。它返回一个包含模型所有可学习参数(如权重和偏置)以及一些其他状态信息(如 BatchNorm 的均值和方差)的字典。 返回的字典中,键是参数的名称(通常是层的名称),值是对应的参数张量。
++运行结果++
python
After1000 iterations, Train Loss: 4564.342
Mean squared error: 4564.342
Mean absolute error: 46.080
R2 score: -0.457
After2000 iterations, Train Loss: 3783.479
Mean squared error: 3783.479
Mean absolute error: 37.779
R2 score: -0.207
......
After20000 iterations, Train Loss: 2447.281
Mean squared error: 2447.281
Mean absolute error: 16.772
R2 score: 0.219
OrderedDict([('layer.weight', tensor([[-6.1492, 3.9196, 12.1156, -2.1037, 2.6352, 2.6877, 13.4887, 7.3559,
-7.3652, 0.8103, 3.4043, -2.8637]])), ('layer.bias', tensor([54.9326]))])
测试代码
与训练代码差不多,包括测试集的读取,定义回归模型、将测试集中的特征向量x输入到model模型中,得到结果,打印回归指标。
python
# 对模型进行测试
if __name__ == '__main__':
# 测试的流程和训练差不多
# 首先读取测试集test.xlsx
df = pd.read_excel("E:/LearningBio/archive/text.xlsx")
features_names = [col for col in df.columns if col not in ['price']]
x = torch.Tensor(df[features_names].values)
y = torch.Tensor(df['price'].values).unsqueeze(1)
# 包括了690个样本
print(f"Testing samples: {len(x)}")
#定义线性回归模型
model=LinearRegression()
#加载刚刚训练好的模型文件model.path
model.load_state_dict(torch.load('E:/LearningBio/archive/model.pth'))
#将特征向量x输入到model中,得到预测结果h
h=model(x)
h_np=h.detach().numpy()
y_np = y.detach().numpy()
#计算h和y之间的MSE、MAE和R2
mse = mean_squared_error(y_np, h_np)
mae = mean_absolute_error(y_np, h_np)
r2 = r2_score(y_np, h_np)
print(f'\tMean squared error: {mse:.3f}')
print(f'\tMean absolute error: {mae:.3f}')
print(f'\tR2 score: {r2:.3f}')
由测试集指标和训练集指标可以看出,两个集合中的三个指标相差不多,模型符合预期。
python
Testing samples: 690
Mean squared error: 2847.840
Mean absolute error: 18.482
R2 score: 0.170