おみくじや福引きのようなもの、あるいは強化学習の実装などでタイトルのような「複数のものから確率で選ぶ」処理が必要になることがある。
これについては以前にもこのような記事を書いた。
【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のドキュメントを積極的に読もうと思わないので、こういうことに気づかないパターンが多い。
機会があったら使っていこう・・・。