Python----深度学习(基于DNN的PM2.5预测)

一、目标

如何使用 PyTorch 实现一个简单的深度神经网络(DNN)模型,并用于回归任务。该模型通过训练数据集来预测PM2.5。代码通过读取数据集、数据处理、模型训练和模型评估等步骤,详细展示了整个实现过程。

二、数据集介绍

Data 含有 18 项观测数据 AMB_TEMP(环境温度), CH4(甲烷), CO(一氧化碳), NMHC(非甲烷总烃), NO(一氧化氮), NO2(二氧化氮), NOx(氮氧化物), O3(臭氧), PM10, PM2.5, RAINFALL(降雨量), RH(相对湿度), SO2(二氧化硫), THC(总碳氢化合物), WD_HR(小时平均风向), WIND_DIREC(风向), WIND_SPEED(风速), WS_HR(小时平均风速)。纵向为日期从2014/1/1到2014/12/20,其中每月记录20天,横向为每日24小时每一小时的记录。

三、设计思路

3.1、准备工作

导入模块包

python 复制代码
import pandas as pd
import numpy as np
import random
import os
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler
from torch.utils.data import TensorDataset, DataLoader

设置随机种子保证结果的可重复性

python 复制代码
def setup_seed(seed):
    # 设置 Numpy 随机数种子,确保Numpy生成的随机数序列一致
    np.random.seed(seed)

    # 设置Python内置随机数种子,保证Python内置的随机函数生成的随机数一致
    random.seed(seed)

    # 设置Python哈希种子,避免不同运行环境下哈希结果不同,影响随机数生成
    os.environ['PYTHONHASHSEED'] = str(seed)

    # 设置PyTorch 随机种子,使PyTorch生成的随机数序列可以重复
    torch.manual_seed(seed)

    # 检查是否有可用的CUDA设备(GPU)
    if torch.cuda.is_available():
        # 设置 CUDA 随机种子,保证在GPU上的随即操作可重复
        torch.cuda.manual_seed(seed)
        # 为所有 GPU 设置随机种子
        torch.cuda.manual_seed_all(seed)
        # 关闭 cudnn 自动寻找最优算法加速的功能,保证结果可重复
        torch.backends.cudnn.benchmark = False
        # 设置 cudnn 为确定性算法,确保每次运行结果一致
        torch.backends.cudnn.deterministic = True

检测是否使用cuda

python 复制代码
if torch.cuda.is_available():
    device = 'cuda'
    print('CUDA is useful!!')
else:
    device = 'cpu'
    print('CUDA is not useful!!')

设置 pandas 显示选项

python 复制代码
# 最多显示1000列
pd.set_option('display.max_columns', 1000)
# 显示宽度为1000
pd.set_option('display.width', 1000)
# 每列最多显示1000个字符
pd.set_option('display.max_colwidth', 1000)

3.2、数据操作

读取数据

python 复制代码
train_data = pd.read_csv('train.csv', encoding='big5')

选取特征数据

python 复制代码
train_data = train_data.iloc[:, 3:]

将数组中值为NR的元素替换为0

python 复制代码
train_data[train_data == 'NR'] = 0

查看缺失情况

python 复制代码
print(train_data.isnull().sum())

对数据进行维度变换和重塑,转为DataFrame格式

python 复制代码
datas = []

# 按照 步长为18 分割数据
for i in range(0, 4320, 18):
    datas.append(numpy_data[i:i+18, :])

# 将datas 转换为Numpy数组
datas_array = np.array(datas, dtype=float)

# 对数据进行维度变换和重塑,转为DataFrame格式
train_data = pd.DataFrame(datas_array.transpose(1, 0, 2).reshape(18, -1).T)

查看相关性

python 复制代码
corr=train_data.corr()
sns.heatmap(corr,annot=True)
plt.show()

从相关性矩阵里筛选大于0.2的特征

python 复制代码
important_features = []
for i in range(len(corr.columns)):
    if abs(corr.iloc[i, 9]) > 0.2:
        important_features.append(corr.columns[i])

