StatModeling Memorandum

StatModeling Memorandum

StanとRとPythonでベイズ統計モデリングします. たまに書評.

Stanで1変数の積分を実行する

Stan2.19でモデルの内部で1変数の積分を実行する機能が追加されましたので簡単に紹介します。Stan2.19がCRANにないとお嘆きのアナタ!GitHubからインストールすればよろし。Windowsならば、Benさんがここに書いてくれた方法でバイナリを直接インストールすることもできます。ただし、他のパッケージとの依存関係は壊れてもしーらん。

積分する関数名は現在のところintegrate_1dです。使い方はStanのマニュアルに載っているかなと期待したけどまだ載ってませんでした。reference manualには少しだけ触れられているけど、これだけではさっぱり分からないです。こういう場合は、StanのdiscouseGitHubリポジトリで検索して、手あたりしだい見ていくと知見が蓄積されます。結局、GitHubリポジトリ内で新しい関数のテストをしているディレクトリがあり、そこに使用例がありました。

この記事では階層モデルの場合に、積分を使って対数尤度を算出する例を扱います。階層モデルの場合には複数の予測したい量が考えられて、それに応じた対数尤度(および情報量規準)が考えられるのでした。

statmodeling.hatenablog.com

ここでは上記の記事でいうところの「モデル2の(3)」に対応する予測を扱います。すなわち、別の新しいクラスができて新しく1人が加わる場合です。この場合、予測分布はグループの平均を積分消去した分布になります。

先にデータ生成およびStanを実行するRコードから説明します。

library(rstan)

G      <- 10
N_by_G <- 2
N      <- N_by_G * G
GID    <- rep(1:G, N_by_G)

set.seed(2)
Mu <- rnorm(G, mean=0, sd=10.0)
Y  <- rnorm(N, mean=Mu[GID], sd=2.0)

data <- list(N=N, G=G, N_by_G=N_by_G, GID=GID, Y=Y)
stanmodel <- stan_model(file='model/model.stan')
fit <- sampling(stanmodel, data=data, iter=3500, warmup=1000, seed=123)

library(loo)
ms <- rstan::extract(fit)
waic  <- waic(ms$log_lik)$waic/(2*N)
looic <- loo(ms$log_lik)$looic/(2*N)
  • 3行目: グループの数です。
  • 4行目: 1グループに何人いるかです。
  • 5行目: 全部で何人いるかです。ここでは20人です。
  • 9行目: 各グループの平均を生成しています。
  • 10行目: 9行目で生成した値を平均として、各グループに含まれる人たちの値を生成しています。
  • 16~19行目: 対数尤度のサンプリング結果から(3)の場合のWAICとLOOICを算出しています。

Stanコードは以下です。

functions {
  real f(real x, real xc, real[] par, real[] y_r, int[] y_i) {
    return exp(normal_lpdf(x   | par[1], par[2]) +
               normal_lpdf(y_r | x,      par[3]));
  }

  real log_lik_marginal(real[] Y, real[] par) {
    return log(integrate_1d(f, par[1]-6*par[2], par[1]+6*par[2], par,
                            Y, {0}, 1e-3));
  }
}

data {
  int G;
  int N;
  vector[N] Y;
  int GID[N];
}

parameters {
  real mu0;
  real<lower=0> s0;
  vector[G] mu;
  real<lower=0> sigma;
}

model {
  mu0 ~ student_t(6, 0, 10);
  s0 ~ student_t(6, 0, 10);
  mu ~ normal(mu0, s0);
  Y ~ normal(mu[GID], sigma);
}

generated quantities {
  vector[N] log_lik;
  real mu_pred = normal_rng(mu0, s0);
  real y_pred = normal_rng(mu_pred, sigma);
  for (n in 1:N)
    log_lik[n] = log_lik_marginal({Y[n]}, {mu0, s0, sigma});
}
  • 2~5行目: 被積分関数です。現状ではこの引数タイプ(real, real, real[], real[], int[])に限るようです。1番目の引数は積分で動く変数、2番目は後述、3番目の引数はパラメータの配列、4番目の引数は実数値をとるデータの配列、5番目の引数は整数値をとるデータの配列です。2番目の引数はどんなときに使うべきか不明だけど、たぶん3番目の引数とは切り離して考えたいパラメータを入れるのに使うのかなぁ…。
  • 7~10行目: 積分して対数尤度を求める関数の定義です。integrate_1d関数の、1番目の引数は関数名、2番目の引数は積分範囲の下限、3番目の引数は積分範囲の上限、4番目の引数は関数に渡すパラメータの配列、5番目の引数は関数に渡す実数値をとるデータの配列、6番目の引数は関数に渡す整数値をとるデータの配列、7番目の引数は積分の相対的な誤差をどれくらいに抑えるか、です。最近のStanでは{}で囲むと配列となり、[]で囲むとvectorとなります。
  • 39行目: ここで対数尤度を求めています。

実際に実行してみると、Rでデータを作成するときの乱数をset.seed(1)の場合には情報量規準の算出までいきますが、set.seed(2)の場合には以下のエラーが出てサンプリングが止まってしまいます。

