2024 Datawhale AI 夏令营 电力需求预测挑战赛学习笔记---task 03

紧接前一篇笔记,本篇笔记主要记录和探讨深度学习的方式进行实现。

再次贴上官方赛事链接:2024 iFLYTEK A.I.开发者大赛-讯飞开放平台

深度学习入门

深度学习的实现我主要是利用pytorch,pytorch的入门教程(我参照的)放在下面:

http://【PyTorch深度学习快速入门教程(绝对通俗易懂!)【小土堆】】https://www.bilibili.com/video/BV1hE411t7RN?p=33&vd_source=9e2d7d85e20db70d93c3d3d4273f4b65

而在分析本次赛事代码之前,我想先说明一下深度学习模型的范式:

深度学习模型范式

首先给出一份标准代码(代码是之前学习的时候写的一道面试题):

import pandas as pd
import torch
from torch import nn, optim
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder
from torch.utils.data import DataLoader, TensorDataset

# 读取数据集
train_df = pd.read_csv("C:\\Users\\admin\\Desktop\\intern\\intern\\train_dataset.csv")
test_df = pd.read_csv("C:\\Users\\admin\\Desktop\\intern\\intern\\test_dataset.csv")

# 丢弃不需要的列,取出标签列
X = train_df.drop(columns=['ID', 'class'])
y = train_df['class']

# 处理缺失值:用均值填补数值列的缺失值
X.fillna(X.mean(), inplace=True)

# 标准化特征
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 编码标签,将类别标签编码为数值
label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)

# 划分训练集和验证集
X_train, X_val, y_train, y_val = train_test_split(X_scaled, y_encoded, test_size=0.2, random_state=42)

# 转换为PyTorch张量
X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train, dtype=torch.long)
X_val_tensor = torch.tensor(X_val, dtype=torch.float32)
y_val_tensor = torch.tensor(y_val, dtype=torch.long)

# 创建数据加载器
train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
val_dataset = TensorDataset(X_val_tensor, y_val_tensor)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)

# 定义模型
class Classifier(nn.Module):
    def __init__(self):
        super(Classifier, self).__init__()
        #定义每一层的输入输出
        self.fc1 = nn.Linear(17, 128)
        self.dropout1 = nn.Dropout(0.3)
        self.fc2 = nn.Linear(128, 64)
        self.dropout2 = nn.Dropout(0.3)
        self.fc3 = nn.Linear(64, 32)
        self.fc4 = nn.Linear(32, 3)
    
    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = self.dropout1(x)
        x = torch.relu(self.fc2(x))
        x = self.dropout2(x)
        x = torch.relu(self.fc3(x))
        x = self.fc4(x)
        return x

# 初始化模型、损失函数和优化器
model = Classifier()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练模型
epochs = 20
for epoch in range(epochs):
    model.train()
    running_loss = 0.0
    for inputs, labels in train_loader:
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
    print(f"Epoch {epoch+1}, Loss: {running_loss/len(train_loader)}")

# 验证模型
model.eval()
val_loss = 0.0
correct = 0
total = 0
with torch.no_grad():
    for inputs, labels in val_loader:
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        val_loss += loss.item()
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
val_accuracy = correct / total
print(f'Validation Loss: {val_loss/len(val_loader)}, Validation Accuracy: {val_accuracy}')

# 对测试集进行预测
X_test = test_df.drop(columns=['ID'])
X_test_scaled = scaler.transform(X_test)
X_test_tensor = torch.tensor(X_test_scaled, dtype=torch.float32)
test_loader = DataLoader(X_test_tensor, batch_size=32, shuffle=False)

model.eval()
predictions = []
with torch.no_grad():
    for inputs in test_loader:
        outputs = model(inputs)
        _, predicted = torch.max(outputs, 1)
        predictions.extend(predicted.numpy())

# 保存预测结果到result.txt
predicted_classes = label_encoder.inverse_transform(predictions)
result_df = pd.DataFrame({'spec_obj_ID': test_df['spec_obj_ID'], 'class': predicted_classes})
result_df.to_csv("C:\\Users\\admin\\Desktop\\result.txt", index=False)

