【Python】リスト型と辞書型

Pythonを初めるきっかけができたので、ちょくちょくPythonについて取り上げたい。

リスト型と辞書型について


元々SASSQLVBAを中心に使っていたので、Rを使い始めたときにリスト型の概念に初めて触れた。
配列(Array)っぽいと言えばその通りなので特に構えることはないが、使えるようになると便利なのでメモする。

文字、数値、浮動小数点は字の通り。
リスト型は [] で囲う。辞書型は {} で囲い「インデックス:値」とする。

x = "a"  #-- 文字 str
x = 1    #-- 数値 int
x = 1.1  #-- 浮動小数点 float
x = [1, 2, 3]  #-- リスト list
x = {"key1" : "val1", "key2" : "val2", "key3" : "val3"}  #-- 辞書 dict


リスト型


リストはインデックスが 0~始まる。

lst1 = ["A", "B", "C"]
print(lst1[0])
A


リスト内には複数の型を含められる。

lst2 = ["1", 2, 3.1, [1,2,3], {"key1":1,"key2":2}]
  
type(lst2)
Out[1]: list
  
type(lst2[0])
Out[2]: str
  
type(lst2[1])
Out[3]: int
  
type(lst2[2])
Out[4]: float
  
type(lst2[3])
Out[5]: list
  
type(lst2[4])
Out[6]: dict


更新・追加・削除・複製方法は次のとおり。

lst1 = [1, 2, 3, 4]
  
#-- 更新
lst1[0] = 99  #-- インデックス0を1から99に更新
  
#-- 追加
lst1.append(5)  #-- 末尾に値:5 を追加。
lst1 += [6, 7]  #-- 末尾に別のリストを追加。
  
#-- 削除
del lst1[5] #-- インデックス5を削除
  
#-- 複製
lst2 = lst1  #-- この方法だと lst2 の更新が lst1 にも反映されてしまうようである。
lst3 = list(lst1)  #-- そのため、list関数で囲ってコピーする(他にもやり方はある)。



辞書型


辞書型も同じく、複数の型を含めることができる。

dict1={"key1":"1"
       ,"key2":2
       ,"key3":3.1
       ,"key4":[1,2,3]
       ,"key5":{"subkey1":"あ","subkey2":"い"}}
 
type(dict1)
Out[1]: dict
 
type(dict1["key1"])
Out[2]: str
 
type(dict1["key2"])
Out[3]: int
 
type(dict1["key3"])
Out[4]: float
 
type(dict1["key4"])
Out[5]: list
 
type(dict1["key5"])
Out[6]: dict
 
type(dict1["key5"]["subkey1"])
Out[7]: str


更新・追加・削除・複製方法は次のとおり。

dict1 = {"key1" : "a", "key2" : "b", "key3" : "c"}
   
#-- 更新
dict1["key1"] = 99  #-- キー:"key1"を99に更新
print(dict1)
   
#-- 追加
dict1["key4"] = "d"  #-- キー:"key4"、値:"d"を追加。
print(dict1)
 
#-- 削除
del dict1["key4"] #-- キー:"key4"を削除
print(dict1)
   
#-- 複製
dict2 = dict1  #-- この方法だと dict2 の更新が dict1 にも反映されてしまうようである。
dict3 = dict(dict1)  #-- そのため、dict関数で囲ってコピーする(他にもやり方はある)。




この記事はここまで。

【統計】生存時間解析 ハザード関数、生存関数などの関係性

生存時間解析ではハザード関数、生存関数など色々な関数が出てくるので関係性をメモ。頭の整理。

離散値の場合


確率密度関数

\quad f\left(t\right)=Pr\left(T=t\right)

死亡関数

\quad F\left(t\right)=\sum ^{t} _{T=0}f\left(t\right)

生存関数

\quad S\left(t\right)=\sum ^{T} _{t<T}f\left(t\right)=1-F\left(t\right)

ハザード関数

\quad h\left(t\right)=Pr\left(T=t \ | \ T \geqq t \right)=\dfrac{f\left(t\right)}{S\left(t-1\right)}

累積ハザード関数

\quad H\left(t\right)=\sum ^{t} _{T=0}h\left(t\right)


(イメージ図)
f:id:cochineal19:20210328135838p:plain:w300

* 縦軸が確率密度関数 f (T)、横軸が時間 T
* 死亡関数 F(t)=時点tまでにイベント発生する確率
* 生存関数 S(t)=時点t以降も生存している(イベント発生しない)確率。
* ハザード関数 H(t)=時点tの直前まで生存している集団(リスク集団、Number At Risk)のうち、時点tでイベント発生する確率


連続値の場合


確率密度関数

\quad f\left(t\right)=\lim _{\Delta t\rightarrow 0}\dfrac{\Pr \left( t \leqq T < t+\Delta t\right) }{\Delta t}

 ※Δt に依存するため、Δt で割って標準化する。

死亡関数

\quad F\left(t\right)=\int _{0}^{t}f\left( t\right) dt

生存関数

\quad S\left(t\right)=\int _{t}^{\infty }f\left( t\right) dt=1-F\left(t\right)

ハザード関数

\quad h\left(t\right)=\lim _{\Delta t\rightarrow 0}\dfrac{\Pr \left( t \leqq T < t+\Delta t \ | \ T \geqq t \right) }{\Delta t}=\dfrac{f\left(t\right)}{S\left(t\right)}

累積ハザード関数

\quad H\left(t\right)=\int _{0}^{t}h\left( t\right) dt


(イメージ図)
f:id:cochineal19:20210328135917p:plain:w300

打ち切りのあるデータの推定量


打ち切りがなければ、死亡関数から累積生存率を推定できる。

 \quad \widehat{S} \left(t\right)=1 − F\left(t\right)

打ち切りがあれば、カプランマイヤー法による推定(条件付き確率)。

\quad \widehat{S} \left( t \right) = \prod_{t_{i} < t} \left( 1 - \dfrac{d_{i}}{n_{i}} \right)


また、累積生存率から累積ハザード関数を推定できる。

\quad \widehat{H}\left( t\right) = -\log\ \widehat{S}\left( t \right) =\sum \dfrac{d_{i}}{n_{i}}

\quad \log \widehat{H}\left( t\right) = \log\left(-\log\ \widehat{S}\left( t \right)\right)


参考


http://www.math.s.chiba-u.ac.jp/~wang/suvival.pdf
Rと生存時間分析(1)
生存時間分析の基礎1(生存時間分析とは・生存時間分析のデータ形式)|Maxwell|note

