目录
引言
在本次实验中,利用PyTorch框架和线性回归模型对波士顿房价进行预测。通过数据预处理、模型构建、训练、测试和预测,提升了房价预测的准确性,深入理解了PyTorch在深度学习中的应用。
步骤:
数据预处理
在机器学习和深度学习中,数据预处理是一个至关重要的步骤。良好的数据预处理能够显著提高模型的性能和预测能力。数据预处理的目标是清洗、规范化和准备数据,以便更好地用于模型训练和测试。
异常值处理
数据预处理的首要步骤是识别并处理异常值。使用箱线图来直观地展示数据的分布情况。通过观察箱线图,发现数据中存在多个异常值。
为了处理这些异常值,采用了四分位数法。首先计算每个特征的第一四分位数(Q1)和第三四分位数(Q3),然后计算四分位间距(IQR)。异常值定义为小于 Q1 - 1.5 * IQR 或大于 Q3 + 1.5 * IQR 的值。使用临界值来替代这些异常值,从而减少它们对模型性能的负面影响。
# 读取数据
data = pd.read_csv("boston_house_prices.csv")
columns = data.columns
num_columns = len(columns)
# 画箱线图的函数
def boxplot(data):
# 创建3行5列的子图布局
fig, axs = plt.subplots(nrows=(num_columns // 3) + 1, ncols=3, figsize=(20, 15))
# 绘制每一列的箱线图
for i, col in enumerate(columns):
row = i // 3
col_num = i % 3
axs[row, col_num].boxplot(data[col])
axs[row, col_num].set_title(col)
axs[row, col_num].set_ylabel('Values')
axs[row, col_num].grid(True)
# 调整布局,防止子图重叠
plt.tight_layout()
plt.show()
boxplot(data)
# 利用四分位数识别异常值
num_features = data.select_dtypes(exclude=['object', 'bool']).columns.tolist()
for feature in num_features:
if feature == 'CHAS':
continue
Q1 = data[feature].quantile(q=0.25)
Q3 = data[feature].quantile(q=0.75)
# 利用临界值替代异常值
IQR = Q3 - Q1
top = Q3 + 1.5 * IQR
bot = Q1 - 1.5 * IQR
values = data[feature].values
values[values > top] = top
values[values < bot] = bot
data[feature] = values.astype(data[feature].dtype)
boxplot(data)
数据集划分
数据集被划分为训练集和测试集,比例为80%和20%。这一步骤通过train_test_split
函数实现,确保了模型能够在未见过的数据上进行有效的泛化。
# 划分数据集
X = data.drop('MEDV', axis=1) # 特征
y = data['MEDV'] # 目标变量
# 划分训练集和测试集,比例为80%和20%
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练集构建
train_dataset = (X_train, y_train)
# 测试集构建
test_dataset = (X_test, y_test)
特征工程
为了消除不同特征之间的量纲影响,对特征进行了归一化处理。使用MinMaxScaler
将数据缩放到[0, 1]区间内,使得不同特征之间具有可比性。这一步骤对于提高模型的收敛速度和预测准确性至关重要。
# 特征归一化
# 创建 MinMaxScaler 对象
scaler = MinMaxScaler()
# 对特征进行归一化
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
模型构建
# 定义线性回归模型
class LinearRegressionModel(nn.Module):
def __init__(self, input_size):
super(LinearRegressionModel, self).__init__()
# 线性层,输入特征数量为输入的特征数,输出为1
self.linear = nn.Linear(input_size, 1)
def forward(self, x):
return self.linear(x)
# 将数据转化为 PyTorch 的 Tensor
X_train_tensor = torch.tensor(X_train_scaled, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train.values, dtype=torch.float32).view(-1, 1)
# 定义模型
input_size = X_train_tensor.shape[1]
model = LinearRegressionModel(input_size)
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
模型训练
# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
model.train()
# 前向传播
outputs = model(X_train_tensor)
loss = criterion(outputs, y_train_tensor)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 打印损失
if (epoch+1) % 100 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
# 打印训练得到的权重和偏置
print("权重 (w):", model.linear.weight.data)
print("偏置 (b):", model.linear.bias.data)
模型测试
# 转换测试集数据为 Tensor
X_test_tensor = torch.tensor(X_test_scaled, dtype=torch.float32)
y_test_tensor = torch.tensor(y_test.values, dtype=torch.float32).view(-1, 1)
# 测试模型
model.eval() # 将模型设置为评估模式
with torch.no_grad():
y_pred = model(X_test_tensor)
test_loss = criterion(y_pred, y_test_tensor)
predictions = model(X_test_tensor).numpy() # 转换为 numpy 数组
y_test_numpy = y_test_tensor.numpy()
mse = mean_squared_error(y_test_numpy, predictions)
print(f'测试集上均方误差: {mse:.4f}')
print(f'损失: {test_loss.item():.4f}')
模型预测
# 使用训练好的模型进行预测
with torch.no_grad():
predictions = model(X_test_tensor)
predictions = predictions.numpy()
# 打印前10个预测结果
print(f"预测结果: {predictions[:10].flatten()}")
print(f"真实值: {y_test.values[:10]}")
完整运行结果:
附完整代码:
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
import torch
import torch.nn as nn
import torch.optim as optim
# 读取数据
data = pd.read_csv("boston_house_prices.csv")
columns = data.columns
num_columns = len(columns)
# 画箱线图的函数
def boxplot(data):
# 创建3行5列的子图布局
fig, axs = plt.subplots(nrows=(num_columns // 3) + 1, ncols=3, figsize=(20, 15))
# 绘制每一列的箱线图
for i, col in enumerate(columns):
row = i // 3
col_num = i % 3
axs[row, col_num].boxplot(data[col])
axs[row, col_num].set_title(col)
axs[row, col_num].set_ylabel('Values')
axs[row, col_num].grid(True)
# 调整布局,防止子图重叠
plt.tight_layout()
plt.show()
boxplot(data)
# 利用四分位数识别异常值
num_features = data.select_dtypes(exclude=['object', 'bool']).columns.tolist()
for feature in num_features:
if feature == 'CHAS':
continue
Q1 = data[feature].quantile(q=0.25)
Q3 = data[feature].quantile(q=0.75)
# 利用临界值替代异常值
IQR = Q3 - Q1
top = Q3 + 1.5 * IQR
bot = Q1 - 1.5 * IQR
values = data[feature].values
values[values > top] = top
values[values < bot] = bot
data[feature] = values.astype(data[feature].dtype)
boxplot(data)
# 划分数据集
X = data.drop('MEDV', axis=1) # 特征
y = data['MEDV'] # 目标变量
# 划分训练集和测试集,比例为80%和20%
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练集构建
train_dataset = (X_train, y_train)
# 测试集构建
test_dataset = (X_test, y_test)
# 特征归一化
# 创建 MinMaxScaler 对象
scaler = MinMaxScaler()
# 对特征进行归一化
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 定义线性回归模型
class LinearRegressionModel(nn.Module):
def __init__(self, input_size):
super(LinearRegressionModel, self).__init__()
# 线性层,输入特征数量为输入的特征数,输出为1
self.linear = nn.Linear(input_size, 1)
def forward(self, x):
return self.linear(x)
# 将数据转化为 PyTorch 的 Tensor
X_train_tensor = torch.tensor(X_train_scaled, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train.values, dtype=torch.float32).view(-1, 1)
# 定义模型
input_size = X_train_tensor.shape[1]
model = LinearRegressionModel(input_size)
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
model.train()
# 前向传播
outputs = model(X_train_tensor)
loss = criterion(outputs, y_train_tensor)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 打印损失
if (epoch+1) % 100 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
# 打印训练得到的权重和偏置
print("权重 (w):", model.linear.weight.data)
print("偏置 (b):", model.linear.bias.data)
# 转换测试集数据为 Tensor
X_test_tensor = torch.tensor(X_test_scaled, dtype=torch.float32)
y_test_tensor = torch.tensor(y_test.values, dtype=torch.float32).view(-1, 1)
# 测试模型
model.eval() # 将模型设置为评估模式
with torch.no_grad():
y_pred = model(X_test_tensor)
test_loss = criterion(y_pred, y_test_tensor)
predictions = model(X_test_tensor).numpy() # 转换为 numpy 数组
y_test_numpy = y_test_tensor.numpy()
mse = mean_squared_error(y_test_numpy, predictions)
print(f'测试集上均方误差: {mse:.4f}')
print(f'损失: {test_loss.item():.4f}')
# 使用训练好的模型进行预测
with torch.no_grad():
predictions = model(X_test_tensor)
predictions = predictions.numpy()
# 打印前10个预测结果
print(f"预测结果: {predictions[:10].flatten()}")
print(f"真实值: {y_test.values[:10]}")
第一次写博客感觉写的不是很好,希望uu们可以提一些建议(˃ ⌑ ˂ഃ )