由上面代码可以见,一般步骤为:

  • 数据的读入:包括训练集和测试集的数据读入, 使用pd.read_csv函数。补充一下:CSV(Comma-Separated Values,逗号分隔值,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。CSV 是一种通用的、相对简单的文件格式,被用户、商业和科学广泛应用。
  • 数据的处理:包括数据清洗(无关数据丢弃)、缺失值处理、非数值数据编码等,以及最最最重要的:标准化!!!(我使用的是StandardScaler来处理)
  • 数据的转化和加载:我使用的是pytorch,所以先转为pytorch张量,然后创建数据加载器DataLoader和TensorDataset(目的是是数据能够批次处理)
  • 模型定义:一般继承pytorch里面的nn.Module(这里面有各种模型板子,具体可以看官网的文档),模型里面必须定义init(每一层是干什么的),以及forward(每一层怎么传的)
  • 模型初始化、损失函数和优化器:损失函数如果是多分类问题就选交叉熵损失函数(具体损失函数怎么选还是去看官方文档),优化器一般都选adam优化器(后面赛题分析也是adam)
  • 训练模型:定义训练轮次,每次训练拿数据,丢给模型,得到输出,与实际输出一起算损失函数,backward后向传播算每层梯度,每层的梯度数据丢给优化器优化参数(step函数)
  • 验证模型:主要是看准确度,预测的和真实值一样就+1
  • 对测试集进行预测:把测试集数据丢给他,额外注意+with torch.no_grad():防止跑的时候修改梯度进而修改模型

本次赛题代码及分析

import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM, Dense, RepeatVector, TimeDistributed
from keras.optimizers import Adam

train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')

# 数据预处理
def preprocess_data(df, look_back=100):
    # 将数据按照id进行分组
    grouped = df.groupby('id')
    datasets = {}
    for id, group in grouped:
        datasets[id] = group.values
        
    # 准备训练数据集
    X, Y = [], []
    for id, data in datasets.items():
        for i in range(10, 15): # 每个id构建5个序列
            a = data[i:(i + look_back), 3]
            a = np.append(a, np.array([0]*(100-len(a))))
            X.append(a[::-1])
            Y.append(data[i-10:i, 3][::-1])
    
    # 准备测试数据集
    OOT = []
    for id, data in datasets.items():
        a = data[:100, 3]
        a = np.append(a, np.array([0]*(100-len(a))))
        OOT.append(a[::-1])
    
    return np.array(X, dtype=np.float64), np.array(Y, dtype=np.float64), np.array(OOT, dtype=np.float64)

# 定义模型
def build_model(look_back, n_features, n_output):
    model = Sequential()
    model.add(LSTM(50, input_shape=(look_back, n_features)))
    model.add(RepeatVector(n_output))
    model.add(LSTM(50, return_sequences=True))
    model.add(TimeDistributed(Dense(1)))
    model.compile(loss='mean_squared_error', optimizer=Adam(0.001))
    return model

# 构建和训练模型
look_back = 100  # 序列长度
n_features = 1  # 假设每个时间点只有一个特征
n_output = 10  # 预测未来10个时间单位的值

# 预处理数据
X, Y, OOT = preprocess_data(train, look_back=look_back)

# 构建模型
model = build_model(look_back, n_features, n_output)

# 训练模型
model.fit(X, Y, epochs=10, batch_size=64, verbose=1)

# 进行预测
predicted_values = model.predict(OOT)

会发现大致跟之前代码思路一样的:

数据处理——preprocess_data:用于对数据进行预处理。(使用 groupby('id')id 对数据进行分组,每个组对应一个独立的时间序列。)

准备数据集——

X 和 Y 分别存储输入序列和输出序列。 对每个 id,在每个序列开始的索引从 10 到 14,共构建 5 个序列。 a = np.append(a, np.array([0]*(100-len(a)))):确保每个序列的长度为100,不足的部分用0填充。 X.append(a[::-1]) 和 Y.append(data[i-10:i, 3][::-1]):将序列逆序并添加到训练数据集中。

然后定义模型——

Sequential():创建一个顺序模型。 LSTM(50, input_shape=(look_back, n_features)):添加一个LSTM层,具有50个单元。 RepeatVector(n_output):重复输入序列 n_output 次,用于后续的LSTM层。 LSTM(50, return_sequences=True):添加另一个LSTM层,返回完整的输出序列。 TimeDistributed(Dense(1)):对每个时间步的输出使用全连接层。 model.compile(loss='mean_squared_error', optimizer=Adam(0.001)):编译模型,使用均方误差作为损失函数,Adam作为优化器。

然后训练和预测——

预处理数据: 调用 preprocess_data 函数对训练数据进行预处理,得到 X, Y, 和 OOT。 构建模型: 调用 build_model 函数构建LSTM模型。 训练模型: 使用 model.fit(X, Y, epochs=10, batch_size=64, verbose=1) 训练模型,训练次数为10,批量大小为64。 进行预测: 使用 model.predict(OOT) 对测试数据进行预测。

本题模型分析

模型用的是LSTM,LSTM是什么?为什么要用它?

LSTM(长短期记忆,Long Short-Term Memory)是一种特殊的递归神经网络(RNN),设计用于处理和预测序列数据中的长时间依赖性问题。LSTM通过引入门控机制,解决了传统RNN在处理长序列数据时的梯度消失和梯度爆炸问题,使得LSTM在自然语言处理、时间序列预测等任务中表现得尤为出色。

电力消耗具有时间依赖性,即当前时刻的消耗可能受到前几天消耗的影响。LSTM通过其特殊的记忆单元和门控机制,可以有效地记住和利用这些长期的时间依赖关系,从而提高预测的准确性。

一些思考

查看示例代码后一直再想有没有其他模型能够拟合,因为之前网上教程主要讲的CNN,所以上网搜了一下是否可以进行应用,发现:

CNN通常用于图像处理任务,但也可以用于时间序列预测,尤其是当序列中存在局部模式时。可以通过一维卷积层来提取时间序列中的特征……

于是大概写了个模型:

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from keras.models import Sequential
from keras.layers import Conv1D, MaxPooling1D, Flatten, Dense
from keras.optimizers import Adam

# 读取数据
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')

# 数据预处理
def preprocess_data(df, look_back=30):
    # 将数据按照id进行分组
    grouped = df.groupby('id')
    datasets = {}
    for id, group in grouped:
        datasets[id] = group.values

    # 准备训练数据集
    X, Y = [], []
    for id, data in datasets.items():
        if len(data) < look_back:
            continue
        for i in range(len(data) - look_back):
            X.append(data[i:i + look_back, 3])  # 取 'target' 列作为输入特征
            Y.append(data[i + look_back, 3])  # 预测下一天的 'target'
    
    return np.array(X, dtype=np.float64), np.array(Y, dtype=np.float64)

# 准备数据
look_back = 30  # 使用过去30天的数据进行预测
X, Y = preprocess_data(train, look_back)

# 数据标准化
scaler = StandardScaler()
X = scaler.fit_transform(X)

# 拆分训练集和验证集
X_train, X_val, Y_train, Y_val = train_test_split(X, Y, test_size=0.2, random_state=42)

# Reshape 输入数据以匹配CNN的输入格式 (samples, time_steps, features)
X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], 1)
X_val = X_val.reshape(X_val.shape[0], X_val.shape[1], 1)

