数据分析——数据预处理和数据管道构建

2023-12-26 16:23:26

目标:对于拿到的一个任意数据集,编写类似数据加载程序,以适应深度学习的研究。

?框架:

针对不同的时间序列数据集,可以总结如下关键步骤,以编写类似上述代码的深度学习数据处理流程:

1. **了解数据集:**


? ?- 了解新数据集的特性,包括时间序列的长度、采样频率、数据格式和标签信息等。

2. **数据加载:**


? ?- 实现加载时间序列数据的函数,可以使用常见的数据处理库(例如`pandas`、`numpy`)。

```python
# 例如,对CSV格式的时间序列数据进行加载
import pandas as pd

def load_time_series_data(file_path):
? ? return pd.read_csv(file_path)
```

3. **数据预处理:**


? ?- 根据时间序列数据的特点进行预处理,包括但不限于:
? ? ?- 缺失值处理
? ? ?- 平滑处理(如滤波)
? ? ?- 标准化或归一化
? ? ?- 特征工程(提取有用的特征)

```python
# 例如,简单的归一化处理
def normalize_time_series_data(data):
? ? return (data - data.mean()) / data.std()
```

4. **数据分割:**


? ?- 将时间序列数据集划分为训练集、验证集和测试集。

```python
# 例如,基于时间的分割
def split_time_series_data(data, train_ratio=0.8, val_ratio=0.1):
? ? train_size = int(len(data) * train_ratio)
? ? val_size = int(len(data) * val_ratio)
? ? test_size = len(data) - train_size - val_size
? ? train_data, val_data, test_data = data[:train_size], data[train_size:train_size + val_size], data[-test_size:]
? ? return train_data, val_data, test_data
```

5. **序列切割:**
? ?- 如果时间序列较长,可以将其切割成固定长度的序列,以便输入深度学习模型。

```python
# 例如,将时间序列切割成固定长度的子序列
def segment_time_series(data, segment_length):
? ? segments = []
? ? for i in range(0, len(data) - segment_length + 1, segment_length):
? ? ? ? segments.append(data[i:i+segment_length])
? ? return segments
```

6. **数据增强:**


? ?- 根据需要,实现时间序列数据的数据增强方法,例如引入噪声、随机缩放等。

```python
# 例如,简单的添加噪声
import numpy as np

def add_noise_to_time_series(data, noise_level=0.1):
? ? noise = np.random.normal(0, noise_level, len(data))
? ? return data + noise
```

7. **构建数据集类:**


? ?- 设计一个数据集类,整合加载、预处理、分割等操作,以便于在深度学习模型中使用。

```python
class TimeSeriesDataset:
? ? def __init__(self, file_path, segment_length=256, train_ratio=0.8, val_ratio=0.1):
? ? ? ? self.data = load_time_series_data(file_path)
? ? ? ? self.data = normalize_time_series_data(self.data)
? ? ? ? self.train_data, self.val_data, self.test_data = split_time_series_data(self.data, train_ratio, val_ratio)
? ? ? ? self.train_segments = segment_time_series(self.train_data, segment_length)
? ? ? ? # ...其他初始化步骤...

# 示例用法
time_series_dataset = TimeSeriesDataset('path/to/your/time_series_data.csv')
```

8. **数据管道:**


? ?- 建立一个数据管道,确保数据有效地输入到深度学习模型中。

```python
# 例如,使用 TensorFlow 的数据管道
import tensorflow as tf

def create_data_pipeline(data, batch_size=32):
? ? dataset = tf.data.Dataset.from_tensor_slices(data)
? ? dataset = dataset.shuffle(buffer_size=len(data))
? ? dataset = dataset.batch(batch_size)
? ? return dataset
```

通过按照这些步骤组织代码,您可以更容易地处理不同时间序列数据集,并确保数据准备流程适应您的深度学习任务。

案例一:将如下LSTM的时间预测项目代码改为由数据加载和处理(data_loader)、模型(models)?、训练代码(train.py)三部分组成。

