$ \newcommand\bm[1]{\boldsymbol{#1}} \newcommand\ve{\varepsilon} \newcommand\vecseq[3]{{#1}_{#2}, \ldots, {#1}_{#3}} \newcommand\alg[1]{\color{blue}{\mathrm{#1}}} $
 

MATLABで『時系列解析入門』7章の追記

7章 の一部の内容は, コードが複雑になったり, 計算が合わなかったりして不安だったので, 単変量ARモデルと多変量ARモデルを 愚直に正規方程式を解くことで求めてみる.

正規方程式, $\theta = (X^{T}X)^{-1}X^{T}y$, は教科書では精度や計算時間の問題からお薦めされていないが, MATLABではX\yとするだけで 解いてくれるのでそれを用いる. もちろん, MATLABもバカみたいに逆行列を求めているのではなく, 賢く早い方法で解いてくれているのでその力にあやかる. アルゴリズム ( mathworks ) のフローチャートを見てもらえばわかるように, 結局QR分解を用いているようである.


非専門家が書いています. 十分に批判的に読んで頂くようお願いいたします. 間違い・疑問点などあれば, ぜひコンタクトフォームへ連絡いただけると幸いです.

単変量ARモデル

モデルとコード

M次のARモデル

\begin{align}\large{ y_{n+1} = \sum_{i=1}^{M} a_n y_{n-i} +v_n \notag }\end{align}
の残差の $v_n$ 以外の部分を行列で記すと,
\begin{align}\large{ \begin{pmatrix} y_{M+1} \\ y_{M+2} \\ \vdots \\ y_{N} \\ \end{pmatrix} = \begin{pmatrix} y_{M} & y_{M-1} & \cdots & y_1 \\ y_{M+1} & y_{M} & \cdots & y_2 \\ \vdots & \vdots & \cdots & \vdots \\ y_{N-1} & y_{N-2} & \cdots & y_{N-M+1} \\ \end{pmatrix} \begin{pmatrix} a_{1} \\ \vdots \\ a_{M} \\ \end{pmatrix} }\end{align}
なので, 行列で記すと,
\begin{align}\large{ \bm{y} = X\bm{\theta}^{\mathrm{T}} + \bm{v}. }\end{align}
結局, AR係数 $\bm{\theta}$ は, 以下の正規方程式を解けば求まる.
\begin{align}\large{ \hat{\bm{\theta}} = (X^{\mathrm{T}}X)^{-1}X^{\mathrm{T}}\bm{y}. }\end{align}
残差分散は,
\begin{align}\large{ \frac{1}{N - M} \| \bm{y} - X\hat{\bm{\theta}}^{\mathrm{T}} \|^2. }\end{align}

MATLAB
function [aic, Arcoef, s2, maic] = arNormaleq(d, lag)
%ARNORMALEQ
%
% INPUT
% d  : data
% lag: maximum AR degree (lag)
% 
% OUTPUT
% aic     : AIC
% Arcoef  : AR coefficient (structure)
% s2      : sigma^2
% maic    : The order which provides the minimum AIC

% preprocessing
d = reshape(d, [], 1);
d = d - mean(d);
N = length(d);

% preallocation
s2  = zeros(1, lag);
aic = zeros(1, lag);

% main
for M = 1:lag
    X = zeros(N-M, M);
    for I = 1:M
        X(:, I) = d(M-I+1:N-I);
    end
    y = d(M+1:N);
    theta  = X\y;
    y_est  = X*theta;
    s2(M)  = sum((y - y_est).^2)/(N-M);
    aic(M) = (N-M) * (log(2*pi*s2(M)) + 1) + 2*(M+1);
    
    % save AR coeff
    name = ['order' num2str(M)];
    Arcoef.(name) = theta;
end

% calculate maic
[~, maic] = min(aic);

end

適用

7章 の結果と比較するため太陽黒点数 ( SUNSPOT ) に適用した. ぱっとみ七章の図と違うように見えるのは, 次数0の結果がないから. それ以外はよく合っている.

name
MATLABコード MATLAB
d = sunspot;
d(d==0) = 10^0.1;
d = log10(d);
lag = 20;
[aic, Arcoef, s2, maic] = arNormaleq(d, lag); % ここがメイン

% PLOT
t = tiledlayout(1, 2); t.Padding = 'compact'; t.TileSpacing = 'compact';
nexttile
	bar(1:lag, aic-min(aic), 0.5, 'LineStyle', 'none')
	ylim([0 50]);
	xlabel('AR order')
	ylabel('AIC')
nexttile
	bar(1:lag, s2, 0.5, 'LineStyle', 'none')
	xlabel('AR order')
	ylabel('$\hat{\sigma}^2$','Interpreter','latex')

多変量ARモデル

モデルとコード

教科書6.7節「多変量ARモデル」より, モデルは

\begin{align}\large{ \bm{y}_n = \sum_{m=1}^{M}A_m \bm{y}_{n-m} + \bm{v}_n, \quad \bm{v}_n \sim \mathcal{N}(\bm{0}, V) }\end{align}
であるが, $\bm{y}_n$ が変量の数の長さを持つベクトルという点に注意. つまり, $\ell$ 変数ARモデルならば, $\bm{y}_n = y_n(1), \ldots, y_n(\ell)$ というかんじ. 単変量ARとの類推で残差の $v_n$ 以外の部分を行列で記すと,
\begin{align}\large{ \begin{pmatrix} \bm{y}_{M+1} \\ \bm{y}_{M+2} \\ \vdots \\ \bm{y}_{N} \\ \end{pmatrix} = \begin{pmatrix} \bm{y}_{M} & \bm{y}_{M-1} & \cdots & \bm{y}_1 \\ \bm{y}_{M+1} & \bm{y}_{M} & \cdots & \bm{y}_2 \\ \vdots & \vdots & \cdots & \vdots \\ \bm{y}_{N-1} & \bm{y}_{N-2} & \cdots & \bm{y}_{N-M+1} \\ \end{pmatrix} \begin{pmatrix} A_{1} \\ \vdots \\ A_{M} \\ \end{pmatrix} }\end{align}
なので, 行列で記すと,
\begin{align}\large{ \bm{y} = X\bm{\theta}^{\mathrm{T}} + \bm{v}. }\end{align}
注意としては, ${\theta}^{\mathrm{T}}$ は, $\ell \times \ell$ 行列 ( $A_i$ ) が縦に $M$ 個ならんだ行列なので, サイズが $M\ell \times \ell$ であるということ. 結局, AR係数 $\bm{\theta}$ は, 以下の正規方程式を解けば求まる.
\begin{align}\large{ \hat{\bm{\theta}} = (X^{\mathrm{T}}X)^{-1}X^{\mathrm{T}}\bm{y}. }\end{align}
残差は,
\begin{align}\large{ \mathrm{res} = \bm{y} - X\hat{\bm{\theta}}^{\mathrm{T}} }\end{align}
なので, $V$ はMATLABのちからを借りてcov(res)で求めた.

MATLAB
function [aic, V, Arcoef, maic] = mvArNormaleq(d, K, lag)
%MVARNORMALEQ
%
% INPUT
% d   :data
% k   :dimension of the data
% lag :maximum AR degree
% 
% OUTPUT
% aic     : AIC (size = lag * k)
% Arcoef  : AR coefficient
% V       : variance-covariance matrix
% maic    : The order which provides the minimum AIC

% preprocessing
d = reshape(d, [], K);
d = d - mean(d);
N = size(d, 1);

% preallocation
V   = zeros(K, K, lag);
aic = zeros(1, lag);

% main
for M = 1:lag
    % make X
    X = zeros(N-M, M*K);
    for I = 1:M
       X(:, K*(I-1)+1:K*I) = d(M-I+1:N-I, :); 
    end
    y = d(M+1:end, :);

    theta = X\y;                % solve normal equation    
    res    = X*theta - y;       % calculate residual
    V(:, :, M)      = cov(res); % save variance covariance matrix
    
    % save AIC
    aic(M) = N * (K*log(2*pi) + log(det(V(:, :, M))) + K) + K*(K+1) + 2*K^2*M;
    
    % save AR coeff
    name = ['order' num2str(M)];
    Arcoef.(name) = permute(reshape(theta, [K, M, K]), [2, 1, 3]);
end

% calculate maic
[~, maic] = min(aic);
end

適用

例として, 船舶データ ( HAKUSAN ) に適用してみた. 4変数, 最大次数20でトライ. 正直複雑でコードに自信がないけど, 最小AICを与える次数は10で, 教科書とおなじになった. AICの増加の仕方も直線的でいい感じ.

name
MATLABコード MATLAB
d = hakusan.velocity;
d = [d hakusan.tate];
d = [d hakusan.yoko];
d = [d hakusan.dakaku];

K = 4;
lag = 60;
[aic, V, Arcoef, maic] = mvArNormaleq(d, K, lag);
bar(1:lag , aic - min(aic), 0.5, 'LineStyle', 'none');
ylim([0 1000])
ylabel('AIC')
xlabel('multivariate AR order')

パワースペクトル・コヒーレンシー!要再検査!

教科書6.7節「多変量ARモデル」にのっとりパワースペクトル・コヒーレンシーを求める函数を作った. だいたい教科書と合った結果がでるが, ちょっと自信がないので参考程度に.

MATLAB
function [spec, amp, phase, coh, power, rpower, f] = crossSpectrum(arcoef, v)
% CROSSSPECTRUM 
% 
% INPUTS
% arcoef: AR coeff matrix
% v     : variance-covariance matrix of the noise
% 
% OUTPUTS
% spec  : cross spectrum
% amp   : amplitude spectrum
% phase : phase spectrum
% coh   : coherency
% power : power spectrum decomposition
% rpower: relative power contribution
% f     : frequency

df = 0.001;
f = 0:df:0.5;
N = length(f);
K = size(v, 1);
M = size(arcoef, 1);

% cross spectrum
spec = zeros(K, K, N);

F = zeros(M, N);
for m = 1:M
    F(m, :) = exp(-2*pi*1i*m*f);
end

A = zeros(N, K, K);
for k = 1:K
    for j = 1:K
        for m = 1:M
            A(:, j, k) = A(:, j, k) + (arcoef(m, j, k) * F(m, :))';
        end
        A(:, j, k) = A(:, j, k) -1*(j == k);
    end
end

A = permute(A, [2, 3, 1]);
for I = 1:N
    spec(:, :, I) = A(:, :, I) \ (v / A(:, :, I)');
end
spec = permute(spec, [3, 1, 2]);

% amplitude and phase spectrum
amp = abs(spec);
phase   = angle(spec) + 2*pi;

% coherency
coh = zeros(size(spec));
for k = 1:K
    for j = 1:K
        coh(:, j, k) = amp(:, j, k).^2 ./ (real(spec(:, j, j)) .* real(spec(:, k, k)));
    end
end

% relative power contribution
power = zeros(size(spec));
B = zeros(size(A));
for I = 1:N
    B(:, :, I) = inv(A(:, :, I));
end
B = permute(B, [3, 1, 2]);
for k = 1:K
    for j = 1:K
        power(:, j, k) = v(k, k) * abs(B(:, j, k)).^2;
    end
end

rpower = zeros(size(power));
for k = 1:K
    sumPower = sum(squeeze(power(:, k, :)), 2);
    for j = 1:K
        rpower(:, k, j) = sum(squeeze(power(:, k, 1:j)), 2) ./ sumPower;
    end
end
end

教科書図6.8に対応するものを作ったが, 結構差がある. なお, 選択されたAR次数は16であった. 教科書では何が選択されているのかは書かれておらずわからない.

name
MATLABコード MATLAB
d = hakusan.velocity;
d = [d hakusan.yoko];
d = [d hakusan.dakaku];

% calculate AR coeff and AIC for AR(1) to AR(32)
K   = 3;
lag = 32;
[aic, V, Arcoef, maic] = mvArNormaleq(d, K, lag);
bar(1:lag , aic - min(aic), 0.5, 'LineStyle', 'none');

% calculate cross spectrum
M = maic;
order = ['order' num2str(M)];
a = Arcoef.(order);
W = squeeze(V(:, :, M));
[spec, amp, phase, coh, power, rpower, f] = crossSpectrum(a, W);

% Plot
t = tiledlayout(3, 3); t.Padding = 'compact'; t.TileSpacing = 'compact';
ax = nexttile;
    plot(f, log10(real(spec(:, 1, 1))))
    xlim([0 0.5]); ax.LineWidth = 1; title('方向角速度'); ylabel('方向角速度')
ax = nexttile;
    plot(f, log10(real(amp(:, 1, 2))))
    xlim([0 0.5]); title('横揺れ');
ax = nexttile;
    plot(f, log10(real(amp(:, 1, 3))))
    xlim([0 0.5]); title('舵角');
ax = nexttile;
    plot(f, log10(real(phase(:, 1, 2))))
    xlim([0 0.5]); ylabel('横揺れ')
ax = nexttile;
    plot(f, log10(real(spec(:, 2, 2))))
    xlim([0 0.5]); ax.LineWidth = 1;
ax = nexttile;
    plot(f, log10(real(amp(:, 2, 3))))
    xlim([0 0.5]); 
ax = nexttile;
    plot(f, log10(real(phase(:, 1, 3))))
    xlim([0 0.5]); ylabel('舵角')
ax = nexttile;
    plot(f, log10(real(phase(:, 2, 3))))
    xlim([0 0.5]); 
ax = nexttile;
    plot(f, log10(real(spec(:, 3, 3 ))))
    xlim([0 0.5]); ax.LineWidth = 1;

続いて, コヒーレンシー.

name
MATLABコード MATLAB
t = tiledlayout(1, 3); t.Padding = 'compact'; t.TileSpacing = 'compact';
ax = nexttile;
    plot(f, coh(:, 1, 2))
    xlim([0 0.5]); title('速度 vs 横揺');
ax = nexttile;
    plot(f, coh(:, 1, 3))
    xlim([0 0.5]); title('速度 vs 舵角');
ax = nexttile;
    plot(f, coh(:, 2, 3))
    xlim([0 0.5]); title('舵角 vs 横揺');

そして, 相対パワー寄与率.

name
MATLABコード MATLAB
t = tiledlayout(3, 1); t.Padding = 'compact'; t.TileSpacing = 'compact';
titles = {'方向角速度', '横揺れ', '舵角'};
for target = 1:K
    nexttile
    for k = K:-1:1
        area(f, rpower(:, target, k), 'LineStyle', 'none'); hold on
    end
    xlim([0 0.5]);
    ylabel(titles{target})
end
xlabel('frequency')

主な参考文献


Rによる 時系列モデリング入門

この記事のTOP    BACK    TOP