【統計】生存時間解析 ログランク検定、一般化Wilcoxon検定(Gehan's Wilcoxon検定)等

ログランク検定、重み付きログランク検定たちについてのメモ。

【目次】



前回のKaplan-meier 法に続く内容。
cochineal19.hatenablog.com

計算式等


先に計算方法をまとめておく。

ログランク検定は生存時間解析において、2群間の生存時間の差を検定する手法。
時点 t ごとにイベントの観測度数と期待度数のズレを見ており、下のクロス表にまとめることができる。
(※クロス表の黄色セル部分を見ている。)

■ 時点 t ごとのイベント有無のクロス表

イベント 合計
A d_{A} n_{A} - d_{A} n_{A}
B d_{B} n_{B} - d_{B} n_{B}
全体 d_{all} n_{all} - d_{all} n_{all}


■ ログランク検定(Log-Rank test)

\quad \chi ^{2} = \dfrac{ \sum w_{i} \left( O_{i} - E_{i} \right)^{2}}{\sum w_{i}^{2}\ Var[O_{i} - E_{i} ]}

\qquad O_{i} = d_{A}

\qquad E_{i} = n_{A} \dfrac{d_{all}}{n_{all}}

\qquad Var[O_{i} - E_{i} ] = \dfrac{n_{A} \cdot n_{B} \cdot d_{all}\left( n_{all} - d_{all} \right)}{n_{all}^{2} \left(n_{all}-1\right)}


この式はマンテル・ヘンツェルの統計量(CMH統計量)であり、ログランク検定はマンテル・ヘンツェルの方法を用いていることが分かる(Cox-Mantel検定、Mantel Log Rank検定とも呼ばれる)。
cochineal19.hatenablog.com

■ ログランク検定の重み
生存時間解析はイベント・打ち切りの発生により観察期間の後期になるほどN数が少なくなる特徴がある。
このため各時点に重みを与える方法がいくつか考案されている。

手法 重み  w_{i} 補足
Log-Rank (Mantel) 1 一定の重み。
Gehan's Wilcoxon n_{all} 初期に強い重み。
Tarone-Ware \sqrt{n_{all}} 初期に強い重み。
Peto-Peto
\tilde{S} _{\left( t \right)} =  \prod _{t_{i}<t} \left(1-\dfrac{d_{all}}{n_{all}+1} \right)
初期に少し重み。
Harrington-Fleming (a, b)
 \tilde{S} \left( t_{i-1} \right)^{a} [ 1-\tilde{S} \left( t_{i-1} \right) ]^{b}
初期に少し重み。


f:id:cochineal19:20210328114133p:plain:w500

重みを見ての通り、観察期間の前半に差が出やすいものは重み付きのログランク検定の方が有意差が出やすく、後半に差が出やすいものは重みなしのログランク検定の方が有意差が出やすい。

簡単な歴史
* Cox (1953) : 二群の差をF検定で示す方法を提案(指数分布に従う場合)。
* Mantel and Haenszel (1959), Mantel (1966) : Coxの手法を拡張して、ログランク検定(重みなし)を提案。
* Gehan (1965) : Gehan-Wilcoxon検定を提案。
* Peto and Peto (1972) : Peto-Peto検定を提案。
* Tarone and Ware (1977) : Tarone-Ware検定を提案。
* Fleming and Harrington (1981), Harrington and Fleming (1982) : Harrington-Fleming検定を提案。

ノート


今回はSAS中心で記事を書く。(Rの関数は調べれていない。。。)

サンプルデータ


前回のKaplan-meier法の記事と同じく、RのMASSパッケージにあるgehanデータ(Remission Times of Leukaemia Patients)を用いる。

まずは手計算してみる


ログランク検定をExcelで計算してみると下図の通りになる。
(累積生存率 S(t) の計算は前回のKaplan-meier法の記事を参照。)

Log-rank (Mantel)
f:id:cochineal19:20210324000945p:plain

Gehan's Wilcoxon
f:id:cochineal19:20210324001220p:plain

Peto-Peto
f:id:cochineal19:20210324001336p:plain

公式どおりなので特記はないが、1行目のデータ(時点t=1)について式を追ってみる。

イベント 合計
A d_{A}=0 n_{A} - d_{A}=21 n_{A}=21
B d_{B}=2 n_{B} - d_{B}=19 n_{B}=21
全体 d_{all}=2 n_{all} - d_{all}=40 n_{all}=42


時点t=1は、A群:イベント=0例、B群:イベント=2例である。
よって、

\quad O_{1} = d_{A}=0

\quad E_{1} = n_{A} \dfrac{d_{all}}{n_{all}}= 21 \dfrac{2}{42} = 1

\quad Var[O_{1} - E_{1} ] = \dfrac{n_{A} \cdot n_{B} \cdot d_{all}\left( n_{all} - d_{all} \right)}{n_{all}^{2} \left(n_{all}-1\right)}=\dfrac{21 \times 21 \times 2\left( 42 - 2 \right)}{42^{2} \left(42 - 1\right)}=0.4878


ここに重みを与えれば各手法となる:

Log-rank (Mantel)

\quad w_{1}=1

\quad w_{1}\left(O_{1} - E_{1}\right) = 1 \times \left(0 - 1\right) = -1

\quad w_{1}^{2} Var[O_{1} - E_{1} ] = 1^{2} \times 0.4878 = 0.4878


Gehan's Wilcoxon

\quad w_{1}=n_{all,1}=42

\quad w_{1}\left(O_{1} - E_{1}\right) = 42 \times \left(0 - 1\right) = -42

\quad w_{1}^{2} Var[O_{1} - E_{1} ] = 42^{2} \times 0.4878 = 860.4878


Peto-Peto

\quad w_{1} = \tilde{S} _{\left( 1 \right)} = 1 - \dfrac{d_{all}}{n_{all}+1} = 1 - \dfrac{2}{42+1} = 0.953

\quad w_{1}\left(O_{1} - E_{1}\right) = 0.953 \times \left(0 - 1\right) = -0.953

\quad w_{1}^{2} Var[O_{1} - E_{1} ] = 0.953^{2} \times 0.4878 = 0.4435


以上の処理を時点分行ってカイ二乗統計量を算出する。

SASでの実行


LIFETESTプロシジャのSTRATAステートメントのTESTオプションで指定する。

proc lifetest data=ADTTE plots=s(cl atrisk maxlen=30 outside) alpha=0.5 conftype=loglog;
    time AVAL * CNSR(0);
    strata TRT01A / test=(LOGRANK WILCOXON TARONE PETO FH(0.5,0.5));
    ods output SurvivalPlot = SP1;
    ods output Quartiles    = QT1;
run;


f:id:cochineal19:20210324002059p:plain:w300

Rでの実行


Log-rank (Mantel) についてsurvivalパッケージのsurvdiff関数で実行できる。
(※他の手法は調べれていない)

> library(survival)
> survdiff(Surv(time=AVAL, event=EVENT) ~ TRT01A, data=ADTTE)
Call:
survdiff(formula = Surv(time = AVAL, event = EVENT) ~ TRT01A, 
    data = ADTTE)

                N Observed Expected (O-E)^2/E (O-E)^2/V
TRT01A=6-MP    21        9     19.3      5.46      16.8
TRT01A=control 21       21     10.7      9.77      16.8

 Chisq= 16.8  on 1 degrees of freedom, p= 4e-05 



プログラムコード


R

library(survival)
survdiff(Surv(time=AVAL, event=EVENT) ~ TRT01A, data=ADTTE)


SAS

proc lifetest data=ADTTE plots=s(cl atrisk maxlen=30 outside) alpha=0.5 conftype=loglog;
    time AVAL * CNSR(0);
    strata TRT01A / test=(LOGRANK WILCOXON TARONE PETO FH(0.5,0.5));
    ods output SurvivalPlot = SP1;
    ods output Quartiles    = QT1;
run;


Python

整備中


参考


統計学(出版:東京図書), 日本統計学会編
https://support.sas.com/documentation/onlinedoc/stat/142/lifetest.pdf
Pinar Gunel Karadeniz and Ilker Ercan, EXAMINING TESTS FOR COMPARING SURVIVAL CURVES WITH RIGHT CENSORED DATA, STATISTICS IN TRANSITION new series, June 2017, Vol. 18, No. 2, pp. 311–328
http://www.math.ucsd.edu/~rxu/math284/slect2.pdf
http://www.math.ucsd.edu/~rxu/math284/slect3.pdf
https://www.pharmasug.org/proceedings/2014/SP/PharmaSUG-2014-SP10.pdf
https://www.sas.com/content/dam/SAS/ja_jp/doc/event/sas-user-groups/usergroups11-a-02.pdf


サイトマップ

cochineal19.hatenablog.com

【統計】生存時間解析 カプランマイヤー法(Kaplan-meier method)

カプランマイヤー法(Kaplan-meier method)についてのメモ。

【目次】



累積生存率とその信頼区間について記載する。
信頼区間はRで扱えるPlain(SASではLinear)、Log、Log-Logの3種類について。

計算式等


先に計算方法をまとめておく。

■ 累積生存率(Cumulative Survival Rate)

 推定値

\qquad \widehat{S} \left( t \right) = \prod_{t_{i} < t} \left( 1 - \dfrac{d_{i}}{n_{i}} \right)


 分散と95%信頼区間(Type:Linear(Plain))

\qquad Var \Big[\widehat{S}\left( t \right)\Big] = \widehat{S}^{2} \cdot \sum_{t_{i} \leqq t}\dfrac{d_{i}}{n_{i}\left(n_{i}-d_{i}\right)}
\qquad \widehat{S}\left( t \right) \pm 1.96 \sqrt{Var \Big[\widehat{S}\left( t \right)\Big]}

  ※ここに示した分散はGreenwoodの公式と言われる。

 分散と95%信頼区間(Type:Log)

\qquad Var \Big[\log\ \widehat{S}\left( t \right)\Big] = \sum_{t_{i} \leqq t}\dfrac{d_{i}}{n_{i}\left(n_{i}-d_{i}\right)}
\qquad \exp \bigg\{ \log\ \widehat{S}\left( t \right) \pm 1.96 \sqrt{Var \Big[\log\ \widehat{S}\left( t \right)\Big]} \bigg\}


 分散と95%信頼区間(Type:Log-Log)

\qquad Var \Big[\log\left(-\log \widehat{S}\left( t \right)\right)\Big] = \sum_{t_{i} \leqq t} \dfrac{d_{i}}{n_{i}\left(n_{i}-d_{i}\right)} \bigg/ \sum_{t_{i} \leqq t} \ \log \dfrac{n_{i} - d_{i}}{n_{i}}
\qquad \exp\Bigg\{-\exp\bigg\{\log\left(-\log\ \widehat{S}\left( t \right)\right) \pm 1.96 \sqrt{Var \Big[\log\left(-\log \widehat{S}\left( t \right)\right)\Big]}\ \bigg\}\Bigg\}


■ 生存期間中央値(Median Survival Time:MST)

 \quad q_{p} = \min \{ t_{i} \ | \ \widehat{S}_{\left( t_{i} \right)} < 1 - p \}


 ※累積生存率が初めて 1 - p(MSTの時は50%)を下回る時点。
 ※p=0.5でMST。p=0.25, 0.75で25、75パーセンタイル値。

■ (参考)累積ハザード(cumulative hazard)

\quad \widehat{H}\left( t\right) = -\log\ \widehat{S}\left( t \right) =\sum \dfrac{d_{i}}{n_{i}}
\quad Var \Big[ \widehat{H}\left( t\right) \Big] = Var \Big[\log\ \widehat{S}\left( t \right)\Big] = \sum\dfrac{d_{i}}{n_{i}\left(n_{i}-d_{i}\right)}


\quad \log \widehat{H}\left( t\right) = \log\left(-\log\ \widehat{S}\left( t \right)\right)
\quad Var \Big[ \log \widehat{H}\left( t\right) \Big] = Var \Big[\log\left(-\log \widehat{S}\left( t \right)\right)\Big]


ノート


Kaplan-meier 法は、打ち切りデータ(Censored data)を考慮した上で生存率を計算する方法である。
生存時間解析というと死亡有無の評価に見えるが、関心イベントの発生を評価するため死亡以外にも使える(例:骨折、転倒など)。

打ち切りとは


関心イベントを追跡できなくなった状態を言う(※本記事では右側打ち切りのみ扱う)。
下図の例では、Bさんは観察期間内にイベントが発生せず打ち切り、Cさんは観察期間中に脱落で打ち切りとなる。
f:id:cochineal19:20210320152204p:plain:w500

打ち切りデータは時点の後ろに「+」を付けて表し、例えば「10+」とすれば時点 t=10 での打ち切りとなる。
また、後述するKaplan-meier curveでは打ち切り時点に「+」をアノテーションする習わしがある(ヒゲと呼ばれる)。

サンプルデータ


今回は、RのMASSパッケージにあるgehanデータ(Remission Times of Leukaemia Patients)を用いる。
白血病患者の寛解の継続期間(週)に関するデータでイベントは再発。cens列に打ち切り情報(0=打ち切り、1=イベント)がある。Control vs. 6-MPの2群データであり、pairは群毎の連番を表す。

> library(MASS)
> head(gehan, 10);
   pair time cens   treat
1     1    1    1 control
2     1   10    1    6-MP
3     2   22    1 control
4     2    7    1    6-MP
5     3    3    1 control
6     3   32    0    6-MP
7     4   12    1 control
8     4   23    1    6-MP
9     5    8    1 control
10    5   22    1    6-MP


これをADTTEと名付けて、以降 RとSASで使用する。

ADTTE <- data.frame(
  AVAL    = gehan$time
  ,EVENT  = gehan$cens
  ,CNSR   = ifelse(gehan$cens==0, 1, 0) #-- イベント=0, 打ち切り>0の形式
  ,TRT01A = gehan$treat)


手計算してみる


6-MP群についてExcelで計算してみると下図の通りになる。
f:id:cochineal19:20210327120649p:plain

 Excel関数の中身(折りたたんでます。ここをクリック)

 7列目: =IF(RC[-2] > 0,(RC[-3] - RC[-2]) / RC[-3], "")
 8列目: =LN((RC[-5] - RC[-4]) / RC[-5])
 9列目: =IF(RC[-5] > 0, R[-1]C * RC[-3], R[-1]C)
10列目: =IF(RC[-4] <> "", (1 - RC[-4]) + R[-1]C, R[-1]C)
11列目: =RC[-2]^2 * RC[1]
12列目: =RC[-5] + R[-1]C
13列目: =RC[-5] + R[-1]C
14列目: =RC[-2] / RC[-1]^2
15列目: =RC[-6] - 1.96 * SQRT(RC[-4])
16列目: =RC[-7] + 1.96 * SQRT(RC[-5])
17列目: =EXP(LN(RC[-8]) - 1.96 * SQRT(RC[-5]))
18列目: =EXP(LN(RC[-9]) + 1.96 * SQRT(RC[-6]))
19列目: =EXP(-1 * EXP(LN(-1 * LN(RC[-10])) + 1.96 * SQRT(RC[-5]) ))
20列目: =EXP(-1 * EXP(LN(-1 * LN(RC[-11])) - 1.96 * SQRT(RC[-6]) ))


ここでは理解のため、6-MP群の3行目のデータまで式を出しながら計算してみる。

生存時間
(t)
リスク集団
(n)
イベント例
(d)
打ち切り
(c)
生存率
1-d/n
6 21 3 1 0.8571
7 17 1 0 0.9412
9 16 0 1  


上表は生存時間解析を行う上での基本情報となる。
このうち、リスク集団は、前時点の「リスク集団 -(イベント例+打ち切り例)」から計算される(時点tになる直前のイベント未発生例)。
また、生存率は「1 -(イベント例÷リスク集団)」で計算し、打ち切り例は含めない。

累積生存率の推定値 S(t)
イベント発生時点を対象に当該時点までの生存率を掛け算するため、t=6、7は次の計算になる。また、t=9は打ち切りのみ(イベント未発生)のため、t=7の累積生存率のままとなる。

 \quad t=6:\quad 1-\dfrac{3}{21}=0.8571

 \quad t=7:\quad \left(1-\dfrac{3}{21}\right)\times\left(1-\dfrac{1}{17}\right)=0.8571\times0.9412=0.8067

 \quad t=9:\quad 0.8067


累積生存率の分散
まず Var[log S(t)] について例示する。
イベント発生時点を対象に「イベント例 / {リスク集団(リスク集団 - イベント例)} 」を足し算するため、t=6、7は次の計算になる。なお、t=9は打ち切りのみのため t=7と同じ。

 \quad t=6:\quad\dfrac{3}{21\left(21-3\right)}=0.0079

 \quad t=7:\quad\dfrac{3}{21\left(21-3\right)}+\dfrac{1}{17\left(17-1\right)}=0.0079+0.0037=0.0116

 \quad t=9:\quad 0.0116


次に Var[log (-log S(t))] について例示する。
Var[log S(t)] を「log{(リスク集団-イベント例)/リスク集団}」の累積和の二乗で割ることで求まるため、次のように計算できる。

 \quad t=6:\quad\dfrac{3/\{21\left(21-3\right)\}}{ \{ \log \left(\left(21-3\right)\right)/21 \}^{2}}=\dfrac{0.0079}{-0.1542^{2}}=0.3340

 \quad t=7:\quad\dfrac{3/\{21\left(21-3\right)\}+1/\{17\left(17-1\right)\} }{ \{ \log \left( \left(21-3\right)/21\right) + \log \left(\left(17-1\right)/17\right) \}^{2}} = \dfrac{0.0079+0.0037}{\left(-0.1542-0.0606\right)^{2}}=\dfrac{0.0116}{-0.2148^{2}}=0.2518

 \quad t=9:\quad 0.2518


最後に Var[S(t)] について例示する。
Var[log S(t)] に累積生存率S(t) の二乗を掛けることで求まるため、次のように計算できる。

 \quad t=6:\quad 0.8571^{2} \times 0.0079=0.0058

 \quad t=7:\quad 0.8067^{2} \times 0.0116=0.0076

 \quad t=9:\quad 0.0076


累積生存率の95%信頼区間
信頼区間は上で求めた推定値・分散を用いるため、1行目の t=6 のみ例示する。

 \quad \exp\{ \log 0.8571\ \pm 1.96 \sqrt{0.0079}\}=[0.7198,\ 1.0207] \verb|(log)|

 \quad \exp\{ - \exp\{ \log \left( - \log 0.8571\right) \pm 1.96 \sqrt{0.3340}\}\}=[0.6197,\ 0.9516] \verb|(log-log)|

 \quad 0.8571 \pm 1.96 \sqrt{0.0058}^{2}=[0.7075,\ 1.0068] \verb|(Linear / Plain)|


なお、信頼区間上限について、今回は例示のため1以上の数値も示したが、実際は0~1の区間を扱うため1以上は1とする。

生存期間中央値
MSTは累積生存率 S(t) が初めて0.5を下回った時点となる。
本サンプルでは S(22)=0.5378 、S(23)=0.4482 のため、MST=23となる。

Rでの実行


survivalパッケージとsurvminerパッケージを使ってKaplan-meier curveを描画する。

library(survival)
library(survminer)


Kaplan-meier法はsurvivalパッケージのSurv関数とsurvfit関数を組み合わせて行う。
累積生存率の信頼区間(conf.type)はlog、log-log、plain を選択できるが、今回はlog-logで例示する。

KM1 <- survfit(formula    = Surv(time=AVAL, event=EVENT) ~ TRT01A
               ,conf.type = "log-log"
               ,conf.int  = .95
               ,type      = "kaplan-meier"
               ,error     = "greenwood"
               ,data      = ADTTE)


なお、Surv関数の部分では次のインプットデータを作っている。
「打ち切りとは」で触れたように数字の後ろに「+」が付くものが打ち切りデータである。

Surv(time=ADTTE$AVAL, event=ADTTE$EVENT)
 [1]  1  10  22   7   3  32+ 12  23   8  22  17   6   2  16  11  34+  8  32+ 12  25+  2  11+
[23]  5  20+  4  19+ 15   6   8  17+ 23  35+  5   6  11  13   4   9+  1   6+  8  10+


Kaplan-meier curveはSurv関数で取得した結果をsurvminerパッケージのggsurvplot関数に引き渡すときれいに描画してくれる。

ggsurvplot(KM1
           ,pval             = TRUE
           ,conf.int         = TRUE
           ,risk.table       = TRUE
           ,risk.table.col   = "strata"
           ,linetype         = "strata"
           ,surv.median.line = "hv"
           ,ggtheme          = theme_bw()
           ,palette          = c("blue", "darkgreen") )

f:id:cochineal19:20210320231218p:plain:w500

なお、生存時間解析の分析データを集約すると次のとおり。

 ★データの中身(折りたたんでます。ここをクリック)

> summary(KM1)
Call: survfit(formula = Surv(time = AVAL, event = EVENT) ~ TRT01A, data = ADTTE, 
    error = "greenwood", conf.type = "log-log", conf.int = 0.95, 
    type = "kaplan-meier")

 TRT01A=6-MP 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    6     21       3    0.857  0.0764        0.620        0.952
    7     17       1    0.807  0.0869        0.563        0.923
   10     15       1    0.753  0.0963        0.503        0.889
   13     12       1    0.690  0.1068        0.432        0.849
   16     11       1    0.627  0.1141        0.368        0.805
   22      7       1    0.538  0.1282        0.268        0.747
   23      6       1    0.448  0.1346        0.188        0.680

 TRT01A=control 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    1     21       2   0.9048  0.0641      0.67005        0.975
    2     19       2   0.8095  0.0857      0.56891        0.924
    3     17       1   0.7619  0.0929      0.51939        0.893
    4     16       2   0.6667  0.1029      0.42535        0.825
    5     14       2   0.5714  0.1080      0.33798        0.749
    8     12       4   0.3810  0.1060      0.18307        0.578
   11      8       2   0.2857  0.0986      0.11656        0.482
   12      6       2   0.1905  0.0857      0.05948        0.377
   15      4       1   0.1429  0.0764      0.03566        0.321
   17      3       1   0.0952  0.0641      0.01626        0.261
   22      2       1   0.0476  0.0465      0.00332        0.197
   23      1       1   0.0000     NaN           NA           NA

> print(KM1)
Call: survfit(formula = Surv(time = AVAL, event = EVENT) ~ TRT01A, data = ADTTE, 
    error = "greenwood", conf.type = "log-log", conf.int = 0.95, 
    type = "kaplan-meier")

                n events median 0.95LCL 0.95UCL
TRT01A=6-MP    21      9     23      13      NA
TRT01A=control 21     21      8       4      11


SASでの実行


Rの実行で使ったデータと同じものをLIFETESTプロシジャで実行する。

proc lifetest data=ADTTE plots=s(cl atrisk maxlen=30 outside) alpha=0.05 conftype=loglog;
    time AVAL * CNSR(0);
    strata TRT01A / test=logrank;
    ods output SurvivalPlot = SP1;
    ods output Quartiles    = QT1;
run;


SASの場合は、LIFETESTプロシジャを実行すれば、累積生存率やグラフを一式出力してくれる。
グラフの設定はplotsオプションで行う。s : 累積生存率の描画、cl : 信頼区間の描画、atrisk maxlen=30 outside : グラフ外にリスク集団を表示。最大文字は30。
信頼区間はconftypeオプションで指定でき、loglog、log、linear等がある。デフォルトはloglog。また、alphaオプションで何%信頼区間にするか指定する。
f:id:cochineal19:20210321015342p:plain:w450

ただし、実際はアウトプットしたデータセットを使って SGPLOTプロシジャで作り直すことが多いかもしれない。
累積生存率等は ods output SurvivalPlot で、MST等は ods output Quartiles でデータセット化できる。

プログラムコード


R

#-- Kaplan-meier method
KM1 <- survfit(formula    = Surv(time=AVAL, event=EVENT) ~ TRT01A  #-- 1群の時はTRT01Aのところを 1 とする。
               ,conf.type = "log-log"  #-- log or log-log or plain
               ,conf.int  = 0.95
               ,type      = "kaplan-meier"
               ,error     = "greenwood"
               ,data      = ADTTE)
 
#-- Kaplan-meier curve
ggsurvplot(KM1
           ,pval             = TRUE
           ,conf.int         = TRUE
           ,risk.table       = TRUE
           ,risk.table.col   = "strata"
           ,linetype         = "strata"
           ,surv.median.line = "hv"  
           ,ggtheme          = theme_bw()
           ,palette          = c("blue", "darkgreen") )


SAS

proc lifetest data=ADTTE plots=s(cl atrisk maxlen=30 outside) alpha=0.05 conftype=loglog;
    time AVAL * CNSR(0);
    strata TRT01A / test=logrank;
    ods output SurvivalPlot = SP1;  /* 累積生存率などのデータセット化 */
    ods output Quartiles    = QT1;  /* MSTなどのデータセット化 */
run;


Python

整備中


参考


統計学(出版:東京図書), 日本統計学会編
https://support.sas.com/documentation/onlinedoc/stat/142/lifetest.pdf
http://www.math.ucsd.edu/~rxu/math284/slect2.pdf
https://www.pharmasug.org/proceedings/2014/SP/PharmaSUG-2014-SP10.pdf
https://www.sas.com/content/dam/SAS/ja_jp/doc/event/sas-user-groups/usergroups11-a-02.pdf


サイトマップ

cochineal19.hatenablog.com

【SQL Server】分類ごとに1つだけフラグを立てる

最近SQL Serverの記事を挙げられていなかったので、
題目通り、任意の分類ごとに1つだけフラグを立てるやり方。

例えば、次のようなデータにID毎に1つだけフラグを立てたいとか、ID・日付毎に1つだけフラグを立てたいというような場面。
用途として、立てたフラグを sum して分類単位での件数集計を行う。
f:id:cochineal19:20210314220723p:plain:w200

SQL Serverでそれらしい関数が見当たらなかったので自作してみる。

SASで言う first by 句的なやつです。

/* サンプル */
data tmp;
length ID1 $10. DATE $20. CLASS1 8.;
input ID1 DATE CLASS1 @@;
cards;
001 2021-01-01 1
001 2021-01-01 1
001 2021-01-02 1
001 2021-01-02 1
001 2021-01-02 1
001 2021-01-02 2
001 2021-01-02 2
002 2021-01-02 1
002 2021-01-02 2
002 2021-01-02 2
;run;
 
/* フラグ付け */
proc sort data=tmp; by ID1 DATE CLASS1;
data tmp;
  set tmp;
  by ID1 DATE CLASS1;
  if first.ID1    then FIRSTFL1 = 1; else FIRSTFL1 = 0;
  if first.DATE1  then FIRSTFL2 = 1; else FIRSTFL2 = 0;
  if first.CLASS1 then FIRSTFL3 = 1; else FIRSTFL3 = 0;
run;



これをSQL Serverでやると:

-- サンプル
drop table #tmp1;
create table #tmp1 ( ID1 varchar(3), DATE1 varchar(10), CLASS1 int )
insert #tmp1 values
 ('001', '2021-01-01', 1)
,('001', '2021-01-01', 1)
,('001', '2021-01-02', 1)
,('001', '2021-01-02', 1)
,('001', '2021-01-02', 1)
,('001', '2021-01-02', 2)
,('001', '2021-01-02', 2)
,('002', '2021-01-02', 1)
,('002', '2021-01-02', 2)
,('002', '2021-01-02', 2)
;
 
-- フラグ付け
select
     *
    ,FIRSTFL1 = case when row_number() over (partition by ID1                order by CLASS1) = 1 then 1 else 0 end
    ,FIRSTFL2 = case when row_number() over (partition by ID1, DATE1         order by CLASS1) = 1 then 1 else 0 end
    ,FIRSTFL3 = case when row_number() over (partition by ID1, DATE1, CLASS1 order by CLASS1) = 1 then 1 else 0 end
from #tmp1


こんな感じで任意のグループごとに1つフラグが立つ。
f:id:cochineal19:20210314221329p:plain:w400

中身は row_number関数でパーティション毎に順番をつけて、case文で順番が1の時だけ1となるようにしている。
効率が良いとは言えないだろうが、一つの方法として。

【統計】時系列分析(ARIMA、SARIMA、SARIMAXをRで実行する)

ARIMA、SARIMA、SARIMAXモデルをRで試してみる。
【目次】


用意したデータ


今回、横浜市の月別火災発生件数を例として扱う。
ソースは横浜市のオープンデータより取得。
このデータは2000年1月~2019年12月の20年間240カ月分ある。

更に火災と関連がありそうなものとして、横浜市の月別平均気温と月別平均相対湿度を回帰成分(外生変数)として準備する。
ソースは気象庁ホームページより。

なお本日使うパッケージはこれら。forecast でARIMAモデルを構築する。

library(tidyverse)
library(forecast)

データ加工


今回、簡便な方法として forecastパッケージの auto.arima 関数を使ってみる。
時系列データセットはTime-Series型、外生変数はmatrix型かvector型が要求されるため、ts関数とmatrix関数で型変換しておく。

#-- データ加工(原系列:時系列型、回帰成分:マトリクス型)
FIRE <- read_csv("./yokohama_kasai.csv")
TEMP <- read.csv("./yokohama_kion.csv")
HUMI <- read.csv("./yokohama_shitsudo.csv")
 
ADTS   <- ts(FIRE$火災件数, frequency=12)
ADXREG <- as.matrix(data.frame(TEMP=TEMP$平均気温, HUMI=HUMI$平均湿度), col=12)


また、17年分(2000~2016年)を学習期間、3年(2017~2019年)をテスト期間としてみる(ホールドアウト法)。
データ分割はwindow関数で比較的簡単にできる。

#-- データ分割(訓練:テスト)
ADTS.train <- window(ADTS, c( 1, 1), c(17,12)) # 2000.01 - 2016.12
ADTS.test  <- window(ADTS, c(18, 1), c(20,12)) # 2017.01 - 2019.12
 
nt <- length(ADTS.train)
ADXREG.train <- window(ADXREG, 1, nt)     # 2000.01 - 2016.12
ADXREG.test  <- window(ADXREG, nt+1, 240) # 2017.01 - 2019.12


観測値の時系列の描画


auto.arima関数を使う前に観測値の時系列を見てみる。
forecast::ggtsdisplay関数を使うと時系列、自己相関、偏自己相関をさっとグラフ化してくれる。
グラフから今回のデータにはラグ1~3の自己相関、1年くらいの季節周期がありそうだと分かる。

forecast::ggtsdisplay(ADTS.train)

f:id:cochineal19:20210309234031p:plain:w500

単位根の検定


ARは定常過程を前提とするため、まず単位根を確認してみる。

urcaパッケージが有名なようだが、forecastパッケージでも ndiffs関数でADF検定やKPSS検定などの単位根検定ができるため、今回はforecastパッケージに統一する。ndiffs関数は、戻り値として d階差がいくつかを返してくれるシンプルなもの。

ADF検定は、帰無仮説を「単位根過程である」、対立仮設を「単位根はない」とし、帰無仮説棄却されなければ単位根があると解釈する手法のようである。
一方、KPSS検定はその逆で、帰無仮説を「単位根がない」とし、棄却されれば単位根があるとする。

forecast::ndiffs(ADTS.train, test="adf")
forecast::ndiffs(ADTS.train, test="kpss")


悩ましいことに、今回のデータではADF検定で単位根なし、KPSS検定で単位根ありとなった。今回はauto.arima関数のデフォルトであるKPSS検定に従うとする。

ARIMAモデルの実行


前述のとおり、forecastパッケージのauto.arima関数を用いる。
先ずは季節成分なし(seasonal=F)でARIMAモデルを実行する。
先ほど単位根検定を行ったが、auto.arima関数内で d=NAとすると単位根検定を行い、d階差を調べてくれるため、試しがてらNAにする。

なお、stepwise=FALSEにすると総当たりでベストモデルを探してくれるようなので今回はFALSEにする(計算コストはかかるが・・)。他、処理速度を上げるため、並列処理(parallel=TURE)にし、CPUのコア数は8とした(ここは自前のPCと要相談)。

mod.arima <- forecast::auto.arima(ADTS.train
                                  ,d         = NA
                                  ,start.p   = 0
                                  ,start.q   = 0
                                  ,seasonal  = F
                                  ,stepwise  = F
                                  ,parallel  = T
                                  ,num.cores = 8
                                  )


auto.arimaを実行するとあっけないほど簡単にモデルが作成できる。
今回はARIMA(3,1,2)がベストモデルとなった。

 \quad z_{t} = \Delta _{1} y_{t} = y_{t} - y_{t-1}
 \quad z_{t} = \phi _{1} z_{t-1} + \phi _{2} z_{t-2} + \phi _{3} z_{t-3} + \varepsilon _{t} + \theta _{1}\varepsilon_{t-1} + \theta _{2}\varepsilon_{t-2}  \quad \quad = 1.1245 z_{t-1} -0.1420 z_{t-2} -0.2988 z_{t-3} + \varepsilon _{t} -1.6998 \varepsilon_{t-1} + 0.7290\varepsilon_{t-2}

> summary(mod.arima)
Series: ADTS.train 
ARIMA(3,1,2) 

Coefficients:
         ar1      ar2      ar3      ma1     ma2
      1.1245  -0.1420  -0.2988  -1.6998  0.7290
s.e.  0.0883   0.1098   0.0737   0.0680  0.0643

sigma^2 estimated as 288:  log likelihood=-861.58
AIC=1735.17   AICc=1735.6   BIC=1755.05

Training set error measures:
                    ME     RMSE     MAE      MPE    MAPE      MASE        ACF1
Training set -1.726492 16.71896 13.4789 -6.19378 17.2469 0.9039288 -0.04407495


次に作成モデルの残差診断を行う。モデルが適切であれば、残差は定常であり自己相関がない。
forecastパッケージでは、checkresiduals関数で残差診断が可能であり、リュング・ボックス検定(Ljung-Box test)を行ってくれる。
この検定は、帰無仮説を「自己相関がない」、対立仮設を「少なくとも1つ以上のラグに自己相関がある」とし、帰無仮説棄却されなければ自己相関がないと解釈する手法である。
今回は p<0.001で有意であり、自己相関がないとは言えない。checkresiduals関数で出力されるコレログラムを見ると自己相関がありそうだと見て取れる。

> resid.arima <- forecast::checkresiduals(mod.arima)

    Ljung-Box test

data:  Residuals from ARIMA(3,1,2)
Q* = 57.292, df = 19, p-value = 1.029e-05

Model df: 5.   Total lags used: 24

f:id:cochineal19:20210312232825p:plain:w500

なお、ARIMAモデルでの予測は次のとおり(黒:観測値、青:予測値)。

fig.arima <- ggplot() +
  geom_line(mapping=aes(x=1:length(mod.arima$fitted), y=c(mod.arima$x)), color="black", size=1) +
  geom_line(mapping=aes(x=1:length(mod.arima$fitted), y=c(mod.arima$fitted)), color="blue", size=2, alpha=.4) +
  labs(title=gsub("Residuals from ","",resid.arima$data.name), x="", y="") +
  theme(plot.title=element_text(size=30)
        ,axis.title=element_text(size=25)
        ,axis.text=element_text(size=20))
plot(fig.arima)

f:id:cochineal19:20210312233404p:plain:w400

SARIMAモデルの実行


続いて、SARIMAを試してみる。
auto.arima を seasonal = T にすることで季節を考慮できる。
なお、季節周期を組み込む場合、入力データにあらかじめ周期を持たせておく必要がある。今回は、ts(FIRE$火災件数, frequency=12) で12周期としている。

mod.sarima <- forecast::auto.arima(ADTS.train
                                   ,d        = NA
                                   ,D        = NA
                                   ,start.p  = 0
                                   ,start.q  = 0
                                   ,start.P  = 0
                                   ,start.Q  = 0
                                   ,seasonal = T
                                   ,stepwise  = F
                                   ,parallel  = T
                                   ,num.cores = 8
                                   )


今回はSARIMA(1,0,1)(0,1,1)[12] がベストモデルであった。

 \quad z_{t}=\Delta _{12}^{1} \Delta _{1}^{0} y_{t} = \Delta _{12}^{1} y_{t} = y_{t} - y_{t-12}

 \quad \phi \left( L \right) \Phi \left( L^{12}\right) z_{t} = \theta \left( L\right) \Theta \left( L^{12}\right) \varepsilon _{t}
 \quad \Leftrightarrow \left( 1 - \phi_{1} L^{1} \right) z_{t} = \left( 1 + \theta_{1} L^{1} \right) \left( 1 + \Theta_{1} L^{12} \right)  \varepsilon _{t}
 \quad \Leftrightarrow \left( 1 - \phi_{1} L^{1} \right) z_{t} = \left( 1 + \theta_{1} L^{1} + \Theta_{1} L^{12} + \theta_{1} \Theta_{1} L^{13} \right)  \varepsilon _{t}
 \quad \Leftrightarrow z_{t} - \phi_{1} z_{t-1} = \varepsilon _{t} + \theta_{1} \varepsilon _{t-1} + \Theta_{1} \varepsilon _{t-12} + \theta_{1} \Theta_{1} \varepsilon _{t-13}
 \quad \Leftrightarrow z_{t} = \phi_{1} z_{t-1} + \varepsilon _{t} + \theta_{1} \varepsilon _{t-1} + \Theta_{1} \varepsilon _{t-12} + \theta_{1} \Theta_{1} \varepsilon _{t-13}
 \quad \Leftrightarrow z_{t} = 0.9644 z_{t-1} + \varepsilon _{t} -0.7851 \varepsilon _{t-1} -0.8848 \varepsilon _{t-12} + \left(-0.7851 \times -0.8848 \right) \varepsilon _{t-13}
 \quad \Leftrightarrow z_{t} = 0.9644 z_{t-1} + \varepsilon _{t} -0.7851 \varepsilon _{t-1} -0.8848 \varepsilon _{t-12} + 0.6947 \varepsilon _{t-13}

> summary(mod.sarima)
Series: ADTS.train 
ARIMA(1,0,1)(0,1,1)[12] 

Coefficients:
         ar1      ma1     sma1
      0.9644  -0.7851  -0.8848
s.e.  0.0586   0.1284   0.0847

sigma^2 estimated as 201.2:  log likelihood=-788.79
AIC=1585.57   AICc=1585.79   BIC=1598.6

Training set error measures:
                    ME     RMSE      MAE       MPE    MAPE      MASE       ACF1
Training set -1.322366 13.65188 10.26076 -3.751509 12.7082 0.6881126 0.08705428


また、リュング・ボックス検定(Ljung-Box test)は非有意であり、自己相関がないと解釈する。コレログラムを見ても自己相関はなくなったようである。

> resid.sarima <- forecast::checkresiduals(mod.sarima)

    Ljung-Box test

data:  Residuals from ARIMA(1,0,1)(0,1,1)[12]
Q* = 18.737, df = 21, p-value = 0.602

Model df: 3.   Total lags used: 24

f:id:cochineal19:20210313002005p:plain:w500

SARIMAモデルでの予測は次のとおり(黒:観測値、青:予測値)。

fig.sarima <- ggplot() +
  geom_line(mapping=aes(x=1:length(mod.sarima$fitted), y=c(mod.sarima$x)), color="black", size=1) +
  geom_line(mapping=aes(x=1:length(mod.sarima$fitted), y=c(mod.sarima$fitted)), color="blue", size=2, alpha=.4) +
  labs(title=gsub("Residuals from ","",resid.sarima$data.name), x="", y="") +
  theme(plot.title=element_text(size=30)
        ,axis.title=element_text(size=25)
        ,axis.text=element_text(size=20))
plot(fig.sarima)

f:id:cochineal19:20210313002321p:plain:w400

SARIMAXモデルの実行


続いて続いて、回帰成分を入れてSARIMAXモデルを試してみる。
auto.arima に xreg = 回帰成分のデータ とすることで天候情報を加える。
平均気温のみ、相対湿度のみ、平均気温&相対湿度の計3パターンのモデルを作ってみるが、以降の例は平均気温のみのモデルで説明する。

mod.sarimax1 <- forecast::auto.arima(ADTS.train
                                    ,d = NA
                                    ,D = NA
                                    ,start.p  = 0
                                    ,start.q  = 0
                                    ,start.P  = 0
                                    ,start.Q  = 0
                                    ,seasonal = T
                                    ,xreg     = ADXREG.train[,1]  #-- 1列目の平均気温を投入
                                    ,stepwise  = F
                                    ,parallel  = T
                                    ,num.cores = 8
                                )


auto.arimaの結果、回帰成分を含めた ARIMA(1,1,2)(2,0,0)[12] がベストモデルとなった。

 \quad z_{t}=\Delta _{12}^{0} \Delta _{1}^{1} y_{t} = \Delta _{1}^{1} y_{t} = y_{t} - y_{t-1}

 \quad z_{t} = \beta _{1} x_{\verb|気温|, t} + \phi_{1} z_{t-1} + \Phi_{1} z_{t-1} - \phi_{1} \Phi_{1} z_{t-2} - \Phi_{2} z_{t-2} - \phi_{1} \Phi_{2} z_{t-3} + \varepsilon _{t} + \theta_{1} \varepsilon _{t-1} + \theta_{2} \varepsilon _{t-2}  \quad \Leftrightarrow z_{t} = -1.6775 x_{\verb|気温|, t} + 0.7233 z_{t-1} + 0.2089 z_{t-1} - 0.7233 \times 0.2089 z_{t-2} - 0.1610 z_{t-2} - 0.7233 \times 0.1610 z_{t-3} + \varepsilon _{t} -1.5227 \varepsilon _{t-1} + 0.5386 \varepsilon _{t-2}  \quad \Leftrightarrow z_{t} = -1.6775 x_{\verb|気温|, t} + 0.9322 z_{t-1} - 0.3121 z_{t-2} -0.1165 z_{t-3} + \varepsilon _{t} -1.5227 \varepsilon _{t-1} + 0.5386 \varepsilon _{t-2}

Series: ADTS.train 
Regression with ARIMA(1,1,2)(2,0,0)[12] errors 

Coefficients:
         ar1      ma1     ma2    sar1    sar2     xreg
      0.7233  -1.5227  0.5386  0.2089  0.1610  -1.6775
s.e.  0.1987   0.2304  0.2188  0.0718  0.0744   0.2372

sigma^2 estimated as 221.3:  log likelihood=-834.48
AIC=1682.95   AICc=1683.53   BIC=1706.15

Training set error measures:
                    ME     RMSE      MAE       MPE     MAPE      MASE        ACF1
Training set -1.544109 14.61906 11.72934 -4.971464 14.77754 0.7865994 0.003945916


また、リュング・ボックス検定(Ljung-Box test)は非有意であり、自己相関がないと解釈する。コレログラムを見ても自己相関はなさそうである。

> resid.sarimax1 <- forecast::checkresiduals(mod.sarimax1)

    Ljung-Box test

data:  Residuals from Regression with ARIMA(1,1,2)(2,0,0)[12] errors
Q* = 16.162, df = 18, p-value = 0.5812

Model df: 6.   Total lags used: 24

f:id:cochineal19:20210313023821p:plain:w400

なお、SARIMAXモデルでの予測は次のとおり(黒:観測値、青:予測値)。

fig.sarimax1 <- ggplot() +
  geom_line(mapping=aes(x=1:length(mod.sarimax1$fitted), y=c(mod.sarimax1$x)), color="black", size=1) +
  geom_line(mapping=aes(x=1:length(mod.sarimax1$fitted), y=c(mod.sarimax1$fitted)), color="blue", size=2, alpha=.4) +
  labs(title=gsub("Residuals from ","",resid.sarimax1$data.name), x="", y="") +
  theme(plot.title=element_text(size=30)
        ,axis.title=element_text(size=25)
        ,axis.text=element_text(size=20))
plot(fig.sarimax1)

f:id:cochineal19:20210313024018p:plain:w400

モデルの比較


以上、ARIMA、SARIMA、SARIMAX(平均気温のみ、相対湿度のみ、平均気温&相対湿度)の5モデルを試してみた。
このうち、残差診断で自己相関がないと解釈できたSARIMAとSARIMAXの2つを中心にどっちが良いか考えてみる。
1つの指標としてAICを見比べてみると、SARIMAモデルが良好のようである。

> #-- モデル比較
> mod.arima$aic
[1] 1735.168
> mod.sarima$aic
[1] 1585.574
> mod.sarimax1$aic #-- 平均気温
[1] 1682.954
> mod.sarimax2$aic #-- 相対湿度
[1] 1607.806
> mod.sarimax3$aic #-- 平均気温&相対湿度
[1] 1603.069


ただし、AICは長期予測の評価に不向きのようなので、準備していたテストデータを用いて予測値と実測値の差を評価する。

ということで、作成モデルでテスト期間の予測を行う。
予測は forecast::forecast関数で行う。hで予測期間、xregで回帰成分を指定する。

> pred.arima   <- forecast::forecast(mod.arima,   h=36)
> pred.sarima  <- forecast::forecast(mod.sarima,  h=36)
> pred.sarimax1 <- forecast::forecast(mod.sarimax1, h=36, xreg=ADXREG.test[,1]) #-- 平均気温
> pred.sarimax2 <- forecast::forecast(mod.sarimax2, h=36, xreg=ADXREG.test[,2]) #-- 相対湿度
> pred.sarimax3 <- forecast::forecast(mod.sarimax3, h=36, xreg=ADXREG.test) #-- 平均気温&相対湿度


予測ができたらforecast::accuracy関数でテスト期間の予実の差を評価する。
以下は見やすさのため round で丸めている。

> round(forecast::accuracy(pred.arima,   ADTS.test), 3)
                 ME   RMSE    MAE    MPE   MAPE  MASE   ACF1 Theils U
Training set -1.726 16.719 13.479 -6.194 17.247 0.904 -0.044        NA
Test set     -1.211 13.147 10.879 -6.628 19.018 0.730  0.365     0.943
> round(forecast::accuracy(pred.sarima,  ADTS.test), 3)
                  ME   RMSE    MAE     MPE   MAPE  MASE   ACF1 Theils U
Training set  -1.322 13.652 10.261  -3.752 12.708 0.688  0.087        NA
Test set     -10.897 17.996 15.191 -20.715 26.342 1.019 -0.010     1.168
> round(forecast::accuracy(pred.sarimax1, ADTS.test), 3) #-- 平均気温
                 ME   RMSE    MAE    MPE   MAPE  MASE  ACF1 Theils U
Training set -1.544 14.619 11.729 -4.971 14.778 0.787 0.004        NA
Test set     -3.952 12.655 11.232 -9.038 19.146 0.753 0.040     0.839
> round(forecast::accuracy(pred.sarimax2, ADTS.test), 3) #-- 相対湿度
                 ME   RMSE    MAE     MPE  MAPE  MASE  ACF1 Theils U
Training set -1.218 12.351  9.413  -3.579 11.73 0.631 0.044        NA
Test set     -6.153 13.265 10.371 -10.731 16.95 0.696 0.346     0.771
> round(forecast::accuracy(pred.sarimax3, ADTS.test), 3) #-- 平均気温&相対湿度
                 ME   RMSE    MAE     MPE   MAPE  MASE  ACF1 Theils U
Training set -1.295 12.145  9.311  -3.630 11.646 0.624 0.006        NA
Test set     -7.307 13.918 11.066 -12.473 18.296 0.742 0.303     0.815


実測値ベースで良く使われる指標としては、RMSE(Root Mean Square Error、二乗平均平方根誤差)やMAE(Mean Absolute Error、平均絶対誤差)がある。

 \quad RMSE=\sqrt{\dfrac{1}{n}\sum\left(y_{t} - \hat{y_{t}} \right)^2}

 \quad MAE=\dfrac{1}{n}\sum|y_{t} - \hat{y}_{t} |

RMSEもMAEも予実の差を見ているが、RMSEは二乗、MAEは絶対値を用いるため異常値に対する重みが違う。
異常値を厳しくみたいのであればRMSEの方が良いが、時系列に処理できないスパイクが複数出てしまうのであれば、MAEの方が実感にあうかもしれない。

また、相対的な指標(割合ベースの指標)としては、MAPE(Mean Absolute Percentage Error、平均絶対誤差率)やMASE(Mean Absolute Scaled Error、平均絶対尺度誤差)がある。
例えば横浜市だけでなく川崎市茅ヶ崎市など別地点のモデルとも比較したいのであれば、実測値ベースの評価指標では比較できないため、相対的な指標を用いると良い。

 \quad MAPE = \dfrac{100}{n}\sum^{n}_{t=1}| \dfrac{ y_{t} - \hat{y}_{t-1} }{y_{t}} |

 \quad MASE = \dfrac{MAE}{ \dfrac{1}{n-m}\sum^{n}_{t=m+1}|y_{t} - \hat{y}_{t-m}|}=\dfrac{MAE}{MAE^{*}_{m}}

MAPEは予実の差を実測値で割る性質から実測値 ≧ 予測値の時  [0,\ 1] 、実測値 ≦ 予測値の時  [ 0,\infty ] の範囲をとり、予測の上振れに大きく反応する。また、実測値に0があると割り算できず使用できない。
MASEは過去時点との差を分母にとる方法で「ナイーブな方法」と言われる。過去時点 m はラグ1や季節周期を用いる。過去時点でスケーリングするため、過学習に注意が必要となる。MAPEと異なり 0 があっても良い。



今回、MAPE・MASEで評価すると平均相対湿度を回帰成分にしたSARIMAXモデルが最も良好だった。
ただし、原系列の下降トレンドをうまく表現するために、人口構成なり住居特性の変化なり何かしら構造的な説明変数を組み込むことで更なる改善が期待される。
なお、ARIMA、SARIMA、SARIMAXの予測線を並べると次のようになった。

ggplot() +
  geom_line(mapping=aes(x=128:240, y=c(ADTS[128:240])), color="black", size=1) +
  geom_line(mapping=aes(x=(nt+1):240, y=c(pred.arima$mean),    color="arima1"), size=2, alpha=.4) +
  geom_line(mapping=aes(x=(nt+1):240, y=c(pred.sarima$mean),   color="arima2"), size=2, alpha=.4) +
  geom_line(mapping=aes(x=(nt+1):240, y=c(pred.sarimax1$mean), color="arima3"), size=2, alpha=.4) +
  geom_line(mapping=aes(x=(nt+1):240, y=c(pred.sarimax2$mean), color="arima4"), size=2, alpha=.6) +
  geom_line(mapping=aes(x=(nt+1):240, y=c(pred.sarimax3$mean), color="arima5"), size=2, alpha=.6) +
  labs(x="", y="", title="予測:モデル比較") +
  scale_colour_manual(
    name="モデル"
    ,values=c(arima1="blue", arima2="darkgreen", arima3="red", arima4="orange", arima5="gray")
    ,labels=c("ARIMA","SARIMA","SARIMAX\n(気温)","SARIMAX\n(湿度)","SARIMAX\n(気温&湿度)")) +
  scale_x_continuous(breaks=seq(128,240,by=12), labels=c(2010:2019)) +
  theme(plot.title=element_text(size=25)
        ,axis.text=element_text(size=20)
        ,legend.title=element_text(size=23)
        ,legend.text=element_text(size=20))

f:id:cochineal19:20210313150639p:plain

おわりに


以上、ARIMAモデル系をRで試してみた。
とは言っても auto.arima を使った簡易的な方法である。時系列分析は職人技と耳にしたことがあるが、最適なパラメータの設計はまさにそうなのだと思う。
また、回帰成分も簡単に入手できる天気のみにしたが、カレンダー効果、人口構造、木造・鉄筋の割合、耐火技術、天災、制度変更など他にも意味のある変数が考えられる。

SASでの実行は余力があるときにまた。

参考


Forecasting: Principles and Practice (2nd ed)
6.7 Prediction accuracy | Fisheries Catch Forecasting
http://www.ide.titech.ac.jp/~hanaoka/finalversion-of-conference.pdf
ExploratoryでProphetを使って時系列予測してみた(後編) | Tableau-id Press -タブロイド-

利用データ
月別火災発生件数 横浜市
気象庁|過去の気象データ・ダウンロード

※本ブログで作成したグラフ等は、上記「利用データ」を編集・加工して作成しています。本分析は解析方法・プログラミングの学習を目的としており、提案・提言等を行うものではありません。

【統計】時系列分析(AR、MA、ARMA、ARIMA、SARIMA、ARIMAXモデル)

本記事は、AR、MA、ARMA、ARIMA、SARIMA、ARIMAXモデル等の特徴について。

【目次】

計算式等


< 前提>

■ 弱定常性(Weakly stationary)
 時系列の期待値、分散および自己共分散が常に一定である状態(時点 t および k に依存しない状態)。単に定常性と言ったらこちらを指す。

\quad E[y_{t}]=\mu_{t}=\mu_{t-k}=\mu
\quad Var[y_{t}]=\sigma^{2} _{t}=\sigma^{2} _{t-k}=\sigma^{2}
\quad Cov \left(y_{t},\ y_{t-s} \right) = Cov \left(y_{t-k},\ y_{t-s-k} \right)


■ 強定常性(Strongly stationary)
 任意の時点の集合 {t1, t2, ..., tm} と k に対する時系列の同時密度関数 f が一定の状態(同時分布が同一となる場合)。

 \quad f \left(y_{t_{1}} \ _{,}\ y_{t_{2}} \ _{,}\ ...\ _{,}\ y_{t_{m}} \right) = f \left( y_{t_{1-k}}\ _{,}\ y_{t_{2-k}}\ _{,}\ ...\ _{,}\ y_{t_{m-k}} \right)


■ ホワイトノイズ(White noise、白色雑音)
 時系列の誤差項。正規分布であり、他の時点と自己相関がない。

\quad E[\varepsilon _{t}]=0, \quad Var[\varepsilon _{t}]=\sigma^{2}, \quad Cov[\varepsilon _{t},\ \varepsilon _{t-s}]=0


ランダムウォーク(Random walk)
 ホワイトノイズの累積和により得られる時系列。

 \quad y_{t} = \sum \varepsilon _{t}


<各モデル>

■ AR(p)モデル(AutoRegressive model、自己回帰モデル
 ラグpまでの過去時点(AR(p) 成分)を説明変数に投入して現時点を表すモデル。pは自己回帰の次数、Φは自己回帰係数。

 \quad y_{t} = c + \sum ^{p}_{s=1} \phi _{s} y_{t-s} + \varepsilon _{t}, \quad \varepsilon _{t}\sim W.N.\left( \sigma ^{2}\right)\quad\verb|※W.N.=ホワイトノイズ|

 ※AR(1) の時:
 \qquad y_{t} = c + \phi _{1} y_{t-1} + \varepsilon _{t}


■ MA(q)モデル(Moving Average model、移動平均モデル)
 ラグqまでの過去のホワイトノイズ(MA(q) 成分)を説明変数に投入して現時点を表すモデル。qは移動平均の次数、θは移動平均係数。

 \quad y_{t} = c + \varepsilon _{t} + \sum ^{q}_{s=1}\theta _{s}\varepsilon_{t-s},\quad \varepsilon _{t}\sim W.N.\left( \sigma ^{2}\right)

 ※MA(1) の時:
 \qquad y_{t} = c + \varepsilon _{t} + \theta _{1}\varepsilon_{t-1}


■ ARMA(p, q)モデル(AutoRegressive Moving Average model、自己回帰移動平均モデル
 AR(p) 成分とMA(q) 成分の両方を説明変数に投入して現時点を表すモデル。

 \quad y_{t} = c + \sum ^{p}_{s=1}\phi _{s}y_{t-s} + \varepsilon _{t} + \sum ^{q}_{s=1}\theta _{s}\varepsilon_{t-s},\quad \varepsilon _{t}\sim W.N.\left( \sigma ^{2}\right)

 ※ARMA(1,1) の時:
 \qquad y_{t} = c + \phi _{1}y_{t-1} + \varepsilon _{t} + \theta _{1}\varepsilon_{t-1}


■ ARIMA(p, d, q)モデル(AutoRegressive Integrated Moving Average model、自己回帰和分移動平均モデル)
 観測値の時系列に対して、近似的に定常な時系列が得られるまで d階の階差(和分プロセス)をとった後に、階差の時系列に対して、ARMA(p,q) モデルを当てはめるモデル。ARIMAモデルは前期と今期のラグ1の d階差をとる。

 和分プロセス:
 [ 1階差 ]
 \quad \Delta_{1} y_{t} = y_{t} - y_{t-1}

 [ 2階差 ]
 \quad \Delta _{1} \Delta _{1} y_{t} = \Delta _{1} y_{t} - \Delta _{1} y_{t-1} = \left(y_{t} - y_{t-1}\right) - \left(y_{t-1} - y_{t-1-1}\right) = y_{t} - 2 y_{t-1} + y_{t-2}

 ※ARIMA(p, 1, q) の時:
 \qquad z_{t} = \Delta _{1} y_{t}
 \qquad z_{t} = c + \sum ^{p}_{s=1}\phi _{s} z_{t-s} + \varepsilon _{t} + \sum ^{q}_{s=1}\theta _{s}\varepsilon_{t-s},\quad \varepsilon _{t}\sim W.N.\left( \sigma ^{2}\right)

 ※ARIMA(1, 1, 1) の時:
 \qquad z_{t} = c + \phi _{1} z_{t-1} + \varepsilon _{t} + \theta _{1}\varepsilon_{t-1}


※追記:SARIMAとARIMAXを加えます。
■ SARIMA(p, d, q)(P, D, Q)[m] モデル(Seasonal AutoRegressive Integrated Moving Average model、季節自己回帰和分移動平均モデル)
 ARIMAモデルと同じ要領でラグ m の季節階差(D階差)をとった後にARMAを当てはめるモデル。ラグ演算子(Lm)を用いて表現する。ラグ演算子の上付き文字はラグを表す(Lm yt = yt-m)。

 \quad \phi \left( L \right) \Phi \left( L^{m}\right) \Delta _{m}^{D} \Delta _{1}^{d} y_{t} = c + \theta \left( L\right) \Theta \left( L^{m}\right) \varepsilon _{t}

 \qquad \phi \left( L \right) = 1 - \phi_{1}  L^{1} - \phi_{2}  L^{2} - ... -  \phi_{p}  L^{p} = 1 - \sum ^{p}_{k=1} \phi_{k}  L^{k}
 \qquad \Phi \left( L^{m} \right) = 1 - \Phi_{1}  L^{m} - \Phi_{2}  L^{2m} - ... -  \Phi_{P}  L^{P\cdot m} = 1 - \sum ^{P}_{k=1} \Phi_{k}  L^{k\cdot m}
 \qquad \theta \left( L \right) = 1 + \theta_{1}  L^{1} + \theta_{2}  L^{2} + ... +  \theta_{q}  L^{q} = 1 + \sum ^{q}_{k=1} \theta_{k}  L^{k}
 \qquad \Theta \left( L^{m} \right) = 1 + \Theta_{1}  L^{m} + \Theta_{2}  L^{2m} + ... +  \Theta_{Q}  L^{Q\cdot m} = 1 + \sum ^{Q}_{k=1} \Theta_{k}  L^{k\cdot m}

  \theta \left( L \right) \Theta \left( L^{m} \right) について、演算子をプラスで示している文献とマイナスで示している文献の両方ある。ホワイトノイズは正規分布を仮定するためどちらでも良いということだろうか。

 ※SARIMA(1, 1, 1) (1, 1, 1) [12] の時(階差と12周期季節階差の2階差):
 \qquad z_{t}=\Delta _{12}^{1} \Delta _{1}^{1} y_{t} = \Delta _{12}^{1} y_{t} - \Delta _{12}^{1} y_{t-1} = \left(y_{t} - y_{t-12}\right) - \left(y_{t-1} - y_{t-1-12}\right) = y_{t} - y_{t-12} - y_{t-1} + y_{t-13}

 \qquad \phi \left( L \right) \Phi \left( L^{12}\right) z_{t} = c + \theta \left( L\right) \Theta \left( L^{12}\right) \varepsilon _{t}
 \qquad \Leftrightarrow \left( 1 - \phi_{1} L^{1} \right) \left( 1 - \Phi_{1} L^{12} \right) z_{t} = c + \left( 1 + \theta_{1} L^{1} \right) \left( 1 + \Theta_{1} L^{12} \right)  \varepsilon _{t}
 \qquad \Leftrightarrow \left( 1 - \phi_{1} L^{1} - \Phi_{1} L^{12} + \phi_{1} \Phi_{1} L^{13} \right) z_{t} = c + \left( 1 + \theta_{1} L^{1} + \Theta_{1} L^{12} + \theta_{1} \Theta_{1} L^{13} \right)  \varepsilon _{t}
 \qquad \Leftrightarrow z_{t} - \phi_{1} z_{t-1} - \Phi_{1} z_{t-12} + \phi_{1} \Phi_{1} z_{t-13} = c + \varepsilon _{t} + \theta_{1} \varepsilon _{t-1} + \Theta_{1} \varepsilon _{t-12} + \theta_{1} \Theta_{1} \varepsilon _{t-13}
 \qquad \Leftrightarrow z_{t} = c + \phi_{1} z_{t-1} + \Phi_{1} z_{t-12} - \phi_{1} \Phi_{1} z_{t-13} + \varepsilon _{t} + \theta_{1} \varepsilon _{t-1} + \Theta_{1} \varepsilon _{t-12} + \theta_{1} \Theta_{1} \varepsilon _{t-13}

 ※季節の自己回帰係数  \Phi_{1}移動平均係数  \Theta_{1} を0にすれば、ひとつ上のARIMAの例で取り上げたARIMA(1, 1, 1) と同じになる。
 \qquad z_{t} = c + \phi _{1} z_{t-1} + \varepsilon _{t} + \theta _{1}\varepsilon_{t-1}


■ ARIMAXモデル(AutoRegressive Integrated Moving Average with eXogenous variables、外生変数付き自己回帰和分移動平均モデル)
 ARIMAモデルに回帰成分 β x (外生変数、eXogenous vriables)を組み込んだモデル。例として閏日や祝日などのカレンダー効果、気温・降水量などの天候、災害や制度変更での水準変動を表す干渉シフト(一定期間フラグを立てる)などを導入する。

 \quad z_{t} = c + \beta x_{t} + \sum ^{p}_{s=1}\phi _{s}z_{t-s} + \varepsilon _{t} + \sum ^{q}_{s=1}\theta _{s}\varepsilon_{t-s},\quad \varepsilon _{t}\sim W.N.\left( \sigma ^{2}\right)


ノート


上に示した過程はARIMAモデルで表すことができる(SARIMA、ARIMAX除く)。

・ARIMA(0,0,0):ホワイトノイズ
・ARIMA(0,1,0):ランダムウォーク
・ARIMA(p,0,0):AR(p)モデル
・ARIMA(0,0,q):MA(q)モデル
・ARIMA(p,0,q):ARMA(p,q)モデル
・ARIMA(p,d,q):ARIMA(p,d,q)モデル

また、MA(q) モデルは時点 t に依存しないため常に定常だが、
AR(p) モデルは、次に示す特性方程式の解(複素解含む)の絶対値がすべて1未満であることが、定常性の必要十分条件と言われる。

\quad 1 = \sum \phi_{s} z^{s} = \phi_{1} z^{1} + \phi_{2} z^{2} + ... + \phi_{s} z^{s}


AR(1) モデルなら 1 < |Φ1| の場合。つまり、Φ1 が1を超えると非定常になってしまう。


ここからは、自己回帰係数Φと平均移動係数θの違いによる振る舞いを見てみる。

次のように適当な定数項 c とホワイトノイズ( =NORM.INV(RAND(),0,0.5) )を準備し、n=150 の観測値の時系列を作成。
Excelでの例示は雑なのでイメージ程度にとどめてほしい。また、ARモデルの初期値は0にしている。
f:id:cochineal19:20210307162430p:plain

この観測値の時系列に対して、AR(1) とMA(1) モデルを当てはめて、自己回帰係数Φと平均移動係数θによる変化を見てみる。

f:id:cochineal19:20210307171843p:plain
f:id:cochineal19:20210307171921p:plain
f:id:cochineal19:20210307171951p:plain
f:id:cochineal19:20210307172016p:plain
f:id:cochineal19:20210307172120p:plain
f:id:cochineal19:20210307172145p:plain
f:id:cochineal19:20210307172215p:plain
f:id:cochineal19:20210307172238p:plain

先ほどの AR(1) モデルの定常性条件(1 < |Φ1| )を頭に入れて見てみると、自己回帰係数Φの絶対値が1以上の Φ=1.1 と Φ=-1.1 で非定常になっていることが良く分かる(予測モデルとして使えない)。
また、MA(1) モデルは定数項 c 付近でバラつく定常な時系列であることが分かる。

次に、先ほどの観測値の時系列にトレンド(時点毎に 0.5 増える)を加えてみる。このトレンド付きの時系列について、ラグ1の1階差(d=1)をとったときの振る舞いを見てみる。
※こちらも例示は雑なのでイメージ程度にとどめてほしい。また、初期値は0にしている。
f:id:cochineal19:20210307165011p:plain

1階差をとった後、階差の時系列が定常になったことが分かる。

今回、AR(1) とMA(1) モデルでいくつかと1階差を1つ例示したが、ARIMA(p,d,q) でどのようなパラメタ設定が良いか(ベストモデルは何か)は、AICやRMSE等の評価指標を用いて判断する。
r では forecastパッケージでここらができるので次回記事にしたい。
SAS にも proc ARIMA があるので余裕があれば。


なお、ARIMA(p,d,q) に従う観測値の時系列は、r の stats::arima.sim関数で比較的簡単に作れるので備忘録がてらメモする。

stats::arima.sim(model=list(order=c(p,d,q), ar=c(x,...), ma=c(x,...), n=x))

AR(p)、MA(q) に従う観測値の時系列:

library(tidyverse)
set.seed(1)
ads1 <- data.frame()
ads1 <- union_all(ads1, data.frame(x=1:200, AVAL=arima.sim(model=list(order=c(1,0,0), ar=c(0.3)),         n=200), TYPE="01. AR(1)  Φ1 = 0.3"))
ads1 <- union_all(ads1, data.frame(x=1:200, AVAL=arima.sim(model=list(order=c(2,0,0), ar=c(0.3,0.5)),     n=200), TYPE="02. AR(2)  Φ1 = 0.3, Φ2 = 0.5"))
ads1 <- union_all(ads1, data.frame(x=1:200, AVAL=arima.sim(model=list(order=c(3,0,0), ar=c(0.3,0.5,0.1)), n=200), TYPE="03. AR(3)  Φ1 = 0.3, Φ2 = 0.5, Φ3 = 0.1"))
ads1 <- union_all(ads1, data.frame(x=1:200, AVAL=arima.sim(model=list(order=c(0,0,1), ma=c(0.3)),         n=200), TYPE="04. MA(1)  θ1 = 0.3"))
ads1 <- union_all(ads1, data.frame(x=1:200, AVAL=arima.sim(model=list(order=c(0,0,2), ma=c(0.3,0.5)),     n=200), TYPE="05. MA(2)  θ1 = 0.3, θ2 = 0.5"))
ads1 <- union_all(ads1, data.frame(x=1:200, AVAL=arima.sim(model=list(order=c(0,0,3), ma=c(0.3,0.5,0.1)), n=200), TYPE="06. MA(3)  θ1 = 0.3, θ2 = 0.5, θ3 = 0.1"))

ggplot(ads1, aes(x=x, y=AVAL)) +
  geom_line() + facet_wrap(. ~ TYPE, ncol=3)

f:id:cochineal19:20210307180214p:plain

ARMA(p,q) に従う観測値の時系列:

set.seed(1)
ads2 <- data.frame()
ads2 <- union_all(ads2, data.frame(x=1:200, AVAL=arima.sim(model=list(order=c(1,0,1), ar=c(0.3),         ma=c(0.3)),         n=200), TYPE="01. ARIMA(1,0,1) \n Φ1 = 0.3 \n θ1 = 0.3"))
ads2 <- union_all(ads2, data.frame(x=1:200, AVAL=arima.sim(model=list(order=c(2,0,2), ar=c(0.3,0.5),     ma=c(0.3,0.5)),     n=200), TYPE="02. ARIMA(2,0,2) \n Φ1 = 0.3, Φ2 = 0.5 \n θ1 = 0.3, θ2 = 0.5"))
ads2 <- union_all(ads2, data.frame(x=1:200, AVAL=arima.sim(model=list(order=c(3,0,3), ar=c(0.3,0.5,0.1), ma=c(0.3,0.5,0.1)), n=200), TYPE="03. ARIMA(3,0,3) \n Φ1 = 0.3, Φ2 = 0.5, Φ3 = 0.1 \n θ1 = 0.3, θ2 = 0.5, θ3 = 0.1"))
ggplot(ads2, aes(x=x, y=AVAL)) +
  geom_line() + facet_wrap(. ~ TYPE, ncol=3)

f:id:cochineal19:20210307181223p:plain
ARIMA(p,d,q) に従う観測値の時系列:

set.seed(1)
ARIMA212 <- data.frame(y=arima.sim(model=list(order=c(2,1,2), ar=c(0.3,0.5), ma=c(0.3,0.5)), n=200), id=1:201)
ggplot(data=ARIMA212, mapping=aes(x=id, y=y)) +
  geom_line() +
  labs(title="ARIMA(2,1,2)", subtitle="(AR: Φ1 = 0.3, Φ2 = 0.5,  MA: θ1 = 0.3, θ2 = 0.5)"
       ,x="時点", y="", caption="🄫Cochineal19") +
  theme(plot.title=element_text(size=30)
        ,plot.subtitle=element_text(size=25)
        ,axis.title=element_text(size=25)
        ,axis.text=element_text(size=20))
 
set.seed(1)
ARIMA222 <- data.frame(y=arima.sim(model=list(order=c(2,2,2), ar=c(0.3,0.5), ma=c(0.3,0.5)), n=200), id=1:202)
ggplot(data=ARIMA222, mapping=aes(x=id, y=y)) +
  geom_line() +
  labs(title="ARIMA(2,2,2)", subtitle="(AR: Φ1 = 0.3, Φ2 = 0.5,  MA: θ1 = 0.3, θ2 = 0.5)"
       ,x="時点", y="", caption="🄫Cochineal19") +
  theme(plot.title=element_text(size=30)
        ,plot.subtitle=element_text(size=25)
        ,axis.title=element_text(size=25)
        ,axis.text=element_text(size=20))

f:id:cochineal19:20210307182908p:plain:w400
f:id:cochineal19:20210307182949p:plain:w400

本日は時系列の特徴について。ここまで。

参考


統計学(出版:東京図書), 日本統計学会編
カルマンフィルタ Rを使った時系列予測と状態空間モデル(出版:共立出版), 野村俊一
http://elsur.jpn.org/202004MMM/chap5.pdf
http://yuchimatsuoka.github.io/seminar/timeseries1.pdf
3.3 Model structure | Fisheries Catch Forecasting
【ML Tech RPT. 】第17回 構造に関連する機械学習を学ぶ (3) ~時系列予測~ - Sansan Builders Blog


サイトマップ

cochineal19.hatenablog.com

本ブログは個人メモです。 本ブログの内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。