划分特征和目标

python 复制代码
X = train_data[important_features].drop(9, axis=1)
# 选取第9列作为目标
y = train_data[9]

划分训练集和测试集

python 复制代码
# 划分训练集和测试集
train_ratio = 0.8

# 训练集特征
X_train = X[:int(train_ratio * len(train_data))]
# 测试集特征
X_test = X[int(train_ratio * len(train_data)):]
# 训练集标签
y_train = y[:int(train_ratio * len(train_data))]
# 测试集标签
y_test = y[int(train_ratio * len(train_data)):]

3.3、标准化

python 复制代码
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

3.4、将数据转换为PyTorch的张量

python 复制代码
# 训练集的特征张量表示
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)
# 测试集的特征张量表示
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)

3.5、使用DataLoader去加载数据集

python 复制代码
# 创建TensorDataset对象,将训练集特征张量与标签一一组合在一起
train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
# 创建DataLoader对象,用于批量加载数据
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)

3.6、定义模型

python 复制代码
class DNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        # 调用父类的构造函数
        super(DNN, self).__init__()
        # 定义第一个Linear层,输入就是input_size,输出维度就是 hidden_size
        self.fc1 = nn.Linear(input_size, hidden_size)
        # 定义第二个Linear层,输入是hidden_size,输出维度是 hidden_size
        self.fc2 = nn.Linear(hidden_size, hidden_size)
        # 定义第三个Linear层,输入是hidden_size,输出维度是 hidden_size
        self.fc3 = nn.Linear(hidden_size, hidden_size)
        # 定义第四个Linear层,输入是hidden_size,输出维度是 output_size
        self.fc4 = nn.Linear(hidden_size, output_size)
        # 定义激活函数
        self.relu = nn.ReLU()

    def forward(self, x):
        # 输入数据经过第一个Linear和ReLU激活
        x = self.relu(self.fc1(x))
        # 输入数据经过第二个Linear和ReLU激活
        x = self.relu(self.fc2(x))
        # 输入数据经过第三个Linear和ReLU激活
        x = self.relu(self.fc3(x))
        # 输入数据经过第四个Linear进行输出
        x = self.fc4(x)
        return x

model = DNN(X_train_tensor.shape[1], 256,1)
# 将模型放到device上
model.to(device)

3.7、定义损失函数和优化器

python 复制代码
# 定义损失函数,使用均方误差损失函数,回归任务
criterion = nn.MSELoss()
# 定义优化器
optimizer = optim.Adam(model.parameters(), lr=0.01)

3.8、训练模型

python 复制代码
for epoch in range(1,1001):
    # 将模型设置为训练模式
    model.train()

    # 初始化总损失
    total_loss = 0

    # 循环加载dataLoader,每次获取一个批次的数据和标签
    for inputs, labels in train_loader:
        # 清空优化器梯度
        optimizer.zero_grad()

        # 将inputs和labels放到device上,即将输入数据放到指定的设备上
        inputs = inputs.to(device)
        labels = labels.to(device)

        # 前向传播,计算输出
        outputs = model(inputs)

        # 计算损失
        loss = criterion(outputs, labels)

        # 反向传播和优化
        loss.backward()

        # 更新参数
        optimizer.step()

        # 累加当前批次的损失
        total_loss += loss

    # 计算本次epoch的平均损失
    avg_loss = total_loss / len(train_loader)

    # 每10个epoch打印一次当前模型的训练情况
    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch + 1}/{1000}], Loss: {avg_loss:.4f}')

3.9、模型评估

python 复制代码
with torch.no_grad():
    # 将模型设置为评估模式
    model.eval()
    # 将测试集放到模型上计算输出
    predict_test = model(X_test_tensor.to(device))
    # 计算测试集的损失
    test_loss = criterion(predict_test, y_test_tensor.to(device))

3.10、 可视化

