MATLABで『時系列解析入門』6章
最終更新:2021/07/27
6章:ARMAモデルによる時系列の解析
非専門家が書いています. 十分に批判的に読んで頂くようお願いいたします. 間違い・疑問点などあれば, ぜひコンタクトフォームへ連絡いただけると幸いです.
ARMAモデルの定義
時系列 $y_n$ を以下で表現するモデル.
- $m$:自己回帰の次数
- $a_i$:自己回帰係数
- $\ell$:移動平均の次数
- $b_i$:移動平均係数
また, $v_n$ は白色雑音, つまり以下を満たす ( $\mathbb{E}[\cdot]$ は期待値 ) .
- $\mathbb{E}[v_n] = 0$
- $\mathbb{E}[v_n^2] = \sigma^2$
- $\mathbb{E}[v_n v_m] = 0 \; (m \neq n)$
- $\mathbb{E}[v_n y_m] = 0 \; (m \lt n)$
ARMAモデルの性質や表現
インパルス応答函数
ARMAモデルに従う時系列 $y_n$ が, 以下のように, 無限次の移動平均モデルで表されるというのは不思議で面白いなと思う.
下のMATLAB函数は, K期後までのインパルス応答函数を求める函数である. ここで, $\sum_{j = 1}^{i} a_j g_{i-j}$ の部分は内積で計算している. 例えば, $i = 5$ のとき, この和は, $a_1g_4 + a_2g_3 + a_3g_2 + a_4g_1 + a_5g_0$ なので,
function [g, k] =impulseResARMA(a, b, K) k = 0:K; a = reshape(a, 1, []); a = [a zeros(1, K+1-length(a))]; % ゼロでパディング b = reshape(b, 1, []); b = [b zeros(1, K+1-length(b))]; % ゼロでパディング g = zeros(size(k)); g(1) = 1; for I = 1:K g(I+1) = dot(a(1:I), g(I:-1:1)) - b(I); end end
これを用いて, 教科書の例を計算してみる.
- $y_n = 0.9 \sqrt{3} y_{n-1} - 0.81 y_{n-2} + v_n$ (2次のARモデル)
- $y_n = v_n - 0.9 \sqrt{2} v_{n-1} + 0.81 v_{n-2}$ (2次のMAモデル)
- $y_n = 0.9 \sqrt{3} y_{n-1} - 0.81 y_{n-2} + v_n - 0.9 \sqrt{2} v_{n-1} + 0.81 v_{n-2}$((2, 2)次のMAモデル)
MATLABコード
MATLABK = 40; % 教科書の倍に設定してみた a = [0.9*sqrt(3) -0.81]; b = [0.9*sqrt(2) -0.81]; t = tiledlayout(3, 1); t.Padding = 'compact'; t.TileSpacing = 'compact'; nexttile [g, k] = impulseResARMA(a, 0, K); bar(k, g, 0.5, 'LineStyle', 'none'); xticklabels({}) ylabel('$g_k$','Interpreter','latex') legend('a', 'Box', 'off') nexttile [g, k] = impulseResARMA(0, b, K); bar(k, g, 0.5, 'LineStyle', 'none'); xticklabels({}) ylabel('$g_k$','Interpreter','latex') legend('b', 'Box', 'off') nexttile [g, k] = impulseResARMA(a, b, K); bar(k, g, 0.5, 'LineStyle', 'none'); xlabel('$k$','Interpreter','latex') ylabel('$g_k$','Interpreter','latex') legend('c', 'Box', 'off')
自己共分散函数
ARMAモデルの自己共分散函数 $C_k$ は以下の方程式(6.11)で求まる. 寄与とするのは, $m$, $\ell$, $a_i$, $b_i$, $\sigma^2$ である.
以下にMATLABで実装する. 以下の2点に注意.
- $C_k = C_{-k}$
- $g_k = 0 \; (k \lt 0)$
コードの内容が少し複雑なので, どのように計算したのか以下に示す. もっといいやり方があると思う. . .
コードの解説 ( click )
式 \eqref{yw} を以下のように書き直す.
では, $\mathbf{M}$ をどう作るかだが, 僕のコードでは以下のような行列を作り,
$\ell \neq 0$ のとき, つまりYule-Walker方程式とならないときは, ベクトル $\boldsymbol{b}$ も作らなければいけない.
コード内にある, G
やgg
は, $\boldsymbol{b}$ をつくる過程の変数である.
function [C, k] = autocovARMA(a, b, s2, K) %AUTOCOVARMA % % INPUTS: % a : 自己回帰係数 % b : 移動平均係数 % s2: 雑音の分散 % K : K期後まで求める l = length(b) * sign(sum(b~=0)); % gを計算 [g, k] =impulseResARMA(a, b, K); a = reshape(a, 1, []); b = reshape(b, 1, []); a = [a zeros(1, K-length(a))]; % ゼロでパディング % 行列Mの作成 M = zeros(K+1, 2*K+1); aa = [zeros(1, K+1) a]; for I = 1:K+1 M(I, :) = circshift(aa, 1-I); end temp = M(:, 1:K); temp = fliplr(temp); M = M(:, K+1:end); M(:, 2:end) = M(:, 2:end) + temp; % l = 0でないなら, ベクトルbを作成. if l ~= 0 p0 = s2 * (1 - dot(b, g(2:l+1))); gg = [g(1:l) zeros(1, K-l+1)]; G = zeros(K, K+1); for I = 1:K G(I, :) = circshift(gg, I-1); end p = -s2 * b * G(:, 1:l)'; p = [p0 p]; else % solve Yule-Walker equation p = [s2 zeros(1, K)]; end M = eye(K+1) - M; C = M\p'; % 式 ( A ) をとく. end
教科書の例を計算した. 教科書図6.2と一致している
MATLABコード
MATLABK = 40; % 教科書の倍に設定してみた s2 = 1; % 教科書には明記されていなかったけれど, 分散1で計算したら教科書と一致した. a = [0.9*sqrt(3) -0.81]; b = [0.9*sqrt(2) -0.81]; t = tiledlayout(3, 1); t.Padding = 'compact'; t.TileSpacing = 'compact'; nexttile [C, k] = autocovARMA(a, 0, s2, 40); bar(k, C, 0.5, 'LineStyle', 'none'); xticklabels({}) ylabel('$C_k$','Interpreter','latex') legend('a', 'Box', 'off') nexttile [C, k] = autocovARMA(0, b, s2, 40); bar(k, C, 0.5, 'LineStyle', 'none'); xticklabels({}) ylabel('$C_k$','Interpreter','latex') legend('b', 'Box', 'off') nexttile [C, k] = autocovARMA(a, b, s2, 40); bar(k, C, 0.5, 'LineStyle', 'none'); xlabel('$k$','Interpreter','latex') ylabel('$C_k$','Interpreter','latex') legend('c', 'Box', 'off')
ARMAモデルのパワースペクトル
次数 ($m$, $\ell$ ) のARMAモデルのパワースペクトルは, 次の式で求められる.
コードは以下.
function [p, f] = spectrumARMA(a, b, s2, doPlot, df) % SPECTRUMARMA % % a: AR coeff. % b: MA coeff. % s2:variance % doPlot: if true, plot spectrum % df: resolution(optional) % % result can be seen with plot(f, log10(p)) a = reshape(a, [], 1); b = reshape(b, [], 1); if ~exist('df', 'var'), df = 0.001; end if ~exist('doPlot', 'var'), doPlot = false; end m = length(a); l = length(b); f = 0:df:0.5; j = 1:m; k = 1:l; tmp = -2*pi*1i; if isequal(a, 0) den = 1; else den = abs(1 - exp(tmp*j.*f')*a).^2; end if isequal(b, 0) num = 1; else num = abs(1 - exp(tmp*k.*f')*b).^2; end p = s2 * num ./ den; if doPlot plot(f, log10(p)); ylabel('$\log{p(f)}$','Interpreter','latex') xlabel('$f$','Interpreter','latex') xlim([0 0.5]) end end
教科書の図6.4を再現してみる.
MATLABコード
MATLABa = [0.9*sqrt(3) -0.81]; b = [0.9*sqrt(2) -0.81]; t = tiledlayout(3, 1); t.Padding = 'compact'; t.TileSpacing = 'compact'; nexttile [p, f] = spectrumARMA(a, 0, 1); plot(f, log10(p)); title('AR(2)') ylabel('$\log{p(f)}$','Interpreter','latex') xlim([0 0.5]) nexttile [p, f] = spectrumARMA(0, b, 1); plot(f, log10(p)); title('MA(2)') ylabel('$\log{p(f)}$','Interpreter','latex') xlim([0 0.5]) nexttile [p, f] = spectrumARMA(a, b, 1); plot(f, log10(p)); title('ARMA(2, 2)') ylabel('$\log{p(f)}$','Interpreter','latex') xlabel('$f$','Interpreter','latex') xlim([0 0.5])