R ile Zaman Serisi Analizine Giriş

Düzenli bir zaman aralığında ölçülen herhangi bir metrik, bir zaman serisi oluşturmaktadır. Zaman serilerinin analizi, endüstriyel ihtiyaç ve özellikle talep, satış, arz ile ilgisi nedeniyle önemlidir.

Bir zaman serisini sistematik olarak anlamak, analiz etmek, modellemek ve tahmin etmek için bileşenlerine bölünmelidir. Bu yazı, zaman serisi analizine yeni başlayanlar için bir giriş niteliğindedir ve aşağıdaki temel soruları yanıtlar:

  • Bir zaman serisinin bileşenleri nelerdir?
  • Zaman serilerinde durağanlık (stationary) kavramı
  • Zaman serileri parçalara (decompose) nasıl ayrılır?
  • Bir zaman serisi trend (de-trend) ve mevsimsellikten (de-seasonalize) nasıl arındırır?
  • Otokorelasyon nedir?

Zaman Serisi (Time Series) Nedir?

Düzenli zaman aralıklarında ölçülen herhangi bir metrik, bir zaman serisidir. Örnek olarak hava durumu verileri, hisse senedi fiyatları, sanayi tahminleri vb. yaygın olanlarıdır.

R ile Zaman Serisi Analizi

Verileri R’a aktardıktan sonra ts veya xts yapıları kullanılarak zaman serileri oluşturulabilir. Özellikle API kullanılarak dış kaynaklardan direk ulaşılan zaman serileri xts (quantmod, PoloniexR, WDI, …vb.) yapıları ile çalışma ortamımıza (enviroment) dahil olmaktadır.

Örnek bir zaman serisi oluşturmak için uniform dağılıma göre data oluşturalım.

x <- runif(2^4, min = -1, max = 1)

Örneğin 1975 yılının üçüncü çeyrek döneminden başlayan çeyreklik (quarterly) bir zaman serisi oluşturalım.

ts(data = x, frequency = 4, start = c(1975, 3))

Örneğin 2000 yılının haziran ayından başlayan aylık (monthly) bir zaman serisi oluşturalım.

ts(1:10, frequency = 12, start = c(2000,6))

Örneğin 2009 yılından 2014 yılına yıllık (yearly) bir zaman serisi oluşturalım.

ts(x, start=c(2009), end=c(2014), frequency=1)

Öte yandan xts ile oluşturulan zaman serilerine uygun olan pek çok uyumlu kütüphane bulunmaktadır. PerformanceAnalytics, TTR, quantmod bunlardan bazılarıdır. ts fonksiyonu stats kütüphanesi içerisinde olup bu kütüphane R ilk çalıştırıldığında otomatik olarak aktif olmaktadır. Bu nedenle ts fonksiyonunu kullanmak için daha önceki yazılarda yaptığımız gibi bir kütüphane aktif hale getirilmemiştir. Ancak xts yapılarını kullanabilmek için xts kütüphanesinin aktif hale getirilmesi gerektiğinin unutulmaması önemlidir.

Zaman Serileri

Bir zaman serisi t anındaki bir veri için (Yt); mevsimlik (St), trend (Tt) ve Hata (et) (white noise) olmak üzere üç bileşenin bir toplamı ya da bir bileşimi olarak ifade edilebilir.

Eklemeli (Additive) Zaman Serileri

Yt = St + Tt + ϵt

Çarpımlı (Multiplicative) Zaman Serileri

Yt = St × Tt × ϵt

Bir çarpımsal zaman serisi, logaritmik transform ile eklemeli zaman serisine dönüştürülebilir.

additiveTS <- log(multiplcativeTS)

Zaman Serilerinde Durağanlık (stationary) Kavramı

Bir zaman serisinin, aşağıdaki koşulları sağlaması durumunda durağan olduğu söylenir.

  1. Zaman serilerinin ortalama değeri zaman içinde sabittir, yani trend bileşeni geçersiz kılınır.
  2. Varyans zamanla artmaz.
  3. Mevsimsellik etkisi azdır.

Trend, Mevsimsellik ve Error (white noise) Bileşenlerinin Ayrılması

Zaman serilerini bileşenlerine ayırmak için stats kütüphanesi içerisindeki stl ve decompose fonksiyonları kullanılabilir.

datasets kütüphanesi içerisindeki EuStockMarkets datasetini göz önüne alalım. Dataset 1991’den 1998’e günlük olarak DAX, SMI, CAC ve FTSE endekslerinin fiyatlarından oluşmaktadır. DAX endeksini inceleyelim.

decompose fonksiyonu aşağıdaki argümanları almaktadır:
x: zaman serisi objesi
type: additive, multiplicative
filter: NULL, AR, MA, …vb.