python 复制代码
# 将预测值从GPU移动到CPU上再去转换为Numpy
predictions = predict_test.cpu().numpy()
# 将测试集目标值从CPU上移动到CPU上并转换为Numpy
y_test_numpy = y_test_tensor.cpu().numpy()
# 绘制结果,创建一个新的图形窗口
plt.figure(1)
# 绘制散点图,用来显示实际值和预测值的关系
plt.scatter(y_test_numpy, predictions, color='blue')
# 绘制对角线,用来对比
plt.plot([min(y_test_numpy), max(y_test_numpy)], [min(y_test_numpy), max(y_test_numpy)], linestyle='--', color='red', lw=2)
# 设置x轴标签
plt.xlabel('Actual Values')
# 设置y轴标签
plt.ylabel('Predicted Values')
# 设置标题
plt.title('Regression Results')


# 绘制实际值和预测值的曲线
# 创建一个新的图形窗口
plt.figure(2)
# 绘制实际值的曲线,取最后100个样本
plt.plot(y_test_tensor[-100:], label='Actual Values', marker='o')
# 绘制预测值的曲线,取最后100个样本
plt.plot(predictions[-100:], label='Predicted Values', marker='*')
# 设置x轴标签
plt.xlabel('Sample Index')
# 设置y轴标签
plt.ylabel('Values')
# 设置标题
plt.title('Actual vs Predicted Values in Linear Regression')

plt.show()

3.11、完整代码

python 复制代码
# 导入必要的库  
import pandas as pd  # 数据处理  
import numpy as np  # 数值计算  
import random  # 随机数生成  
import os  # 操作系统功能  
import torch  # PyTorch库  
import torch.nn as nn  # 神经网络模块  
import torch.optim as optim  # 优化算法  
import matplotlib.pyplot as plt  # 绘图  
import seaborn as sns  # 高级可视化工具  
from sklearn.preprocessing import StandardScaler  # 特征缩放  
from torch.utils.data import TensorDataset, DataLoader  # 数据集与数据加载器  

# 设置随机种子以保证结果的可重复性  
def setup_seed(seed):  
    # 设置 Numpy 随机数种子,确保Numpy生成的随机数序列一致  
    np.random.seed(seed)  
    # 设置Python内置随机数种子,保证Python内置的随机函数生成的随机数一致  
    random.seed(seed)  
    # 设置Python哈希种子  
    os.environ['PYTHONHASHSEED'] = str(seed)  
    # 设置PyTorch随机数种子  
    torch.manual_seed(seed)  

    # 检查CUDA设备  
    if torch.cuda.is_available():  
        torch.cuda.manual_seed(seed)  # 设置CUDA随机种子  
        torch.cuda.manual_seed_all(seed)  # 为所有GPU设置随机种子  
        torch.backends.cudnn.benchmark = False  # 保证结果可重复  
        torch.backends.cudnn.deterministic = True  # 使用确定性算法  

# 检测CPU/GPU可用性  
if torch.cuda.is_available():  
    device = 'cuda'  # 使用CUDA  
    print('CUDA is useful!!')  
else:  
    device = 'cpu'  # 使用CPU  
    print('CUDA is not useful!!')  

setup_seed(0)  # 设置随机种子  

# 设置pandas显示选项,以便显示更多列和行  
pd.set_option('display.max_columns', 1000)  # 最多显示1000列  
pd.set_option('display.width', 1000)  # 显示宽度为1000  
pd.set_option('display.max_colwidth', 1000)  # 每列最多显示1000个字符  

# 读取数据集  
train_data = pd.read_csv('train.csv', encoding='big5')  # 注意编码格式  
# 查看前5行数据,确保数据读取正确  
# print(train_data.head())  
# 打印数据集的信息,查看数据集的情况  
# print(train_data.info())  

# 选取从第3列开始到最后的所有列作为特征数据  
train_data = train_data.iloc[:, 3:]  

# 将数组中值为'NR'的元素替换为0  
train_data[train_data == 'NR'] = 0  

# 将train_data转换为Numpy数组  
numpy_data = train_data.to_numpy()  

# 创建一个列表,用来存储拆分后的数据  
datas = []  

