様々な確率分布とC++を使った乱数生成

<これはKogakuin Univ Advent Calendar 2020 10日目の記事です>

はじめに

どうも2年ぶりです、Linebrackと申します。 嫌な事件だったね…(去年のアドベントカレンダー)
まあ、気を取り直して今年も(?)書きます。

背景と目的

最近はPythonベイズ推定について学んでいます。このような分野では確率分布という概念を積極的に扱いまして、乱数の生成とも密接な関係を持っています。中でも、乱数生成に興味を持っている人は多いのではないかと思います。そのため、今回は確率分布に従った乱数を生成しようと思います。具体的には、C/C++を使って、一様分布、正規分布、ベータ分布、ポアソン分布の疑似乱数を生成します。そして、pythonヒストグラムを書いて実際の確率密度関数と比較して妥当か調べます。

理論

確率分布

まず、とは確率変数に対して、各々の値をとる確率を表したものである(Wikiより)。ここで、確率変数とは確率的に様々な値をとる変数であり、離散的なものと連続的なものがある。離散の例としては、サイコロの出目X∈{1,2,..,5,6}がわかりやすい。一方、連続なものは文字通り連続的な出力が得られるものである。もし、得られたデータから確率分布を見たい場合はヒストグラムを書いてみるといいだろう。また、代表的な確率分布には確率密度関数というものが決まっており、X=xのとき、確率p(X=x)を計算することができる。さて、代表的な確率密度関数を見てみよう。

一様分布

 一様分布は、確率変数がどの値でも確率が同じ分布である。下図は連続な場合であるが、aからbの範囲の乱数が一様に得られることを示す。これは、C言語でいうrand()関数で生成できる。また、他の乱数生成アルゴリズムとして線形合同法メルセンヌツイスタが利用できる。

f:id:linebrack:20201210020107p:plain
連続一様分布(Wikipediaより)

正規分布

 正規分布は、平均μ,標準偏差σからなる確率分布である。下図のような中心で確率が最も高く、離れるほど確率が低くなるような分布となっているが、これが実世界の多くの現象にあてはまる。例えば、身長が平均に近い人と身長が極端に高い人の比率を考えると、平均に近い人の方が多くいると考えられる。 f:id:linebrack:20201210021555p:plain

様々な正規分布(Wikiより)

ベータ分布

 ベータ分布はベイズ推定によく使われる分布である。パラメータはaとbを持ち、それはa-1回当たり、b-1回外れるときの分布に対応している。具体的な説明は省くが、もっと詳しく知りたい方は

ベータ分布の意味と平均・分散の導出 | 高校数学の美しい物語

f:id:linebrack:20201210022205p:plain

ベータ分布の確率密度関数(wikiより)

ポアソン分布

 ポアソン分布は、ランダムなイベントが一定時間内に何回発生するかの分布である。パラメータはλで、イベントが単位時間内に平均λ回起きることに対応している。また、ポアソン分布の乱数は回数となるため離散であることに注意する。これも具体的な説明は省きますが、

ポアソン分布の意味と平均・分散 | 高校数学の美しい物語 参考にどうぞ。

乱数生成の実験

一様分布の乱数

ここでは、以下の方法を用いて0から1の連続な乱数をとることを考える。

線形合同法

 CongruenceMethodクラスとして実装した。a,b,cの値を決めることで、合同式による漸化式の更新で乱数を生成することができる。

メルセンヌツイスタ

 具体的な理論は良くわからないが、今回は線形合同法の比較としてメルセンヌツイスタを使った。

確率分布に従った乱数の生成

 理論で紹介したどの分布も0から1の連続一様乱数からの変換で生成できる。具体的に、一様分布・正規分布ポアソン分布は[1]のpdfを参考にした。 ベータ分布は[2]の基本アルゴリズムを用いた。

乱数の生成とpythonによる描画

 C/C++で以上のアルゴリズムを用いて10000個づつ乱数を作り、csvファイルとして保存し、それをpython確率密度関数と共に描画した。

結果

線形合同法を用いた場合

一様分布

f:id:linebrack:20201210025912p:plain
[0,10]の一様分布で生成した場合

正規分布

f:id:linebrack:20201210030104p:plain
μ=0,σ=5で生成した場合

ベータ分布

f:id:linebrack:20201210030224p:plain
a=2,b=4で生成した場合

ポアソン分布

f:id:linebrack:20201210030259p:plain
λ=5で生成した場合

メルセンヌツイスタを用いた場合

一様分布

f:id:linebrack:20201210031059p:plain
[0,10]の一様分布で生成した場合

正規分布

f:id:linebrack:20201210031124p:plain
μ=0,σ=5で生成した場合

ベータ分布

f:id:linebrack:20201210031140p:plain
a=2,b=4で生成した場合

ポアソン分布

f:id:linebrack:20201210031159p:plain
λ=5で生成した場合