tsData <- EuStockMarkets[, "DAX"]

decomposedRes <- decompose(x=tsData, 
                           type="multiplicative")

str(decomposedRes)
## List of 6
##  $ x       : Time-Series [1:1860] from 1991 to 1999: 1629 1614 1607 1621 1618 ...
##  $ seasonal: Time-Series [1:1860] from 1991 to 1999: 1 1 1 1 1 ...
##  $ trend   : Time-Series [1:1860] from 1991 to 1999: NA NA NA NA NA NA NA NA NA NA ...
##  $ random  : Time-Series [1:1860] from 1991 to 1999: NA NA NA NA NA NA NA NA NA NA ...
##  $ figure  : num [1:260] 1 1 1 1 1 ...
##  $ type    : chr "multiplicative"
##  - attr(*, "class")= chr "decomposed.ts"
plot (decomposedRes)

stlRes <- stl(tsData, s.window = "periodic")
head(stlRes$time.series)
##      seasonal    trend remainder
## [1,] 43.19010 1602.604 -17.04460
## [2,] 55.37950 1603.064 -44.81349
## [3,] 61.29141 1603.523 -58.30489
## [4,] 68.44706 1603.983 -51.39003
## [5,] 68.45272 1604.442 -54.73518
## [6,] 70.83962 1604.902 -65.13158

Otokoreasyon (Autocorrelation & Partial-Autocorrelation)

Otokorelasyon (autocorrelation), bir zaman serisinin kendisinin gecikmeleri ile korelasyonudur. Bu önemli bir metriktir çünkü;

  • Zaman serilerinin önceki durumlarının (gecikmiş gözlemler) mevcut durum üzerinde bir etkisi olup olmadığını gösterir. Otokorelasyon grafiğinde, otokorelasyon kesikli mavi çizgiyi aşarsa, spesifik gecikmenin mevcut serilerle önemli ölçüde korele olduğu anlamına gelir. Örneğin, AirPassengers’in otokorelasyon grafiğinde (sol, aşağıda), x ekseni üzerinde gösterilen tüm gecikmeler için önemli bir otokorelasyon mevcuttur.
  • Zaman serilerinin durağan olup olmadığını belirlemek için genel olarak kullanılır.

datasets kütüphanesi içerisindeki AirPassengers pek çok örnekte kullanılan bir örnek datasettir.

par(mfrow=c(1,2))
acfRes <- acf(AirPassengers) 
pacfRes <- pacf(AirPassengers) 

par(mfrow=c(1,1))

datasets kütüphanesi içerisindeki UKLungDeaths dataseti içerisinden kadınlar (fdeaths) ve erkeklerin (mdeaths) belirli hastalıklardan dolayı aylık ölüm sayılarına ait zaman serileri için cross-correlation bulalım.

ccf(mdeaths, fdeaths, ylab = "cross-correlation")

Zaman Serilerinin Trendden Arındırılması (de-trend)

Lineer trend barındıran zaman serilerini trendden arındırmak için sıklıkla doğrusal regresyonu kullanılmaktadır. Ortaya çıkan model kalıntıları, trend yoksun olan zaman serilerinin bir temsilidir.

Bunun haricinde farklı yöntemler kullanılarak zaman serileri lineer ve lineer olmayan trendlerden arındırılabilmektedir: AR(1), fourier ve wavelet dönüşümleri, kalman filtreleri gibi farklı yöntemler kullanılabilir. Öte yandan forecast kütüphanesi içerisindeki seasonaldummy ve fourier fonksiyonları kullanılarak de-trend yapılabilir.

datasets kütüphanesi içersisindeki JohnsonJohnson hisse senedinin 1960-1980 arasındaki çeyreklik datalarını inceleyelim. Model sonucu kalıntılar de-trend edilmiş zaman serisidir.

plot(JohnsonJohnson, type="l", main="JohnsonJohnson")

trModel <- lm(JohnsonJohnson ~ c(1:length(JohnsonJohnson)))
trResid <- resid(trModel)

trModel_AR1 <- arima(x=JohnsonJohnson, order=c(1,0,0))
trResid_AR1 <- resid(trModel_AR1)
par(mfrow=c(1,2))
plot(trResid, type="l", col="blue", main="de-trended (regresyon)")
plot(trResid_AR1,  type="l", col="red", main="de-trended (ar(1))")

Zaman Serilerinin Mevsimsellikten Arındırılması (de-seasonalize)

