iT邦幫忙

2023 iThome 鐵人賽

DAY 26
1
AI & Data

ML From Scratch系列 第 26

[Day 26] Recurrent Neural Network — 解決真實問題

  • 分享至 

  • xImage
  •  

今天是第 26 天 !!!

我們將會透過 Recurrent Neural Network (RNN) 和 Long Short-Term Memory (LSTM) 來對銷售額進行預測。

Kaggle Competition 是 Store Sales - Time Series Forecasting

https://ithelp.ithome.com.tw/upload/images/20230926/20152821eWd18TVo6U.png

Dataset

資料集包括日期、商店和產品信息,以及該產品是否正在促銷,以及銷售數字。

train.csv

包括時間序列特徵store_nbrfamilyonpromotion,以及目標銷售。

  • store_nbr: 識別出售產品的商店。
  • family: 識別出售的產品類型。
  • sales 給出了在特定日期的特定商店中產品家族的總銷售額。

test.csv

具有與訓練數據相同的特徵。

預測此文件中日期的目標銷售額。

測試資料中的日期是訓練數據中最後日期之後的15天。

stores.csv

商店,包括城市、州、類型和集群。其中,cluster是相似商店的分組。

oil.csv

每日油價。包括在訓練和測試數據時間範圍內的數值。

holidays_events.csv

節假日和活動

Implementation

Import Library

import os
import numpy as np  # 線性代數
import pandas as pd  # 數據處理,CSV文件輸入/輸出(例如pd.read_csv)

from sklearn import preprocessing  # 使用scikit-learn進行數據預處理
from sklearn.preprocessing import MinMaxScaler  # 使用MinMaxScaler進行特徵縮放
from sklearn.preprocessing import OrdinalEncoder  # 使用OrdinalEncoder對特徵進行編碼

import tensorflow as tf  # 引入TensorFlow深度學習庫
from tensorflow import keras  # 引入Keras,作為TensorFlow的高階API
from tensorflow.keras import layers  # 引入Keras的各種層
from tensorflow.keras.layers import SimpleRNN, LSTM, Dense  # 引入RNN、LSTM和Dense層
from tensorflow.keras.layers import Dropout  # 引入Dropout層,用於防止過擬合
from tensorflow.keras.layers import Reshape  # 引入Reshape層,用於重塑輸出形狀
from tensorflow.keras.models import Model  # 引入Keras模型
from tensorflow.keras.optimizers import Adam  # 引入Adam優化器,用於模型訓練
from tensorflow.keras.layers import BatchNormalization  # 引入BatchNormalization層,用於規範輸入數據

import warnings
warnings.filterwarnings('ignore')  # 忽略警告訊息

Load Dataset

data_path = '../input/store-sales-time-series-forecasting/'

# 讀取oil.csv文件,並將'date'列設置為索引
oil = pd.read_csv(os.path.join(data_path, 'oil.csv'), index_col='date')

# 讀取holidays_events.csv文件,並將'date'列設置為索引
holidays_events = pd.read_csv(os.path.join(data_path, 'holidays_events.csv'), index_col='date')

# 讀取stores.csv文件
stores = pd.read_csv(os.path.join(data_path, 'stores.csv'))

# 讀取transactions.csv文件
transactions = pd.read_csv(os.path.join(data_path, 'transactions.csv'))

# 讀取train.csv文件,將'id'列設置為索引,並解析'date'列為日期格式
train = pd.read_csv(os.path.join(data_path, 'train.csv'), index_col='id', parse_dates=['date'], infer_datetime_format=True)

# 讀取test.csv文件,並解析'date'列為日期格式
test = pd.read_csv(os.path.join(data_path, 'test.csv'), parse_dates=['date'], infer_datetime_format=True)

RNN

keras.backend.clear_session()
np.random.seed(42)
tf.random.set_seed(42)

def timemodel():
    model = keras.Sequential()
### basic RNN model
    model.add(layers.SimpleRNN(units=200, return_sequences=True, input_shape=[n_past, n_features]))
    model.add(keras.layers.BatchNormalization())
    model.add(layers.Dropout(0.2))
    model.add(layers.SimpleRNN(units=200, return_sequences=True))
    model.add(keras.layers.BatchNormalization())
    model.add(layers.Dropout(0.2))

    model.add(keras.layers.TimeDistributed(keras.layers.Dense(n_features)))
    
    
    model.compile(loss="mae", optimizer=keras.optimizers.Adam(learning_rate=0.001), metrics=['mae'])
    return model

這裡我們建立了一個基本的時間序列模型。

該模型包括兩個SimpleRNN層,每個層都包含200個單元,並使用批次正規化和丟棄層進行規範和防止過擬合。

最後,模型使用TimeDistributed對Dense層進行時間分佈,然後使用均方誤差(MAE)作為損失函數,Adam優化器進行訓練,學習率為0.001,同時計算MAE指標。

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
simple_rnn (SimpleRNN)       (None, 16, 200)           396600    
_________________________________________________________________
batch_normalization (BatchNo (None, 16, 200)           800       
_________________________________________________________________
dropout (Dropout)            (None, 16, 200)           0         
_________________________________________________________________
simple_rnn_1 (SimpleRNN)     (None, 16, 200)           80200     
_________________________________________________________________
batch_normalization_1 (Batch (None, 16, 200)           800       
_________________________________________________________________
dropout_1 (Dropout)          (None, 16, 200)           0         
_________________________________________________________________
time_distributed (TimeDistri (None, 16, 1782)          358182    
=================================================================
Total params: 836,582
Trainable params: 835,782
Non-trainable params: 800
_________________________________________________________________

Train Model

early_stopping = keras.callbacks.EarlyStopping(monitor = 'val_mae',
                                               min_delta=0.0001,
                                               patience=100, 
                                               restore_best_weights=True)

EPOCHS = 1000
model_history = model.fit(
    X_train, y_train,
    validation_data=(X_val, y_val), 
    epochs=EPOCHS, 
    callbacks=[early_stopping], 
    batch_size=512, 
    shuffle=True)

這裡使用提前停止回調函數來訓練模型。

該回調函數將監控驗證集上的均方誤差(val_mae),如果均方誤差的變化小於0.0001,並且在連續100個epoch內未改善模型性能,則提前停止訓練,並還原最佳權重。

訓練總共執行1000個epoch,並使用批次大小為512,同時對訓練數據進行洗牌。

Model Predicition

for day_ith, day_ith_pred in y_predict.iterrows():
    # 對於每一天的每個樣本數量(從0到1781,對應16天)
    for n_samples_per_day in range(len(day_ith_pred)):
        # 獲取樣本的ID
        sample_id = pivoted_test.iloc[[day_ith], [n_samples_per_day]].values[0][0]  # 總樣本數
        # 將預測值設為非負值(如果預測值為負數,則設為0)
        values = max(0, day_ith_pred.values[n_samples_per_day])
        # 將預測的銷售值存儲在submission數據框中
        submission.at[sample_id, 'sales'] = values

將模型預測的結果(y_predict)映射到測試數據中(pivoted_test),並將預測的銷售值存儲在submission數據框中。


完整的 code 可以去 Kaggle Notebook 實際執行喔~

接下來幾天將進入最後一個主題 Reinforcement Learning !!!

敬請期待 ~

/images/emoticon/emoticon43.gif

Reference


上一篇
[Day 25] Recurrent Neural Network — 主題實作
下一篇
[Day 27] Reinforcement Learning
系列文
ML From Scratch31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言