# 按照步长为18分割数据  
for i in range(0, 4320, 18):  
    datas.append(numpy_data[i:i+18, :])  

# 将datas转换为Numpy数组  
datas_array = np.array(datas, dtype=float)  

# 对数据进行维度变换和重塑,转为DataFrame格式  
train_data = pd.DataFrame(datas_array.transpose(1, 0, 2).reshape(18, -1).T)  

# 计算特征相关性矩阵  
corr = train_data.corr()  

# 绘制相关性热图  
plt.figure(0)  
# 使用seaborn库绘制相关性矩阵的热图  
sns.heatmap(corr, annot=True)  

# 从相关性矩阵里筛选比较重要的特征(绝对值大于0.2的特征)  
important_features = []  
for i in range(len(corr.columns)):  
    if abs(corr.iloc[i, 9]) > 0.2:  
        important_features.append(corr.columns[i])  

# print('比较重要的特征:', important_features)  

# 定义特征(X)和目标(y)  
X = train_data[important_features].drop(9, axis=1)  # 选取重要特征,但排除目标特征  
y = train_data[9]  # 选取第9列
# 划分训练集和测试集
train_ratio = 0.8  # 设定训练集比例

# 训练集特征
X_train = X[:int(train_ratio * len(train_data))]  # 根据比例切分训练集特征
# 测试集特征
X_test = X[int(train_ratio * len(train_data)):]  # 根据比例切分测试集特征
# 训练集标签
y_train = y[:int(train_ratio * len(train_data))]  # 根据比例切分训练集标签
# 测试集标签
y_test = y[int(train_ratio * len(train_data)):]  # 根据比例切分测试集标签

# 使用标准化进行特征缩放
scaler = StandardScaler()  # 实例化标准化对象
X_train_scaled = scaler.fit_transform(X_train)  # 拟合并转换训练集特征
X_test_scaled = scaler.transform(X_test)  # 仅转换测试集特征

# 将数据转换为PyTorch的张量
# 训练集的特征张量表示
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)
# 测试集的特征张量表示
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)

# 使用DataLoader加载数据集
# 创建TensorDataset对象,将训练集特征和标签一一组合在一起
train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
# 创建DataLoader对象,用于批量加载数据
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)


# 构建DNN模型
class DNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        # 调用父类的构造函数
        super(DNN, self).__init__()
        # 定义第一个Linear层,输入维度为input_size,输出维度为hidden_size
        self.fc1 = nn.Linear(input_size, hidden_size)
        # 定义第二个Linear层,输入是hidden_size,输出维度是hidden_size
        self.fc2 = nn.Linear(hidden_size, hidden_size)
        # 定义第三个Linear层,输入是hidden_size,输出维度是hidden_size
        self.fc3 = nn.Linear(hidden_size, hidden_size)
        # 定义第四个Linear层,输入是hidden_size,输出维度是output_size
        self.fc4 = nn.Linear(hidden_size, output_size)
        # 定义激活函数
        self.relu = nn.ReLU()  # ReLU激活函数

    def forward(self, x):
        # 输入数据经过各层和激活函数
        x = self.relu(self.fc1(x))  # 第一个Linear和ReLU激活
        x = self.relu(self.fc2(x))  # 第二个Linear和ReLU激活
        x = self.relu(self.fc3(x))  # 第三个Linear和ReLU激活
        x = self.fc4(x)  # 最后一层线性输出
        return x

    # 实例化模型


model = DNN(X_train_tensor.shape[1], 256, 1)  # 输入特征维度、隐藏层节点数和输出维度

# 将模型放到指定设备上(GPU或CPU)
model.to(device)