Zaman serisinin mevsimsellik deseni hakkında fikir verir ve mevsimsel etkiler olmadan verilerin modellenmesine yardımcı olur. Zaman serisini mevsimsellikten arındırmak için aşağıdaki iki adım kullanılabilir.
1. Adım: stl() fonksiyonu ile zaman serisi ayrılır.
2. Adım: forecast kütüphanesi içerisindeki seasadj() fonksiyonu kullanılır.

library(forecast)

#Adım 1
ts_stl <- stl(AirPassengers, "periodic") 
head(ts_stl$time.series)
##            seasonal    trend   remainder
## Jan 1949 -25.497718 127.1873  10.3103699
## Feb 1949 -35.220935 126.6495  26.5714028
## Mar 1949  -3.027478 126.1117   8.9157625
## Apr 1949  -8.299054 126.1989  11.1001224
## May 1949  -5.737289 126.2861   0.4511408
## Jun 1949  32.336634 126.7330 -24.0696572
#Adım 2
ts_sa <- seasadj(ts_stl) 
par(mfrow=c(1,2))
plot(AirPassengers, type="l", main="Airpassengers")  
plot(ts_sa, type="l", main="Seasonal Adjusted")

par(mfrow=c(1,1))
seasonplot(ts_sa, 
           s=12, 
           col=rainbow(12), 
           year.labels=TRUE, 
           main="Seasonal plot: Airpassengers")

Zaman Serilerinde Durağanlık Testleri

Zaman serilerinin durağanlığının incelenmesi için tseries kütüphanesi içerisindeki Augmented Dickey-Fuller (adf.test), Phillips–Perron birim kök testi (pp.test) ve Kwiatkowski-Phillips-Schmidt-Shin (KPSS) test (kpss.test) kullanılabilir.

adf.test ve pp.test için:
H0: birim kök içerir.
HA: birim kök içermez, durağandır.

kpss.test için:
H0: level veya trend durağandır.
HA: durağan değildir.

Test sonuçlarına göre p-value (test istatistiğinin olasılık değeri) %5’den küçük ise (%95 güven seviyesinde) testin boş hipotezi ret edilir. Buna göre incelendiğinde daha önce kullandığımız DAX datasının her üç teste göre de durağan olmadığı görülmektedir.

library(tseries)

tsData <- EuStockMarkets[,"DAX"]

adf.test(tsData)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  tsData
## Dickey-Fuller = -0.82073, Lag order = 12, p-value = 0.9598
## alternative hypothesis: stationary
kpss.test(tsData, null="Trend")
## 
##  KPSS Test for Trend Stationarity
## 
## data:  tsData
## KPSS Trend = 3.3323, Truncation lag parameter = 9, p-value = 0.01
pp.test(tsData)
## 
##  Phillips-Perron Unit Root Test
## 
## data:  tsData
## Dickey-Fuller Z(alpha) = -0.79232, Truncation lag parameter = 8,
## p-value = 0.99
## alternative hypothesis: stationary

Zaman Serilerini Durağanlaştırma

Bir zaman serisinin farkının alınması, serideki her veri noktasını ardılından çıkarılması anlamına gelir. Genellikle zaman serisilerini durağanlaştırmak için kullanılır. Çoğu zaman serisi deseni için 1 veya 2 farklandırma yeterlidir. Fakat zaman serileri mevsimsellik gösteriyorsa, mevsim etkisini ortadan kaldırmak için ilgili sezonun veri noktalarıyla olan fark daha iyi bir yaklaşım gösterir. Bu işlemden sonra, gerekirse, birbirini izleyen veri noktalarıyla tekrar fark alınır.

Ne kadar fark alınacağı nasıl belirlenir? forecast kütüphanesi içerisindeki nsdiff ve ndiff fonksiyonları ile durağanlaştırma için gerekli adım sayıları bulunabilir.

AirPassangers dataseti için mevsimsel fark adedini öğrenmek için nsdiff fonksiyonunu kullanılmıştır. Ardından dif fonksiyonu mevsimsel fark alınmış ve grafik oluşturulmuştur.

# Mevsimsel Fark
nsdiffs(AirPassengers)
## [1] 1
AirPassengers_seasdiff <- diff(AirPassengers, 
                               lag=frequency(AirPassengers), 
                               differences=1)

plot(AirPassengers_seasdiff, type="l", main="Seasonally Differenced") 

Zaman serisi şuan mevsimsellikten arındırılmıştır ancak seri durağan mıdır? Bunun için ndiff fonksiyonunu kullanabiliriz. ndiff fonksiyonu bize serinin durağanlaştırılması için 1 farkının alınmaını işaret etmektedir.

ndiffs(AirPassengers_seasdiff)
## [1] 1
stationaryTS <- diff(AirPassengers_seasdiff, 
                     differences= 1)

plot(stationaryTS, type="l", main="Differenced and Stationary")