...(中略)...
Chain 2: 
[1] "Error in sampler$call_sampler(args_list[[i]]) : "                                                                                                                                                      
[2] "  Exception: Exception: integrate: error estimate of integral above zero 1.80655e-006 exceeds the given relative tolerance times norm of integral above zero  (in 'model2f8834cb4d93_model' at line 8)"
[3] "  (in 'model2f8834cb4d93_model' at line 39)"                                                                                                                                                           
[1] "error occurred during calling the sampler; sampling not done"

Stanのintegrate_1dは内部的にはBoostのintegrate_1dを使っているようですが、どうもやや不安定な気がします。GSLのCQUADの方が安定しています({RcppGSL}で使う例はこちら)。また、尤度を算出するような場合、どこかに対数をいれて積分しないと値が小さくなりすぎて数値的に不安定になります。以前log_sum_expとシンプソンの公式を使う方法は一例ですが、特化した効率の良い方法がありそうです。今後に期待します。いや、お前がやるんだよ。

統計・機械学習・R・Pythonで用途別のオススメ書籍

比較的読みやすい本を中心に紹介します。今後は毎年このページを更新します。

微分積分

高校数学をきちんとやっておけばそんなに困ることないような。偏微分テイラー展開は大学演習のような本でしっかりやっておきましょう。ラグランジュの未定乗数法のような、統計・機械学習で必要になる部分は、ネット等で学べばいいかなと思っています。

線形代数

tensorflowなどのおかげで順伝播部分(行列積および行列とベクトルの積)さえ書ければ線形代数の知識はそこまでいらないんじゃないかという流れを感じます。しかし、主成分分析やトピックモデルなどの行列分解や、ガウス過程などのカーネル法のような様々なデータ解析の手法に一歩踏み込むと、きちんとした勉強が必要になります。理解しやすくて使いやすくて、統計や機械学習への応用を主眼においた線形代数の本はまだ見たことないです。機械学習シリーズとかで基礎から「The Matrix Cookbook」*1までを視野に入れた本が出てきてくれると良いのですが。

以下では個人的な好みの教科書を挙げておきます。「線形代数とその応用」です。ちなみにこれは第1版の翻訳ですが、原著の方は第4版まで出ています。

線形代数とその応用

線形代数とその応用

統計学入門

色々読んでみましたが、現在決定版と言えるものは存在しないように思えました。個人的には、シグマと積分の復習、場合の数・数え上げの方法、確率、確率変数、確率密度、度数分布とヒストグラム、代表値・平均・分散、確率分布、同時分布、周辺分布、確率変数の変数変換、検定、散布図と箱ひげ図、回帰、相関あたりをRやPythonなどを使いながらシンプルに説明していく本があるといいと思うのですが、なかなかバランスのとれたいい本がありません。初歩の初歩しか説明してない、グラフが少ない、検定にページを割きすぎ、分厚い、ちょっと難しいなどの不満点があります。立ち読みして自分にあった本を選ぶのがいいと思います。

読み物では大村平先生のシリーズをオススメします。僕は「確率のはなし」「統計のはなし」「統計解析のはなし」「多変量解析のはなし」「実験計画と分散分析のはなし」「ORのはなし」を持っていますが、どれも読みやすくて面白いです。特に「統計解析のはなし」「実験計画と分散分析のはなし」「ORのはなし」が面白かった記憶があります。

統計解析のはなし―データに語らせるテクニック (Best selected Business Books)

統計解析のはなし―データに語らせるテクニック (Best selected Business Books)

ORのはなし―意思決定のテクニック

ORのはなし―意思決定のテクニック

統計学演習

統計の実力向上のためには、「紙と鉛筆で手を動かして計算する」という経験がどこかで必要になります。そこで、シグマと積分はすでに慣れ親しんで、統計の初歩は少し知っている人に「統計学演習」をオススメします。

統計学演習

統計学演習

演習問題の難易度と内容が素晴らしいです。しかし、演習の前にある簡潔なまとめは説明がないので、復習として使うのがよいでしょう。

Rを使って機械学習に詳しくなりたい

RやPythonを使って機械学習をやってみようという本は多いのですが、手法の背後にある考え方までもきちんと説明している本はあまり見たことありません。その中で「Rによる統計的学習入門」は非常にオススメです。

Rによる 統計的学習入門

Rによる 統計的学習入門

  • 作者: Gareth James,Daniela Witten,Trevor Hastie,Robert Tibshirani,落海浩,首藤信通
  • 出版社/メーカー: 朝倉書店
  • 発売日: 2018/08/03
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログ (1件) を見る

原著は「An Introduction to Statistical Learning with Applications in R」でここからpdfがダウンロードできます。著者の中はあのHastie先生とTibshirani先生もいます。この本をもとにしたオンライン授業もここから無料で受講することができます。阪大などの授業でも使われているようです。

Rを使って伝統的な統計手法に詳しくなりたい

「Rで楽しむ統計」がオススメです。統計解析で陥りやすいミスなども随所にあって面白いです。例えば、正規性の検定をしてからt検定をするような二段階検定がたまに行われているのを見かけますが、それがいけない理由は??