?1.1 整体代码(修改前)

import torch
import torch.nn as nn

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 读取数据集
dataset = pd.read_csv(r'D:\datasets\预测模型实验\PRZ liquid space leak 0.8.csv')

# 将行数做成一列显式的索引列
dataset.insert(0, 'Index_Column', dataset.index)

all_data = dataset['主回路1热管段冷却剂温度(℃)306.852814'].values


# 数据预处理
# 定义划分比例
train_ratio = 0.8  # 80%的数据作为训练集

# 计算划分索引
split_index = int(len(dataset) * train_ratio)

# 划分数据
train_data = dataset.iloc[:split_index]
test_data = dataset.iloc[split_index:]

# 标准化
from sklearn.preprocessing import MinMaxScaler

# '主回路1热管段冷却剂温度(℃)306.852814' 是要归一化的列名
column_name = '主回路1热管段冷却剂温度(℃)306.852814'

# 将 DataFrame 转换为 NumPy 数组
train_data_array = train_data[column_name].values.reshape(-1, 1)

# 使用 MinMaxScaler 进行归一化
scaler = MinMaxScaler(feature_range=(-1, 1))
train_data_normalized = scaler.fit_transform(train_data_array)

# 数据张量化
train_data_normalized = torch.FloatTensor(train_data_normalized).view(-1)

# 训练数据转换为序列和相应的标签
train_window = 30

def create_inout_sequences(input_data, tw):
    inout_seq = []
    L = len(input_data)
    for i in range(L-tw):
        train_seq = input_data[i:i+tw]
        train_label = input_data[i+tw:i+tw+1]
        inout_seq.append((train_seq ,train_label))
    return inout_seq

train_inout_seq = create_inout_sequences(train_data_normalized, train_window)

# 创建模型
import torch.nn as nn

class LSTM(nn.Module):
    def __init__(self, input_size=1, hidden_layer_size=100, output_size=1):
        super().__init__()
        self.hidden_layer_size = hidden_layer_size

        self.lstm = nn.LSTM(input_size, hidden_layer_size)
        self.linear = nn.Linear(hidden_layer_size, output_size)

    def forward(self, input_seq):
        lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq), 1, -1), self.hidden_cell)
        predictions = self.linear(lstm_out.view(len(input_seq), -1))
        return predictions[-1]

# 构建模型对象
model = LSTM()
loss_function = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

import matplotlib.pyplot as plt

epochs = 50
losses = []  # 用于存储每个 epoch 的损失值

for i in range(epochs):
    epoch_loss = 0.0  # 用于累积每个 epoch 的损失值

    for seq, labels in train_inout_seq:
        optimizer.zero_grad()
        model.hidden_cell = (torch.zeros(1, 1, model.hidden_layer_size),
                            torch.zeros(1, 1, model.hidden_layer_size))

        y_pred = model(seq)

        single_loss = loss_function(y_pred, labels)
        single_loss.backward()
        optimizer.step()

        epoch_loss += single_loss.item()

    losses.append(epoch_loss)  # 记录每个 epoch 的损失值

    if i % 5 == 0:  # 每5个 epoch 打印一次损失值
        print(f'Epoch [{i}/{epochs}], Loss: {epoch_loss:.8f}')

# 绘制损失曲线
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss Over Epochs')
plt.show()

# 进行预测
fut_pred = 30

test_inputs = train_data_normalized[-train_window:].tolist()
#print(test_inputs)

model.eval()

for i in range(fut_pred):
    seq = torch.FloatTensor(test_inputs[-train_window:])
    with torch.no_grad():
        model.hidden = (torch.zeros(1, 1, model.hidden_layer_size),
                        torch.zeros(1, 1, model.hidden_layer_size))
        test_inputs.append(model(seq).item())


# 将归一化后的预测值转换为实际预测值
actual_predictions = scaler.inverse_transform(np.array(test_inputs[train_window:] ).reshape(-1, 1))