# 构建CNN模型
def build_cnn_model(look_back, n_features):
    model = Sequential()
    model.add(Conv1D(filters=64, kernel_size=2, activation='relu', input_shape=(look_back, n_features)))
    model.add(MaxPooling1D(pool_size=2))
    model.add(Flatten())
    model.add(Dense(50, activation='relu'))
    model.add(Dense(1))  # 预测一个未来值
    model.compile(optimizer=Adam(0.001), loss='mean_squared_error')
    return model

# 初始化和编译模型
cnn_model = build_cnn_model(look_back, 1)

# 训练模型
cnn_model.fit(X_train, Y_train, epochs=10, batch_size=64, validation_data=(X_val, Y_val), verbose=1)

# 预测
X_test, _ = preprocess_data(test, look_back)
X_test = scaler.transform(X_test)
X_test = X_test.reshape(X_test.shape[0], X_test.shape[1], 1)

predictions = cnn_model.predict(X_test)

# 保存预测结果
result_df = pd.DataFrame({'id': test['id'], 'dt': test['dt'], 'predicted_target': predictions.flatten()})
result_df.to_csv('predictions.csv', index=False)

模型部分说明:

使用sequential模型(线性堆叠的层次结构);

Conv1D是用于时间序列数据的卷积层。 filters=64: 卷积核的数量,即输出的维度数。这里我使用64个卷积核来提取特征。 kernel_size=2: 卷积核的大小,这里选择2意味着我在每个时间步上应用长度为2的卷积核。 activation='relu': 激活函数,选择ReLU(修正线性单元),常用于CNN中以引入非线性。 input_shape=(look_back, n_features): 输入形状,即时间步数和每个时间步的特征数量。这里输入的形状是(30, 1)。

MaxPooling1D用于下采样序列数据,通过取池化窗口中的最大值来减少数据的空间维度。 pool_size=2: 池化窗口的大小,这里选择2意味着我每2个时间步取一个最大值,减少输入的长度一半。

Flatten层将多维输入展平成一维,以便连接到全连接层。

Dense层是全连接层,包含50个神经元。 activation='relu': 激活函数选择ReLU。

最后一层是一个单神经元的全连接层,用于输出一个连续值,即预测的电力消耗。

  • 19
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值