静かなる名辞

pythonとプログラミングのこと


【python】複数の選択肢から確率で選ぶ


 おみくじや福引きのようなもの、あるいは強化学習の実装などでタイトルのような「複数のものから確率で選ぶ」処理が必要になることがある。

 これについては以前にもこのような記事を書いた。

【python】一定の確率で違う選択をする - 静かなる名辞

 この方法でも上手くいくのだが、選択肢が複数になった場合が面倒くさかったり、確率を後から変えるのが大変だったりと、それなりにデメリットがあった。

 理想的には、確率のリストなどを渡せばよしなに処理してくれるものがほしい。こんな風に。

何か凄いもの(確率のリスト)
# -> リストのindexを0:15%, 1:35%, 2:20%, 3, 30%の確率で返す

 できないと思っていたが、numpyでできることが判明した。ただしversion 1.7.0以上が必要。

numpy.random.choice — NumPy v1.15 Manual

 たとえば、a,b,c,dを[0.15, 0.35, 0.2, 0.3]の確率で選びたい場合、単にこうすれば良い。

np.random.choice(["a", "b", "c", "d"], p=[0.15, 0.35, 0.2, 0.3])
# -> "a", "b", "c", "d"のいずれかが確率で返る

 想像以上に簡単だ・・・。

 インデックスを返させることもできる。

np.random.choice(4, p=[0.15, 0.35, 0.2, 0.3])
# -> 0, 1, 2, 3のいずれかが確率で返る

 0,1,2,3を選んでくれる。素晴らしい。

 更に、複数の結果を吐かせることもできる。

np.random.choice(4, size=10, p=[0.15, 0.35, 0.2, 0.3])
# -> 一例:array([3, 2, 3, 3, 1, 3, 2, 1, 1, 0])

 更に更に、replaceというオプションがある。これは重複するかどうかを指定する(ふくびきで出た玉を一々中に戻すかどうかに相当)。defaultはTrueで、玉を中に戻すことに相当する。Falseにすると次のようなことができる。

np.random.choice(5, 5, replace=False)
# -> array([3, 0, 4, 1, 2])

 これはランダムサンプリングするときに使えるだろう。ただし、同時にpオプションを指定すると上手く動かない。次のエラーが出る。

ValueError: Cannot take a larger sample than population when 'replace=False'

 何はともあれ、こんな便利なものがあることは知らなかった。普段numpyのドキュメントを積極的に読もうと思わないので、こういうことに気づかないパターンが多い。

 機会があったら使っていこう・・・。