Time Series adalah salah satu teknik machine learning yang digunakan untuk evaluasi atau membuat keputusan. Time series akan mempelajari data sebelumnya berdasarkan waktu dan pola (pattern) yang ada.

Time series membuat model untuk memprediksi masa depan berdasarkan nilai dari data sebelumnya atau bisa disebut dengan forecasting.


Mempersiapkan Data


Untuk membuat sebuah model machine learning, seperti biasa kita akan menyiapkan data. Data kali ini kita ambil dari Kaggle.com. Kita akan mencoba memprediksi penjualan saham sepeda berdasarkan rentang waktu yang ditentukan.

Download Dataset (Londong Bike Sharing)

Masukan dataset ke dalam dataframe dengan mengubah format waktu pada dataset.

import panda as pd

url = '/content/drive/My Drive/datasets/London bike sharing dataset/london_merged.csv'
data = pd.read_csv(url, parse_dates=['timestamp'], index_col='timestamp')

Jika kita lihat, hasilnya kira - kira akan seperti ini :

“Tampilan Data Saham Penjualan Sepeda”
Tampilan Data Saham Penjualan Sepeda

Parameter parse_date akan mengubah format waktu menjadi format kolom pada dataframe. Hal ini dilakukan agar format waktu dapat dimanipulasi dengan mudah.

Selanjutnya kita dapat melakukan checking data, untuk menentukan apakah di dalam dataframe terdapat error atau nilai null.

data.isnull().sum()

“Tampilan Data Jumlah Null dan Error”
Tampilan Data Jumlah Null dan Error

Dengan menggunakan kombinasi parameter isnull() dan sum() maka dataframe akan menghitung jumlah data yang memiliki nilai null.

Kita tambahkan kolom baru dengan datanya nanti akan berhubungan dengan waktu, contoh data yang akan kita tampung adalah data jam, hari, bulan, dan tahun.

data['hour'] = data.index.hour
data['day_of_week'] = data.index.dayofweek
data['day_of_month'] = data.index.day
data['month'] = data.index.month

Pada data timestamp yang tadi telah di buat, kita dapat mengambil data waktu tertentu seperti jam, hari, bulan, atau tahun. Nilai yang di ambil kita masukan Kembali ke dalam dataframe dalam bentuk kolom.

“Data Dengan Penambahan Kolom Jam, Hari, Bulan”
Data Dengan Penambahan Kolom Jam, Hari, Bulan

Jika kita lihat datanya, dataframe mendapatkan 4 kolom baru sesuai dengan nilai waktu yang kita deklarasikan.


Dataframe Exploring


Sebelum kita membuat model, kita dapat melakukan exploring data terlebih dahulu. Exploring data sangat berguna untuk mempelajari pattern dasar pada data. Dengan exploring data kita juga dapat mencari informasi-informasi sederhana yang akan digunakan sebagai dasar dalam mencari informasi-informasi selanjutnya.

Kita akan mencoba melihat grafik penjualan saham sepeda setiap bulan, dengan membuat dataframe lain yang diurutkan setiap bulan.

import matplotlib.pyplot

data_by_month = data.resample('M').sum()

time = data_by_month.index.values
test = data_by_month['cnt'].values

plt.figure(figsize=(15,5))
plt.plot(time, test)

Fungsi resample() akan mengambil sample data waktu yang ada pada dataset. Lalu, kita bagi data menjadi time sebagai waktu dan test sebagai data penjualannya dan menampilkannya dalam bentuk grafik dengan plot().

“Tampilan Grafik Penjualan Setiap Bulan”
Tampilan Grafik Penjualan Setiap Bulan

Jika kita lihat grafik diatas, terlihat dengan jelas penjualan diawal tahun 2015 naik pada tahun 2016 tetapi turun pada tahun 2017.


Data Splitting


Kali ini data akan dibagi menggunakan fungsi train_test_split(), tetapi kita akan berikan parameter iloc agar data tidak teracak. Jika data teracak, maka data kita akan sulit untuk dipelajari oleh mesin.

from sklearn.model_selection import train_test_split
import numpy as np

train_size = int(len(data) * 0.8) # bobot 80%
train, test = data.iloc[0:train_size], data.iloc[train_size:len(data)]

print(train.shape, test.shape)

Data akan dibagi 80% data awal sebagai data untuk training dan sisanya 20% untuk testing.

Sebelum di lakukan splitting, data akan kita normalisasi data dengan RobustScaler() untuk menghilangkan rata-rata dan skala pada nilai-nilai yang ada.

from sklearn.preprocessing import RobustScaler

transformer = RobustScaler()
cnt_transformer = transformer.fit(train[['cnt']])

train['cnt'] = cnt_transformer.transform(train[['cnt']])

test['cnt'] = cnt_transformer.transform(test[['cnt']])

Dengan fungsi fit(), data akan menghasilkan nilai median dan kuartil yang nantinya akan digunakan untuk mengukur data.

“Process Fitting Dengan RobustScaler”
Process Fitting Dengan RobustScaler

Setelah selesai dengan proses fit() selanjutnya kita akan menormalisasi data dengan fungsi transform().

scale_col = ['t1', 't2', 'hum', 'wind_speed']
scale_transformer = transformer.fit(train[scale_col].to_numpy())

train.loc[:, scale_col] = scale_transformer.transform(
    train[scale_col].to_numpy()
)

test.loc[:, scale_col] = scale_transformer.transform(
    test[scale_col].to_numpy()
)

