時系列データに対するブートストラップ法(ブロック・ブートストラップ法)について

あたまだし

検定やクロスバリデーション等への応用を企図した、サンプル数を水増しするための手法としてブートストラップ法がある。これをRで実行するにはsample関数を使って自分でリサンプリングするコードを実装するか、あるいはbootパッケージのboot関数を用いればいい。

ただ、通常このようなリサンプリングにおいては、例えば、データのレコードの行番号を一様にリサンプリングするなど、"データの順序"を考慮したものとはなっておらず、これはデータの順序に意味があるデータ、特に(時)系列データに対して問題となってくるので、通常のブートストラップ法を適用することはできない。

時系列データに対するブートストラップ法に関しては、まず、大枠としてのブロック・リサンプリング法があり、その構成要素としてブロック・ジャックナイフ法、ブロック・ブートストラップ法が研究されてきた。ブロック・ジャックナイフ法はさほどメジャーではないということなので、ここではブロック・ブートストラップ法のみを取り上げる。また、時系列データには定常性を仮定する。

詳しくは

を見るとよい。論文へのリファレンスも多くオススメ。本記事の内容は当該書籍のRのコード部分の要約に近い。

ブロック・ブートストラップ法

ブロック・ブートストラップ法のアイディアは非常に単純で、

  • データの順序に意味があるのならば、データを1つだけではなく、塊(ブロック)としてリサンプリングすればよかろう

というものである。そうすることで、大局的なデータの相関構造は壊れるが、ブロック内での局所的なデータの相関構造は担保されるだろうというものである。

ブロック・ブートストラップ法の中でも、ここでは

  • 移動ブロック・ブートストラップ法(Moving Block Bootstrap, 以下MBB法)
  • 円形ブロック・ブートストラップ法(Circular Block Bootstrap, 以下CBB法)
  • 定常ブートストラップ法(Stationary Bootstrap, 以下SB法)

の3つを取り上げる。上述の書籍ではこれに加え「非重複ブロック・ブートストラップ法」も取り喘げているが、私的にあまりイケてない感があったので、こいつは端折る。

以下ではbootパッケージのtsboot関数を使うので、これはインストールして読み込んでおく。

install.packages("boot")
library("boot")

移動ブロック・ブートストラップ法(Moving Block Bootstrap, MBB法)

MBB法は例えば、

> x <- 1:5
> x
[1] 1 2 3 4 5

というデータがあった時に、ブロックサイズを3とすると

c(1:3)
c(2:4)
c(3:5)

という3つのブロックにデータ分割し、このブロック自身をリサンプリングするものである。なお、ブロックは元のデータと同じ数だけデータがリサンプリングされるよう、リサンプリングされるその個数が決まる。今回の場合は2個ブロックがあればデータが6個できるので、ブロックは2個リサンプリングされ、はみ出した1個のデータは捨てられる。

tsboot関数を使ってMBB法を行うためには、引数として

  • sim="fixed"
  • endcorr=FALSE

と設定する。その他の引数については、第一引数(tseries)にデータを、第二引数(statistic)にブートストラップ法で計算したい統計量を算出したい関数を指定する。

ここで第二引数にはMBB法を使って計算したい統計量を算出する関数を渡すが、統計量ではなく、リサンプルされたサンプルそのものが欲しい場合には、引数をそのまま返す関数を指定すればよい。Rには引数をそのまま返す関数、force関数があるので、これを指定している。force関数の実装は要するに

force <- function(x){x}

ということだ。

実際にMBB法を使って見ると

> # ブロックの長さを3としたMBB法によりテストデータと同じ長さのブートストラップ標本を4回発生させる
> tsboot(x, force, R=4, l=3, sim="fixed", endcorr=FALSE)$t
[,1] [,2] [,3] [,4] [,5]
[1,]    2    3    4    2    3
[2,]    2    3    4    1    2
[3,]    2    3    4    1    2
[4,]    1    2    3    1    2

となる。使用した引数の意味を改めて書いておくと

  • tseries: (時系列)データ
  • stat: ブートストラップ法により計算したい統計量
  • R: リサンプリング回数
  • l: ブロックの長さ
  • sim: リサンプルの発生方法
  • endcorr: ブロックの端点補正有無

となる。
tsboot関数の返り値自体はbootクラスのオブジェクトになっており、リサンプリングの際の条件なども持っているが、ここでは特段いらないので、その返却値に対して$tと付けることで、リサンプリングの結果だけを取得している。

円形ブロック・ブートストラップ法(Circular Block Bootstrap, CBB法)

これは物理でいう”周期境界条件”をつけたものと考えると良い。具体的には、先ほど同様のデータ

> x
[1] 1 2 3 4 5

に対して、ブロックサイズを3とすると

c(1:3)
c(2:4)
c(3:5)
c(4,5,1)
c(5,1,2)

という5つのブロックにデータ分割し、このブロック自身をリサンプリングするものである。こうすることで先ほどのデータでいうと1や5という数値が2,3に比べて出にくいというMBB法に存在した、"リサンプリングデータに対する偏り"がなくなる。

RでCBB法を実行する上で、MBB法と違う点はendcorr=TRUEとするだけである。また、このendcorr引数はデフォルトでTRUEとなっているので、実際には書かなくていい。

# ブロックの長さを3としたCBB法によりテストデータと同じ長さのブートストラップ標本を4回発生させる
> tsboot(x, force, R=4, l=3, sim="fixed")$t
[,1] [,2] [,3] [,4] [,5]
[1,]    3    4    5    3    4
[2,]    3    4    5    2    3
[3,]    3    4    5    4    5
[4,]    3    4    5    1    2
定常ブートストラップ法(Stationary Bootstrap, SB法)

理論的な背景を調べきれていないのだが、元の時系列が定常であっても、MBB・CBBでリサンプリングした場合には定常性が崩れる場合がある(らしい)。そういう状況を避けるためには、SB法を使うとよい。RでSB法を実行する上で、CBB法と違う点はsim="geom"とするだけである。こうすることで、平均l(ブロックサイズ)になる幾何分布からブロックサイズをサンプリングするようになる。なので、SB法の場合、ブロック数は一定とならない。

# ブロックの長さを3としたSB法によりテストデータと同じ長さのブートストラップ標本を4回発生させる
> tsboot(x, force, R=4, l=3, sim="geom")$t
     [,1] [,2] [,3] [,4] [,5]
[1,]    3    4    5    5    1
[2,]    5    1    1    1    2
[3,]    1    2    3    4    5
[4,]    1    2    3    4    5

ブロックサイズの選び方、

上述の参考書籍に「サブサンプリング法に基づくブロック長さの選択法」なるものが載っていた。疲れたから省略。

まとめ

結局定常ブートストラップ法使っておけばいいのか?なんかタラタラ書いてたら堅い日本語になっちゃった・・・