Table of Contents

7. Časové řady

Cíle cvičení

Doplňkové poklady

Klouzavý průměr

Vyhlazování (smoothing) dat pomocí klouzavého průměru je jednoduchá, ale efektivní technika zpracování časových řad. Cílem vyhlazování je odstranit šum a lépe odhalit původní signál. Klouzavé průměry jsou jednoduchým a běžným typem vyhlazování používaným v analýze časových řad a při předpovídání časových řad.

Výpočet klouzavého průměru spočívá ve vytvoření nové řady, jejíž hodnoty jsou tvořeny průměrem nezpracovaných pozorování v původní časové řadě. Klíčovým parameterem metody je šířka okna, které se posouvá podél časové osy a v jehož rámci jsou vypočítány průměrné hodnoty v nové řadě.

Nejjednodušší metodou vyhlazení je případ, kdy použijeme pro výpočet nových hodnot několik bodů před a několik bodů po středu okna (centered moving averace). Příklad pro velikost okna 3:

center_ma(t) = mean(obs(t-1), obs(t), obs(t+1))

Metoda potřebuje znát budoucí data, takže se většinou používá na analýzu již pořízených časových řad. Metodu lze použít odstranění trendových a sezónních složek z časové řady, pro predikci použít nelze.

O něco lepší je použít pouze historické hodnoty, zde pro okno velikosti 3:

trail_ma(t) = mean(obs(t-2), obs(t-1), obs(t))

Data

Pro účely cvičení budeme používat dostupnou časovou řadu, obsahující počet porodů v Kalifornii, v roce 1959.

daily-total-female-births.zip

Stáhněte si soubor do pracovního adresáře a rozbalte. Prvních několik řádků vypadá následovně:

"Date","Births"
"1959-01-01",35
"1959-01-02",32
"1959-01-03",30
"1959-01-04",31
"1959-01-05",44

Načtení a zobrazení dat

from pandas import read_csv
from matplotlib import pyplot
 
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
 
print(series.head())
series.plot()
pyplot.show()

Vyhlazení dat

Pro vyhlazení dat použijeme funkci rolling(). Tato funkce automaticky vytvoří okno o požadované velikosti a použije ho pro výpočet hodnot nové řady. Následující příklad pracuje s oknem velikosti 3, vyzkoušejte i okna jiné velikosti.

# Tail-rolling average transform
rolling = series.rolling(window=3)
rolling_mean = rolling.mean()
print(rolling_mean.head(10))
 
# plot original and transformed dataset
series.plot()
rolling_mean.plot(color='red')
pyplot.show()

Klouzavý průměr jako vstup pro predikce

Klouzavý průměr lze použít jako zdroj nových informací při modelování předpovědi časové řady (tzv. supervised learning).

V tomto případě se vypočítaný klouzavý průměr přidá jako nová vstupní funkce použitá k předpovědi dalšího časového kroku. Nejprve je třeba posunout kopii řady o jeden časový krok dopředu. Ta bude představovat vstup do předpovědi neboli verzi řady se zpožděním = 1.

X, 	y
NaN,	obs1
obs1,	obs2
obs2,	obs3

Pro lepší představu graficky pro okno velikosti 3:

from pandas import read_csv
from pandas import DataFrame
from pandas import concat
 
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
 
df = DataFrame(series.values)
 
width = 3
 
lag1 = df.shift(1)
lag3 = df.shift(width - 1)
 
window = lag3.rolling(window=width)
means = window.mean()
 
dataframe = concat([means, lag1, df], axis=1)
dataframe.columns = ['mean', 't-1', 't+1']
 
print(dataframe.head(10))

Přímá predikce

from numpy import mean
from sklearn.metrics import mean_squared_error
from matplotlib import pyplot
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
# prepare situation
X = series.values
window = 3
history = [X[i] for i in range(window)]
test = [X[i] for i in range(window, len(X))]
predictions = list()
# walk forward over time steps in test
for t in range(len(test)):
	length = len(history)
	yhat = mean([history[i] for i in range(length-window,length)])
	obs = test[t]
	predictions.append(yhat)
	history.append(obs)
	print('predicted=%f, expected=%f' % (yhat, obs))
error = mean_squared_error(test, predictions)
print('Test MSE: %.3f' % error)
# plot
pyplot.plot(test)
pyplot.plot(predictions, color='red')
pyplot.show()
# zoom plot
pyplot.plot(test[0:100])
pyplot.plot(predictions[0:100], color='red')
pyplot.show()

Dekompozice časové řady

Data

Pro toto cvičení použijeme časovou řadu s údaji o měsíčním počtu cestujících v letech 1949 až 1960.

airline-passengers.zip

Načtení dat

from pandas import read_csv
from matplotlib import pyplot
series = read_csv('airline-passengers.csv', header=0, index_col=0)
series.plot()
pyplot.show()

Sezónní dekompozice

import pandas as pd
from matplotlib import pyplot
from statsmodels.tsa.seasonal import seasonal_decompose
series = pd.read_csv('airline-passengers.csv', header=0)
s = series.squeeze()
x = list(s['Passengers'])
y = pd.Series(x, index=pd.date_range("1-1-1949", periods=len(x), freq="M"), name="Passengers")
result = seasonal_decompose(y, model='multiplicative')
result.plot()
pyplot.show()

Kvalita fitování

import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import STL
from statsmodels.datasets import elec_equip as ds
 
elec_equip = ds.load().data
 
def add_stl_plot(fig, res, legend):
    """Add 3 plots from a second STL fit"""
    axs = fig.get_axes()
    comps = ["trend", "seasonal", "resid"]
    for ax, comp in zip(axs[1:], comps):
        series = getattr(res, comp)
        if comp == "resid":
            ax.plot(series, marker="o", linestyle="none")
        else:
            ax.plot(series)
            if comp == "trend":
                ax.legend(legend, frameon=False)
 
stl = STL(elec_equip, period=12, robust=True)
res_robust = stl.fit()
fig = res_robust.plot()
res_non_robust = STL(elec_equip, period=12, robust=False).fit()
add_stl_plot(fig, res_non_robust, ["Robust", "Non-robust"])
plt.show()