Rで楽しむ統計 (Wonderful R 1)

Rで楽しむ統計 (Wonderful R 1)

Pythonを使って機械学習に詳しくなりたい

「第2版 Python機械学習プログラミング」をオススメします。第1版の書評を以前書きました。

「Python機械学習プログラミング」 Sebastian Raschka(著), 株式会社クイープ(訳), 福島真太朗(監訳) - StatModeling Memorandum

[第2版]Python 機械学習プログラミング 達人データサイエンティストによる理論と実践 (impress top gear)

[第2版]Python 機械学習プログラミング 達人データサイエンティストによる理論と実践 (impress top gear)

Pythonを使って統計をはじめたい

Pythonで理解する統計解析の基礎」をオススメします。易しいところを主にカバーしています。Pythonの初歩と統計の初歩のバランスが良いです。

Pythonで理解する統計解析の基礎 (PYTHON×MATH SERIES)

Pythonで理解する統計解析の基礎 (PYTHON×MATH SERIES)

Rの初歩と伝統的な統計を知っている人が統計モデリングをはじめたい

「データ解析のための統計モデリング入門」をオススメします。一般化線形モデルを含めて一歩ずつ学んでいきます。Rのコマンドの説明も丁寧で親切です。

プログラミング少しできる人が統計モデリングに詳しくなりたい

「StanとRでベイズ統計モデリング」をオススメします。StanEdwardPyroなどと同様の確率的プログラミング言語で、高次元のパラメータ空間からサンプリングを効率的に行えるのが特徴です。今後、確率的プログラミング言語で新しい独自モデルを試行錯誤していきたい人にとっても一読の価値があると思います。

因果推論や効果測定を詳しく知りたい

「岩波データサイエンス vol.3」がオススメです。統計を扱う上で非常に重要なのが因果関係ですが、この本を除いて読みやすい類書がほとんどありません。傾向スコアだけでなく、反実仮想を考えた回帰モデルやRCT(ランダム化比較試験)との対応がきちんと書いてあって勉強になりました。

岩波データサイエンス Vol.3

岩波データサイエンス Vol.3

Rのデータ処理や可視化に詳しくなりたい

Rといえばデータ処理能力と作図能力がずば抜けています。これらについては「RユーザのためのRStudio実践入門」をオススメします。Rの新しめの文法がメインですが、これから主流になっていくことは間違いないと思っていますので、ここから入門でよいと思います。

RユーザのためのRStudio[実践]入門−tidyverseによるモダンな分析フローの世界−

RユーザのためのRStudio[実践]入門−tidyverseによるモダンな分析フローの世界−

プログラミング言語としてのRに詳しくなりたい

「Rプログラミング本格入門: 達人データサイエンティストへの道」がオススメです。Rubyなど他のプログラミング言語に慣れているようなエンジニアに特に向いていると思います。前半はRの簡潔で良質なまとめ、後半はメタプログラミング・データベース操作・高速化手法など中級者向けの話題です。統計手法はあまり載っていません。僕はR言語徹底解説は8章から難しくなってきて読み切れなかったのですが、この本は読み切ることができました。

Rプログラミング本格入門: 達人データサイエンティストへの道

Rプログラミング本格入門: 達人データサイエンティストへの道

Stanにもっと詳しくなりたい

Stanのマニュアルがオススメです。日本語化プロジェクトがあり、少し前のバージョンですが主要パートについては日本語訳もほとんど完成しています(ここ)。現在は原文に忠実にするよりも、より大胆にそぎ落として分かりやすい日本語にするのを目標にしてます。もともとの英語が難しく訳に苦戦している箇所もあるので、勉強がてら是非プロジェクトへの参加をお待ちしております。 github.com

*1:研究者にとってハンドブック的に有名な本。行列の微分とかが載ってます。pdf file

TensorFlowで統計モデリング

とある勉強会で「TensorFlowで統計モデリング」というタイトルで講義をしました。聴衆はPythonユーザが多く、データ量が大きい問題が多そうだったので、StanよりもTensorFlowで点推定するスキルを伸ばすとメリットが大きいだろうと思ってこのようなタイトルになりました。

発表資料は以下になります。

発表資料の途中に出てくるtf_tutorial.htmlmodeling.htmlの内容は、以下のipynbをhtmlで出力したものです(見づらかったらプログラム名のところをクリックしてGitHubに移動して見てください)。 ちなみに僕が紹介しているTensorFlowの書き方はEager Executionではなく、Define and Runのやや古い書き方です。あまり気にしていませんけど。

ここではTensorFlowを使った点推定による統計モデリングを紹介しましたが、Edward2やTensorFlow ProbabilityやPyMCといった確率的プログラミング言語を使えば、ベイズ推定による統計モデリングも可能です。しかしながら、現状ではこれらのベイズ推定の質があまり良いと感じないので、個人的にはベイズ推定でやる場合にはStan、点推定でやる場合にはTensorFlowという使い分けにしています。

Enjoy!