17 Ekim 2017 Salı

Keras LSTM ile Zaman Serisi Tahmini

Daha önceki bir yazımda ARIMA ile zaman serisi tahminine dair bir örnek paylaşmıştım. Bu yazı kapsamında ise Keras LSTM katmanı kullanarak zaman serisi tahmini yapan bir uygulama gerçekleştireceğim. LSTM ile ilgili daha ayrıntılı bilgi almak için, benim de bu yazıya referans olarak kullandığım derindelimavi adresindeki yazıyı okuyabilirsiniz. 

Uygulamamız için kullanacağımız veri seti ARIMA örneğindeki ile aynı, 1949-1961 yılları arasında aylara göre taşınan yolcu sayılarından oluşmakta.


LSTM 'nin açılımı Long Short-Term Memory , ve bir çeşit RNN (Recurrent Neural Network) yapısında bir sinir ağı modeli. Bu modelde bir hafıza hücresi de kullanılarak bir önceki zamandan gelen bilgi sonrakine aktarılabiliyor. Zaten zaman serilerinde istenen şey de zamana bağlı bir değişkenin önceki değerlerine bakarak geleceği tahmin etmek. Şimdi yavaş yavaş koda başlayalım ve ilk olarak veri setimizi okuyalım.
import pandas as pd
import numpy as np
import matplotlib.pylab as plt 
import matplotlib.patches as mpatches
from keras.layers.core import Dense,Activation,Dropout,Flatten,Reshape
from keras.layers import LSTM
from keras.models import Sequential
from sklearn.preprocessing import MinMaxScaler

data_orjinal = pd.read_csv('AirPassengers.csv')
data_orjinal = data_orjinal['#Passengers']


LSTM veri ölçeğine son derece bağımlı bu sebeple verimizi 0-1 arasına ölçeklememiz/normalize etmemiz lazım, en son ters dönüşüm ile tekrar gerçek ölçeğe çevireceğiz.
scaler = MinMaxScaler(feature_range=(0,1))
ts = scaler.fit_transform(data_orjinal)

Şimdi ise veri setimizi eğitim ve test için parçalara ayıralım. Daha önceki keras sınıflandırma örneğinde cross-validation ile daha sağlıklı bir değerlendirme yapılacağından bahsetmiştik, zaman serisi problemi için ise verilerin sırası önemli olduğundan bu şekilde bir rastgele parçalara ayırma işlemi gerçekleştirmiyoruz. Verisetini LSTM için uygun girdi formatına çevirip, eğitim ve test verilerini oluşturuyoruz. (144 aylık veri mevcut, 70'ini eğitim için ayırdık).
timestep=3
X=[]
Y=[]

data = ts

for i in range(len(data)-timestep):
    X.append(data[i:i+timestep])
    Y.append(data[i+timestep])

X = np.asanyarray(X)
Y = np.asanyarray(Y)

X = X.reshape((X.shape[0],X.shape[1],1))


k = 70
Xtrain = X[:k,:,:]
Ytrain = Y[:k]

Xtest = X[k:,:,:]
Ytest = Y[k:]

timestep değişkeni giriş verisinin büyüklüğünü belirliyor. Bu değeri 3 ayarladık, böylece önceki 3 değere bakarak sonraki değer tahmin edilmeye çalışılacak. İki LSTM katmanını 0.2'lik Dropout katmanı ile birlikte modelimize ekleyelim. Dropout katmanı overfitting 'i yani sistemin eğitim verisini aşırı ezberlemesini engellemek için kullanılan bir katman. 
model = Sequential()
model.add(LSTM(64,batch_input_shape=(None,timestep,1),return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(32,return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(1))

model.compile(loss='mse',optimizer='rmsprop')
model.fit(Xtrain, Ytrain, batch_size=512, epochs=50)

Modelimizi kurduk ve eğitim verisi ile ağı eğittik. Artık tahmin işlemi yapıp sonuçları elde edebiliriz. Bu noktada tahmin edilen değerleri ters dönüşüm ile yeniden ölçekleyeceğimizi hatırlatmak istiyorum.
Ypred = model.predict(X)

Ypred = scaler.inverse_transform(Ypred)
Ypred = Ypred[:,0]

Ve son olarak gerçek değerler ile tahmin edilen değerleri karşılaştıralım.
Yreel = data_orjinal[timestep:].values

plt.plot(Yreel,label='Yreel',color='blue')
plt.plot(Ypred,label='Ypred',color='red')

blue_patch = mpatches.Patch(color='blue', label='Yreel')
red_patch = mpatches.Patch(color='red', label='Ypred')
plt.legend(handles=[blue_patch,red_patch])
plt.title('RMSE: %.4f'% np.sqrt(sum((Ypred-Yreel)**2)/len(Yreel)))
plt.show()


RMSE hata oranını grafiğin üstünde yazdırdık, gerçek değer ile tahmin edilen değerin benzer grafik gösterdiğini söyleyebiliriz. Daha iyi bir karşılaştırma için daha önceki ARIMA ile zaman serisi inceleme yazımızda elde ettiğimiz grafiği de paylaşmak istiyorum.
RMSE hata değerine bakacak olursak, LSTM ile ARIMA'ya kıyasla gerçeğe daha yakın sonuç elde ettik. 

Böylece Keras ile LSTM ağ yapısını kullanarak zaman serisi tahmininin nasıl yapılacağına dair bir örnek uygulama gerçekleştirmiş olduk.

Ve son olarak tüm kodları bir arada paylaşıyorum...
"""
Created on Mon Oct 16 17:50:41 2017

@author: IbrahimD
"""
import pandas as pd
import numpy as np
import matplotlib.pylab as plt 
import matplotlib.patches as mpatches
from keras.layers.core import Dense,Activation,Dropout,Flatten,Reshape
from keras.layers import LSTM
from keras.models import Sequential
from sklearn.preprocessing import MinMaxScaler

data_orjinal = pd.read_csv('AirPassengers.csv')
data_orjinal = data_orjinal['#Passengers']

scaler = MinMaxScaler(feature_range=(0,1))
ts = scaler.fit_transform(data_orjinal)
          
seed = 7
np.random.seed(seed)

timestep=3
X=[]
Y=[]

data = ts

for i in range(len(data)-timestep):
    X.append(data[i:i+timestep])
    Y.append(data[i+timestep])

X = np.asanyarray(X)
Y = np.asanyarray(Y)

X = X.reshape((X.shape[0],X.shape[1],1))


k = 70
Xtrain = X[:k,:,:]
Ytrain = Y[:k]

Xtest = X[k:,:,:]
Ytest = Y[k:]

model = Sequential()
model.add(LSTM(64,batch_input_shape=(None,timestep,1),return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(32,return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(1))


model.compile(loss='mse',optimizer='rmsprop')
model.fit(Xtrain, Ytrain, batch_size=512, epochs=50)

Ypred = model.predict(X)

Ypred = scaler.inverse_transform(Ypred)
Ypred = Ypred[:,0]

Yreel = data_orjinal[timestep:].values

plt.plot(Yreel,label='Yreel',color='blue')
plt.plot(Ypred,label='Ypred',color='red')

blue_patch = mpatches.Patch(color='blue', label='Yreel')
red_patch = mpatches.Patch(color='red', label='Ypred')
plt.legend(handles=[blue_patch,red_patch])
plt.title('RMSE: %.4f'% np.sqrt(sum((Ypred-Yreel)**2)/len(Yreel)))
plt.show()



1 yorum: