Kurs
Giriş
Hareketli ortalama, kayan veya koşan ortalama olarak da adlandırılır, tüm veri kümesinin farklı alt kümelerinin ortalamalarını hesaplayarak zaman serisi verilerini analiz etmek için kullanılır. Zaman içinde veri kümesinin ortalamasını almak söz konusu olduğundan, hareketli ortalama (MM) veya kayan ortalama olarak da adlandırılır.
Kayan ortalama çeşitli şekillerde hesaplanabilir, ancak bu yollardan biri, sayıların tam bir serisinden sabit bir alt küme almaktır. İlk hareketli ortalama, sayıların ilk sabit alt kümesinin ortalaması alınarak hesaplanır ve ardından alt küme, bir sonraki sabit alt kümeye doğru ilerletilerek değiştirilir (alt gruba gelecekteki değeri dahil ederken seriden bir önceki sayıyı hariç tutar).
Hareketli ortalama çoğunlukla, daha uzun vadeli eğilimlere odaklanırken kısa vadeli dalgalanmaları yakalamak için zaman serisi verileriyle birlikte kullanılır.
Zaman serisi verilerine birkaç örnek olarak hisse senedi fiyatları, hava durumu raporları, hava kalitesi, gayri safi yurtiçi hasıla, istihdam vb. verilebilir.
Genel olarak, hareketli ortalama veriyi pürüzsüzleştirir.
Hareketli ortalama birçok algoritmanın bel kemiğidir; bunlardan biri, zaman serisi verileri için tahminler yapmak üzere hareketli ortalamaları kullanan Otoregresif Bütünleşik Hareketli Ortalama Modeli (ARIMA)’dır.
Çeşitli hareketli ortalama türleri vardır:
-
Basit Hareketli Ortalama (SMA): Basit Hareketli Ortalama (SMA), belirli sayıda zaman periyodu boyunca ortalama almak için kayan bir pencere kullanır. Önceki n verinin eşit ağırlıklı ortalamasıdır.
SMA’yı daha iyi anlamak için bir örnek ele alalım; n değerden oluşan bir dizi:

o hâlde n veri noktası için eşit ağırlıklı kayan ortalama, kayan pencerenin boyutu M olmak üzere, esasen önceki M veri noktasının ortalamasıdır:

Benzer şekilde, sonraki kayan ortalama değerlerini hesaplarken toplama yeni bir değer eklenecek ve önceki zaman periyodu değeri çıkarılacaktır; çünkü önceki periyotların ortalaması elinizde olduğundan her seferinde tam toplamı almak gerekmez:

- Kümülatif Hareketli Ortalama (CMA): Yeni bir gözlem eklendikçe en eski gözlemi dışlayan basit hareketli ortalamanın aksine, kümülatif hareketli ortalama önceki tüm gözlemleri dikkate alır. CMA, eğilimleri analiz etmek ve veriyi pürüzsüzleştirmek için çok iyi bir teknik değildir. Bunun nedeni, mevcut veri noktasına kadar olan tüm önceki verilerin ortalamasını almasıdır; yani n değerinden oluşan dizinin eşit ağırlıklı ortalaması:
mevcut zamana kadar şu şekilde verilir:
Benzer şekilde, her yeni değer geldiğinde kümülatif ortalamayı güncellemek aşağıdaki formülle hesaplanabilir:

- Üssel Hareketli Ortalama (EMA): SMA ve CMA’nın aksine, üssel hareketli ortalama son fiyatlara daha fazla ağırlık verir ve bunun sonucu olarak, eğilimin hareketini daha hızlı bir şekilde daha iyi modelleyebilir veya daha iyi yakalayabilir. EMA’nın tepkisi, verinin desenine doğru orantılıdır.
EMA’lar eski verilere kıyasla yeni verilere daha yüksek ağırlık verdiğinden, SMA’lara kıyasla en son fiyat değişikliklerine daha duyarlıdır; bu da EMA’dan elde edilen sonuçları daha zamanında kılar ve dolayısıyla EMA diğer tekniklere göre daha çok tercih edilir.
Yeterince teori oldu, değil mi? Hadi hareketli ortalamanın pratik uygulamasına geçelim.
Zaman Serisi Verilerinde Hareketli Ortalama Uygulaması
Basit Hareketli Ortalama (SMA)
Önce, sahte bir zaman serisi verisi oluşturalım ve yalnızca Python kullanarak SMA’yı uygulamayı deneyelim.
Bir ürün için talep olduğunu ve bunun 12 ay (1 Yıl) boyunca gözlemlendiğini varsayın; 3 ve 4 aylık pencere periyotları için hareketli ortalamaları bulmanız gerekiyor.
Modül içe aktar
import pandas as pd
import numpy as np
product = {'month' : [1,2,3,4,5,6,7,8,9,10,11,12],'demand':[290,260,288,300,310,303,329,340,316,330,308,310]}
df = pd.DataFrame(product)
df.head()
Bu eğitimdeki kodu çevrimiçi olarak çalıştırın ve düzenleyin
Kodu çalıştır| month | demand | |
|---|---|---|
| 0 | 1 | 290 |
| 1 | 2 | 260 |
| 2 | 3 | 288 |
| 3 | 4 | 300 |
| 4 | 5 | 310 |
Şimdi pencere boyutu 3 için SMA’yı hesaplayalım; bu, her seferinde hareketli ortalamayı hesaplamak için üç değeri dikkate alacağınız ve her yeni değer için en eski değerin göz ardı edileceği anlamına gelir.
Bunu uygulamak için pandas iloc fonksiyonunu kullanacaksınız; çünkü ihtiyacınız olan sütun demand, bunu iloc fonksiyonunda sabitleyecek, satırı ise veri çerçevesinin sonuna ulaşana kadar yineleyeceğiniz değişken i yapacaksınız.
for i in range(0,df.shape[0]-2):
df.loc[df.index[i+2],'SMA_3'] = np.round(((df.iloc[i,1]+ df.iloc[i+1,1] +df.iloc[i+2,1])/3),1)
| month | demand | SMA_3 | |
|---|---|---|---|
| 0 | 1 | 290 | NaN |
| 1 | 2 | 260 | NaN |
| 2 | 3 | 288 | 279.3 |
| 3 | 4 | 300 | 282.7 |
| 4 | 5 | 310 | 299.3 |
Sağlama yapmak için, dahili pandas rolling fonksiyonunu da kullanalım ve özel Python tabanlı basit hareketli ortalamamızla eşleşip eşleşmediğine bakalım.
df['pandas_SMA_3'] = df.iloc[:,1].rolling(window=3).mean()
df.head()
| month | demand | SMA_3 | pandas_SMA_3 | |
|---|---|---|---|---|
| 0 | 1 | 290 | NaN | NaN |
| 1 | 2 | 260 | NaN | NaN |
| 2 | 3 | 288 | 279.3 | 279.333333 |
| 3 | 4 | 300 | 282.7 | 282.666667 |
| 4 | 5 | 310 | 299.3 | 299.333333 |
Harika, gördüğünüz gibi özel ve pandas hareketli ortalamaları birebir örtüşüyor; bu da SMA uygulamanızın doğru olduğu anlamına gelir.
Hadi, window_size 4 için de hızlıca basit hareketli ortalamayı hesaplayalım.
for i in range(0,df.shape[0]-3):
df.loc[df.index[i+3],'SMA_4'] = np.round(((df.iloc[i,1]+ df.iloc[i+1,1] +df.iloc[i+2,1]+df.iloc[i+3,1])/4),1)
df.head()
| month | demand | SMA_3 | pandas_SMA_3 | SMA_4 | |
|---|---|---|---|---|---|
| 0 | 1 | 290 | NaN | NaN | NaN |
| 1 | 2 | 260 | NaN | NaN | NaN |
| 2 | 3 | 288 | 279.3 | 279.333333 | NaN |
| 3 | 4 | 300 | 282.7 | 282.666667 | 284.5 |
| 4 | 5 | 310 | 299.3 | 299.333333 | 289.5 |
df['pandas_SMA_4'] = df.iloc[:,1].rolling(window=4).mean()
df.head()
| month | demand | SMA_3 | pandas_SMA_3 | SMA_4 | pandas_SMA_4 | |
|---|---|---|---|---|---|---|
| 0 | 1 | 290 | NaN | NaN | NaN | NaN |
| 1 | 2 | 260 | NaN | NaN | NaN | NaN |
| 2 | 3 | 288 | 279.3 | 279.333333 | NaN | NaN |
| 3 | 4 | 300 | 282.7 | 282.666667 | 284.5 | 284.5 |
| 4 | 5 | 310 | 299.3 | 299.333333 | 289.5 | 289.5 |
Şimdi, hesapladığınız hareketli ortalamaların verisini görselleştireceksiniz.
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=[15,10])
plt.grid(True)
plt.plot(df['demand'],label='data')
plt.plot(df['SMA_3'],label='SMA 3 Months')
plt.plot(df['SMA_4'],label='SMA 4 Months')
plt.legend(loc=2)
<matplotlib.legend.Legend at 0x11fe15080>

Kümülatif Hareketli Ortalama
Artık gerçek bir veri kümesine geçmeye hazır olduğumuzu düşünüyorum.
Kümülatif hareketli ortalama için, bu bağlantıdan indirilebilen bir hava kalitesi veri kümesini kullanalım.
df = pd.read_csv("AirQualityUCI/AirQualityUCI.csv", sep = ";", decimal = ",")
df = df.iloc[ : , 0:14]
df.head()
| Date | Time | CO(GT) | PT08.S1(CO) | NMHC(GT) | C6H6(GT) | PT08.S2(NMHC) | NOx(GT) | PT08.S3(NOx) | NO2(GT) | PT08.S4(NO2) | PT08.S5(O3) | T | RH | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 10/03/2004 | 18.00.00 | 2.6 | 1360.0 | 150.0 | 11.9 | 1046.0 | 166.0 | 1056.0 | 113.0 | 1692.0 | 1268.0 | 13.6 | 48.9 |
| 1 | 10/03/2004 | 19.00.00 | 2.0 | 1292.0 | 112.0 | 9.4 | 955.0 | 103.0 | 1174.0 | 92.0 | 1559.0 | 972.0 | 13.3 | 47.7 |
| 2 | 10/03/2004 | 20.00.00 | 2.2 | 1402.0 | 88.0 | 9.0 | 939.0 | 131.0 | 1140.0 | 114.0 | 1555.0 | 1074.0 | 11.9 | 54.0 |
| 3 | 10/03/2004 | 21.00.00 | 2.2 | 1376.0 | 80.0 | 9.2 | 948.0 | 172.0 | 1092.0 | 122.0 | 1584.0 | 1203.0 | 11.0 | 60.0 |
| 4 | 10/03/2004 | 22.00.00 | 1.6 | 1272.0 | 51.0 | 6.5 | 836.0 | 131.0 | 1205.0 | 116.0 | 1490.0 | 1110.0 | 11.2 | 59.6 |
Veriyle çalışırken ön işleme her zaman gerekli bir adımdır. Sayısal veriler için en yaygın ön işleme adımlarından biri NaN (Null) değerlerini kontrol etmektir. Eğer herhangi bir NaN değeri varsa, bunları 0 ile veya ortalama ile ya da önceki/sonraki değerlerle değiştirebilir veya hatta düşürebilirsiniz. Değiştirmek genellikle düşürmeye kıyasla daha iyi bir seçenektir; ancak bu veri kümesinde birkaç AŞK (NULL) değer bulunduğundan, bunları düşürmek serinin sürekliliğini etkilemeyecektir.
df.isna().sum()
Date 114
Time 114
CO(GT) 114
PT08.S1(CO) 114
NMHC(GT) 114
C6H6(GT) 114
PT08.S2(NMHC) 114
NOx(GT) 114
PT08.S3(NOx) 114
NO2(GT) 114
PT08.S4(NO2) 114
PT08.S5(O3) 114
T 114
RH 114
dtype: int64
Yukarıdaki çıktıya göre, tüm sütunlarda yaklaşık 114 NaN değeri olduğunu görebilirsiniz; ancak bunların hepsinin zaman serisinin sonunda yer aldığını fark edeceksiniz, o hâlde hızlıca bunları düşürelim.
df.dropna(inplace=True)
df.isna().sum()
Date 0
Time 0
CO(GT) 0
PT08.S1(CO) 0
NMHC(GT) 0
C6H6(GT) 0
PT08.S2(NMHC) 0
NOx(GT) 0
PT08.S3(NOx) 0
NO2(GT) 0
PT08.S4(NO2) 0
PT08.S5(O3) 0
T 0
RH 0
dtype: int64
Kümülatif hareketli ortalamayı Sıcaklık sütununa (T) uygulayacaksınız, o hâlde bu sütunu tüm veriden hızlıca ayıralım.
df_T = pd.DataFrame(df.iloc[:,-2])
df_T.head()
| T | |
|---|---|
| 0 | 13.6 |
| 1 | 13.3 |
| 2 | 11.9 |
| 3 | 11.0 |
| 4 | 11.2 |
Şimdi, yukarıdaki verinin kümülatif ortalamasını bulmak için pandas expanding metodunu kullanacaksınız. Giriş bölümünden hatırlarsanız, basit hareketli ortalamanın aksine, kümülatif hareketli ortalama, ortalamayı hesaplarken önceki tüm değerleri dikkate alır.
df_T['CMA_4'] = df_T.expanding(min_periods=4).mean()
df_T.head(10)
| T | CMA_4 | |
|---|---|---|
| 0 | 13.6 | NaN |
| 1 | 13.3 | NaN |
| 2 | 11.9 | NaN |
| 3 | 11.0 | 12.450000 |
| 4 | 11.2 | 12.200000 |
| 5 | 11.2 | 12.033333 |
| 6 | 11.3 | 11.928571 |
| 7 | 10.7 | 11.775000 |
| 8 | 10.7 | 11.655556 |
| 9 | 10.3 | 11.520000 |
Zaman serisi verileri zamana göre çizilir, bu yüzden tarih ve saat sütunlarını birleştirip bir datetime nesnesine dönüştürelim. Bunu başarmak için Python’daki datetime modülünü kullanacaksınız (Kaynak: Zaman Serisi Eğitimi).
import datetime
df['DateTime'] = (df.Date) + ' ' + (df.Time)
df.DateTime = df.DateTime.apply(lambda x: datetime.datetime.strptime(x, '%d/%m/%Y %H.%M.%S'))
temperature veri çerçevesinin indeksini datetime ile değiştirelim.
df_T.index = df.DateTime
Şimdi, gerçek sıcaklık ile kümülatif hareketli ortalamayı zamana göre çizelim.
plt.figure(figsize=[15,10])
plt.grid(True)
plt.plot(df_T['T'],label='temperature')
plt.plot(df_T['CMA_4'],label='CMA_4')
plt.legend(loc=2)
<matplotlib.legend.Legend at 0x1210a2d30>