“Process Transformasi Dengan RobustScaler”
Process Transformasi Dengan RobustScaler

Fungsi transform() akan mengukur data, lalu mengganti nilai tengah (center value) ke nilai tengah yang baru, dengan cara mengukur nilai tengah yang baru berdasarkan jarak kuartil yang ada di dalam data tersebut.

Lalu, untuk splitting data kita akan membuat fungsi sendiri agar data yang kita split sesuai dengan keingingnan kita. Kita namakan fungsi split_data(), dan kode nya seperti di bawah.

import numpy as np
import tensorflow as tf

def split_data(x, y, time_steps=1):
    xs, ys, [], []
    for i in range(len(x) - time_steps):
        v = x.iloc[i:(i + time_steps)].values
        xs.append(v)
        ys.append(y.iloc[i + time_steps])
    return np.array(xs), np.array(ys)

x_train, y_train = split_data(train, train.cnt, 10)
x_test, y_test = split_data(test, test.cnt, 10)

print(x_train_shape, y_train_shape)

Output :

(13921, 10, 13) (13921,)

Dalam fungsi split_data() memiliki parameter x , y dan time_steps. Parameter x itu adalah data asli, sedangkan parameter y adalah data yang sudah di transform. Dan untuk time_steps digunakan untuk menentukan pembagian data setiap segmen.

Data yang telah di normalisasi tadi, akan terbagi dengan fungsi split_data() dan bentuknya akan berubah sesuai dengan waktu yang diberikan. Dalam kasus ini data akan dibagi 10 pada setiap segmennya.


Calbacks


Buat apa Keras callbacks pada model kita? Keras Callbacks membantu kita dalam menangani bug secara lebih lebih cepat serta membantu dalam membuat model kita lebih baik lagi. Dia juga dapat memvisualisasikan model training yang berjalan, serta mencegah lebih awal terjadinya overfitting.

Kali ini kita akan membuat callbacks secara manual dengan memanggil objek Callback dari keras.

class my_allback(tf.keras.callbacks.Callback):
    def on_epoch_end(self, epoch, logs={}):
        if(logs.get('mae') < 0.1):
            print("MAE has reached below 10%")

    def on_train_end(self, epoch, logs={}):
        print('Done')

callbacks = my_allback()

fungsi on_epoch_end() akan menjalankan fungsi callbacks setiap satu epoch selesai dijalankan dalam sekali training dan fungsi on_train_end() akan menjalankan fungsi saat training selesai dijalankan.

Mean Absolute Error atau MAE adalah salah satu metrics yang digunakan untuk menghitung kualitas dari suatu model machine learning. MAE akan menghitung rata-rata dari jumlah error yang terjadi pada sebuah model.


Modeling


Model machine learning yang akan kita rancang, dilakukan secara manual dengan menggunakan model Sequential dan dengan menambahkan 2 layer LSTM.

model = tf.keras.models.Sequential([
    tf.keras.layers.LSTM(128,return_sequences=True),
    tf.keras.layers.LSTM(128),
    tf.keras.layers.Dropout(rate=0.2),
    tf.keras.layers.Dense(30, activation="relu"),
    tf.keras.layers.Dense(30, activation="relu"),
    tf.keras.layers.Dense(1)
])

LSTM adalah Long Short-Term Memory yaitu, salah satu layer yang menggunakan deep learning untuk memecahkan masalah yang rumit seperti machine translation, speech recognition, dan lainnya.

Jika menggunakan 2 layer LSTM, maka layer pertama harus diberikan parameter return_sequences yang bernilai True.

model.compile(loss = tf.keras.losses.Huber(),
              optimizer = tf.keras.optimizers.Adam(lr=0.01),
              metrics = ["mae"])

Kali ini, compiling kita akan menggunakan nilai “hubber” pada parameter loss, Lalu nilai “Adam” sebagai optimizer dan nilai “mae” sebagai metrics.


Training Data


Selanjutanya kita training model awal dengan melakukan 50 epoch dan parameter shuffle diberi nilai False agar data tidak teracak.

history = model.fit(x_train,
                    y_train,
                    epochs=50,
                    batch_size=32,
                    validation_split=0.2,
                    callbacks = callbacks,
                    shuffle=False)

Evaluating Model


Lalu yang terakhir, kita akan membuat fungsi dibawah untuk melihat progress dari pelatihan yang telah kita lakukan.

def show_final_history(history):
    fig, ax = plt.subplots(1, 2, figsize(15,5))
    ax[0].set_titles('LOSS')
    ax[0].plot(history.epoch, history.history["loss"], label="Train Loss")
    ax[0].plot(history.epoch, history.history["val_loss"], label="Validation Loss")
    ax[1].set_title('MAE')
    ax[1].plot(history.epoch, history.history["mae"], label="Mae")
    ax[1].plot(history.epoch, history.history["val_mae"], label="Validation Mae")
    ax[0].legend()
    ax[1].legend()

show_final_history(history)

&ldquo;Grafik Perbandingan LOSS dan MAE&rdquo;
Grafik Perbandingan LOSS dan MAE

Terlihat error pada loss dan metrics mae turun secara perlahan, hal ini menandakan bahwa model yang kita buat cukup bagus. Mungkin dibutuhkan lebih banyak epoch untuk mendapatkan hasil yang lebih maksimal.

. . .

Sekian untuk pembahasan cara membuat model machine learning time series analysis. Untuk hasil kode notebook nya akan saya post di github AnbiDev. Terima kasih.