# 定义损失函数,使用均方误差损失函数,适用于回归任务
criterion = nn.MSELoss()
# 定义优化器,使用Adam优化器
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 进行训练迭代
for epoch in range(1, 1001):
    model.train()  # 将模型设置为训练模式
    total_loss = 0  # 初始化总损失

    # 循环加载DataLoader,每次获取一个批次的数据和标签
    for inputs, labels in train_loader:
        # 清空优化器梯度
        optimizer.zero_grad()
        # 将inputs和labels放到device上
        inputs = inputs.to(device)
        labels = labels.to(device)

        # 前向传播,计算输出
        outputs = model(inputs)

        # 计算损失
        loss = criterion(outputs, labels)

        # 反向传播和优化
        loss.backward()  # 反向传播计算梯度
        optimizer.step()  # 更新参数

        # 累加当前批次的损失
        total_loss += loss.item()  # 获取当前批次的损失,累加到 total_loss

    # 计算本次 epoch 的平均损失
    avg_loss = total_loss / len(train_loader)

    # 每10个epoch打印一次当前模型的训练情况
    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch + 1}/{1000}], Loss: {avg_loss:.4f}')

# 模型的评估
with torch.no_grad():  # 不计算梯度以提高速度和减少内存使用
    model.eval()  # 将模型切换到评估模式
    # 将测试集放到模型上计算输出
    predict_test = model(X_test_tensor.to(device))
    # 计算测试集的损失
    test_loss = criterion(predict_test, y_test_tensor.to(device))

# 打印测试集的损失
print('MSE:', test_loss.item())  # 打印均方误差

# 将预测值和目标值转换为Numpy数组
predictions = predict_test.cpu().numpy()  # 将预测值从GPU移到CPU并转换为Numpy
y_test_numpy = y_test_tensor.cpu().numpy()  # 将测试集目标值从GPU移动到CPU并转换为Numpy

# 绘制结果,创建一个新的图形窗口
plt.figure(1)
# 绘制散点图,用来显示实际值和预测值的关系
plt.scatter(y_test_numpy, predictions, color='blue', label='Predicted Values')
# 绘制对角线,用来对比预测值与实际值的关系
plt.plot([min(y_test_numpy), max(y_test_numpy)], [min(y_test_numpy), max(y_test_numpy)],
         linestyle='--', color='red', lw=2, label='Ideal Prediction')
# 设置x轴标签
plt.xlabel('Actual Values')
# 设置y轴标签
plt.ylabel('Predicted Values')
# 设置标题
plt.title('Regression Results')
plt.legend()  # 显示图例

# 绘制实际值和预测值的曲线
plt.figure(2)
# 绘制实际值的曲线,取最后100个样本
plt.plot(y_test_numpy[-100:], label='Actual Values', marker='o')
# 绘制预测值的曲线,取最后100个样本
plt.plot(predictions[-100:], label='Predicted Values', marker='*')
# 设置x轴标签
plt.xlabel('Sample Index')
# 设置y轴标签
plt.ylabel('Values')
# 设置标题
plt.title('Actual vs Predicted Values in Linear Regression')
plt.legend()  # 显示图例

plt.show()  # 显示所有图形
相关推荐
学渣676561 分钟前
什么时候使用Python 虚拟环境(venv)而不用conda
开发语言·python·conda
飞哥数智坊5 分钟前
打工人周末充电:15条AI资讯助你领先一小步
人工智能
Tech Synapse8 分钟前
基于CARLA与PyTorch的自动驾驶仿真系统全栈开发指南
人工智能·opencv·sqlite
layneyao9 分钟前
深度强化学习(DRL)实战:从AlphaGo到自动驾驶
人工智能·机器学习·自动驾驶
悲喜自渡72118 分钟前
线性代数(一些别的应该关注的点)
python·线性代数·机器学习
海特伟业1 小时前
隧道调频广播覆盖的实现路径:隧道无线广播技术赋能行车安全升级,隧道汽车广播收音系统助力隧道安全管理升级
人工智能
Huanzhi_Lin1 小时前
python源码打包为可执行的exe文件
python
CareyWYR1 小时前
每周AI论文速递(250421-250425)
人工智能
声声codeGrandMaster1 小时前
django之账号管理功能
数据库·后端·python·django
追逐☞1 小时前
机器学习(10)——神经网络
人工智能·神经网络·机器学习