自分用メモ。DPMにおいてハイパーパラメータのサンプリングをする必要がある場合、Gamma分布からサンプリングしてこなければならない。「Boostさんにお願いしてどうにかしてもらおう...」と思っていたところ、BoostさんはGamm分布の1変数のバージョンでしかAPIを提供していないということに気づいてしばらく止まる。
Gamma分布のpdf*1は、shape parameter k、scale parameter を用いて
と書ける。Boostさんはこのscale parameter がの場合しか提供していないということである。しかし、shapeをあれこれ変えた場合のサンプリングも容易にできる。scaleのほうをfixすると
となるが、この場合で元の式でと変数変換すればこの式。ゆえにBoostさんで提供されているGamma分布でshapeを指定して乱数を生成し、その値をscaleで「かければ」両方指定したものと同じということである。まどろっこしい...。
プログラム
念のため実験して確かめる。Gamma分布の期待値はであるが、それに近い感じになるかを確かめる。#include <iostream> #include <boost/random.hpp> template<class D, class G = boost::mt19937> class Rand { G gen_; D dst_; boost::variate_generator<G, D> rand_; public: Rand() : gen_(static_cast<unsigned long>(time(0))), rand_(gen_, dst_) {} template<typename T1> Rand(T1 a1) : gen_(static_cast<unsigned long>(time(0))), dst_(a1), rand_(gen_, dst_) {} template<typename T1, typename T2> Rand(T1 a1, T2 a2) : gen_(static_cast<unsigned long>(time(0))), dst_(a1, a2), rand_(gen_, dst_) {} typename D::result_type operator()() { return rand_(); } }; int main(int argc, char *argv[]) { double shape = 10.0; double scale = 2.0; Rand<boost::gamma_distribution<> > rgamma(shape); double result = 0.0; int N = 1000; for (int i = 0; i < N; i++) { result += rgamma() * scale; } std::cout << (double) result / N << std::endl; }
それっぽい値になったので大丈夫そうである。
% g++ gamma.cpp; ./a.out
20.0174
注意
ひじょーにconfusingなんだけど、Gamma分布はとパラメタライズされることがある(PRMLなどはこっちの形式で書かれていて自分もこっちに慣れている)。この場合、上のコードで「かけているところ」は「割らないといけない」ことに注意しよう。というか、この違いではまって「変な乱数生成されてるけどなんで...」としばらくはまったのであった。。。
参考
- Gamma (and Erlang) Distribution - 1.39.0
- c++ - Gamma Distribution in Boost - Stack Overflow
- Random number generation using C++ TR1
- 作者: 石井健一郎,上田修功
- 出版社/メーカー: オーム社
- 発売日: 2014/08/26
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
*1:probability density function。ちなみに累積のほうはCDF