# 可视化预测值与实际值
x = np.arange(437, 467, 1)

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用中文字体(例如:黑体)
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

plt.title('主回路1热管段冷却剂温度')
plt.ylabel('温度值')
plt.grid(True)
plt.autoscale(axis='x', tight=True)
plt.plot(dataset['主回路1热管段冷却剂温度(℃)306.852814'],label='实际温度')
plt.plot(x,actual_predictions, label='预测温度')
# 添加图例
plt.legend()
plt.show()

?将如上LSTM的时间预测项目代码改为由数据加载和处理(data_loader)、模型(models)?、训练代码(train.py)三部分组成。

1.2??数据加载和处理(data_loader)

将被用于深度学习的数据集定义为一个数据集类,数据的加载和预处理都通过这个类来实现。编写该类时,主要关注两个方面,其一是构造函数(详情如下),其二就是?

构造函数:

初始化可控参数,包括加载数据(导入数据)初始化超参数实例化某种工具(比如归一化实例)。?

data_loader部分的代码:

# data_loader/shujvjiazai.py
import torch
import pandas as pd
from sklearn.preprocessing import MinMaxScaler

# 数据加载
class DataLoader:
    def __init__(self, file_path, column_name, train_ratio=0.8):
        self.dataset = pd.read_csv(file_path)
        self.train_ratio = train_ratio  # 划分为训练集的比例
        self.scaler = MinMaxScaler(feature_range=(-1, 1)) # 归一化实例
        self.column_name = column_name  # 将要被归一化的列名

    def load_and_preprocess_data(self):
        split_index = int(len(self.dataset) * self.train_ratio) # # 计算划分索引

        # 划分数据集
        train_data = self.dataset.iloc[:split_index] # 划分的训练集
        test_data = self.dataset.iloc[split_index:]  # 划分的测试集

        # # 将 DataFrame 转换为 NumPy 数组
        train_data_array = train_data[self.column_name].values.reshape(-1, 1)
        train_data_normalized = self.scaler.fit_transform(train_data_array)

        # 张量化
        train_data_normalized = torch.FloatTensor(train_data_normalized).view(-1)

        # 返回张量化后的数据
        return train_data_normalized

要点:
(1)构造函数负责加载数据和声明(初始化)可控参数。

(2)在函数中定义数据预处理的步骤,比如数据划分,归一化,张量化等。

1.3 模型(model)

整体代码中和将代码分写,关于model部分并无变化。

?

1.4 训练脚本(train.py)

在训练脚本train.py中,需要导入前面编写好的数据加载代码,比如要导入?

data_loader/shujvjiazai.py中的数据处理类DataLoader

那就在train.py中做导入,即:

from data_loader.shujvjiazai import DataLoader

由上可知,也可以在shujvjiazai.py文件中写下多个不同的数据集处理类,比如class?DataLoader1,class?DataLoader2,class?DataLoader3

这样当train中需要对某个数据集做训练时,只要在train.py中导入该数据集类即可。比如:

from data_loader.shujvjiazai import DataLoader2? # 应用数据集DataLoader2?

?

?关于创建模型实例,以及迭代训练模型的代码,train.py中好“一体化”代码并没有什么两样。

总结

若想改变原来写“一体化”代码的习惯,养成将代码分块,其实就是python中模块化的思想。

(1)首先,编写好数据加载和预处理模块(例如:data_loader/shujvjiazai.py ),导入数据,设置好一些超参数。

(2)然后再根据数据预处理的基本步骤,将各个步骤写成函数,于数据集类中。

(3)编写好模型代码(例如:models/LSTM_LKW.py )。

(4)编写好模型训练代码(train.py)。主要在于导入包部分,其他的训练代码的写法其实和“一体化”代码一样。导入如上(1)(3)中的数据和模型,所以在train.py中。需要导入这两个模块。

?

?

?

文章来源:https://blog.csdn.net/m0_55196097/article/details/135198507
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。