Üssel Hareketli Ortalama
df_T['EMA'] = df_T.iloc[:,0].ewm(span=40,adjust=False).mean()
df_T.head()
| T | CMA_4 | EMA | |
|---|---|---|---|
| DateTime | |||
| 2004-03-10 18:00:00 | 13.6 | NaN | 13.600000 |
| 2004-03-10 19:00:00 | 13.3 | NaN | 13.585366 |
| 2004-03-10 20:00:00 | 11.9 | NaN | 13.503153 |
| 2004-03-10 21:00:00 | 11.0 | 12.45 | 13.381048 |
| 2004-03-10 22:00:00 | 11.2 | 12.20 | 13.274655 |
plt.figure(figsize=[15,10])
plt.grid(True)
plt.plot(df_T['T'],label='temperature')
plt.plot(df_T['CMA_4'],label='CMA_4')
plt.plot(df_T['EMA'],label='EMA')
plt.legend(loc=2)
<matplotlib.legend.Legend at 0x14b2a41d0>

Vay canına! Yukarıdaki grafikten de görebileceğiniz gibi, Üssel Hareketli Ortalama (EMA) verinin desenini yakalamada mükemmel bir iş çıkarırken, Kümülatif Hareketli Ortalama (CMA) kayda değer ölçüde geride kalıyor.
Daha da ileri gidin!
Eğitimi tamamladığınız için tebrikler.
Bu eğitim, verilerinizin hareketli ortalamalarını nasıl hesaplayabileceğinize ve onlardan nasıl anlam çıkarabileceğinize dair iyi bir başlangıçtı.
Pandas kütüphanesini kullanmadan kümülatif ve üssel hareketli ortalama Python kodunu yazmayı deneyin. Bu, nasıl hesaplandıklarına ve birbirlerinden hangi açılardan farklı olduklarına dair çok daha derin bir bilgi sağlayacaktır.
Hâlâ denenecek çok şey var. Girdi verisi ile hareketli ortalama arasındaki kısmi otokorelasyonu hesaplamayı deneyin ve ikisi arasında bir ilişki bulmaya çalışın.
pandas’ta DataFrame’ler hakkında daha fazla bilgi edinmek isterseniz, DataCamp’in etkileşimli pandas Foundations kursunu alın.
Kaynaklar:
Lütfen bu eğitimle ilgili tüm sorularınızı aşağıdaki yorumlar bölümünde sormaktan çekinmeyin.