考察

どちらの方法でも、大体うまく疑似乱数が生成できた。しかしながら線形合同法を用いたベータ分布のサンプリングでは乱数がある周期でループしてしまい、疑似乱数の生成に失敗した。このことから、周期の長いメルセンヌツイスタの使用を推奨する。

おわりに

今回使ったコードはgithubで共有します!(https://github.com/Line-brack/KogakuinAdvent2020_12_10)
本当はc++で確率分布の乱数生成をやりたかっただけなのに、細かいアルゴリズムから実装したくなり、内容が盛りだくさんになってしまった...。どうかこの記事を見た方には、様々な分布があることだけでも知ってもらえば幸いです。

参考

[1]http://sys.ci.ritsumei.ac.jp/probability/2011/10-6.pdf
[2] ベータ分布のサンプリングアルゴリズムを読みとく - Qiita
[3]C言語による乱数生成

今、通学途中にしていること<advent calender 17日目>

初めまして、linebrackと申します。初投稿です。

ひょんなことから記事を作ることになったのですが、お手柔らか(?)にお願いします!

はじめに

突然ですが、皆さんは電車に乗っているときに何をしていますか?

スマホや読書、睡眠、新聞などが王道でしょうか?

電車が混んでいればある程度制限されるものの、様々なことができそうです。

しかし、パソコンは電車がよっぽどガラガラでない限り使うことができません。

プログラミングをやっている人は特に、

電車内であろうと自作のプログラムを実行したいと思うはずです。(偏見)

そんな問題の解決に光明を投げかけてくれたのは、Solo Learnというサービスです。

SoloLearnとは

SoloLearnとは、13の言語に対応しているプログラミング学習サイトです。

www.sololearn.com

無料で利用できます。PC版、アプリ版の両方が存在しており、

「Code Playground」という、自由にコードを入力して実行結果を出力する機能があります。この機能のおかげで、スマホであろうと簡単にプログラミングができます。

SoloLearnは英語にのみ対応しており、日本語には対応していません。(日本語入力は可能)しかし、簡単な言い回しや表現が使われているので、日本人でも比較的学び易いです。もっと詳しく知りたい方は、下のサイトを参考にしてください。

SoloLearn 評判/評価は? 無料で学べるプログラミング ソロラーンの使い方から感想まで | プログラミング入門レシピ

通学でそれをする利点

たくさんありますが、とりあえず3つほど挙げます。

  • 英語、プログラミングの両方を同時に学べ一石二鳥。
  • 「Code Playground」があるので、試したいコードがあるときにスマホさえあればどこでも実行可能。
  • 自分の作成したコードを公開することができる。また、海外兄貴のコードも見ることができる。
 英語、プログラミングの両方を同時に学べ一石二鳥

電車内で英語を学習するには、単語帳や文法書を読む方が遥かに効率的だと思われる方もいるでしょう。まっことその通りだと私も思うのですが、それはあくまで「英語」のみを学ぶことに限ります。一方SoloLearnは、英語でプログラミング言語の仕様について説明しているので、プログラミングに関わる英語が頻出します。なので、プログラマの道を志す人にとっては、純粋な「英語」を学ぶよりも効率的だと言えます。(もちろん、単語帳などもおざなりにしてはいけないが)

しかし、肝心のプログラミングは深く学べるのか気になりますよね。大丈夫、しっかり学べる環境になってますよ。

「Code Playground」があるので、試したいコードがあるときにスマホさえあればどこでも実行可能

スマホでもC++,Python,htmlなどのコードを手軽に実行できます。そのため、

通学途中に試したいプログラムがあっても、家或いは学校に着くまで待つ必要がないのです。

f:id:linebrack:20181216165201j:plain

これは私が作った二乗根の値を出力するプログラムです。(math.cのsqrt()と比較している)
自分の作成したコードを公開することができる。また、海外兄貴のコードも見ることができる

SoloLearnでは、自作したコードを公開することができます。ユーザーの多くは外国人なのですが、プログラミング言語はもちろん共通なので、海外兄貴のコードであろうとなんの支障もなしに見ることができます。

f:id:linebrack:20181216170214j:plain

公開したくないコードはprivateにできます。さらに、グッドボタンも付いているので、時おり海外兄貴から評価されます。

また、コメント機能もあります。なので、コードの理解を助けたり、英語でのコミュニケーション力を身に着けることができます。

f:id:linebrack:20181216171025j:plain

コメントされたとき、正直緊張しました。(ガバガバ英語の使い手なので、多少はね?)

最後に

どうでしたか?少しは興味を持ってもらえたでしょうか。

場所が縛られていようとも、そこでできることを探求すればきっと、間隙をも最大限に活用する術があるはず。今回紹介したものはその一例にすぎませんが、皆さんも是非、合間を有効的に使えるサービスなどを探してみるのはどうでしょうか。