random
前回、リスト内包表記で複数のリストを同時に作成する方法を紹介しました。
今回はrandomモジュールのrandom.choicesを使って、重みあり(偏りあり)でランダムに要素を取得する方法を紹介していきます。
ちなみにrandomモジュールの基本に関してはこちらで解説していますので、よかったらどうぞ。
まずはちょっとおさらいから。
あるリストからランダムに値を一つ取得する場合、random.choice(リスト)を使います。
import random
val_list = [1, 2, 3, 4, 5, 6]
val = random.choice(val_list)
print(val)
実行結果
6
偏りなく取得したい場合はこれでいいのですが、今回は偏りあり、つまりそれぞれの値に重みがある状態でランダムに取得するのが目標です。
この場合、random.choiceではできなくて、複数の値をランダムに取得する「random.choices」を使用します。
import random
val_list = [1, 2, 3, 4, 5, 6]
val = random.choices(val_list)[0]
print(val)
実行結果
2
random.choicesの場合、一つだけ要素を取得したとしてもリストで返ってくるので、「[0]」とインデックスを指定して値を取り出しています。
重みありでランダムに取得
それでは本題。
重み(偏り)ありでリストからランダムに要素を取得する方法です。
その場合、取得したい値を格納したリストの他に、そのリストに対応した重みのリストが必要になります。
今回の場合、取得する値のリストを「val_list」、重みのリストを「weight_list」としてリストを作成しました。
そしてrandom.choicesのオプションとしてweightsを追加します。
import random
val_list = [1, 2, 3, 4, 5, 6]
weight_list = [10, 1, 1, 1, 1, 1]
val = random.choices(val_list, weights=weight_list)[0]
print(val)
実行結果
1
今回の場合、「weight_list = [10, 1, 1, 1, 1, 1]」となっているので、val_listの「1」は他の値と比べて10倍出やすくなっているはずです。
とはいっても一回の試行では分からないので、プログラムを書いて検証してみました。
本当に重みにあっているのか検証
まずは重みなしの検証です。
先ほどのリストからランダムに10000回抽出し、リストに格納します。
そして「リスト名.count(要素)」でそれぞれの要素の数をカウントして、試行回数(10000)で割って出現確率を求めてみました。
ちなみに一番最後は単純に6分の1が幾つになるか計算しているだけです。
import random
cycle = 10000
val_list = [1, 2, 3, 4, 5, 6]
result_list = [random.choices(val_list)[0] for _ in range(cycle)]
print(result_list.count(1)/cycle)
print(result_list.count(2)/cycle)
print(result_list.count(3)/cycle)
print(result_list.count(4)/cycle)
print(result_list.count(5)/cycle)
print(result_list.count(6)/cycle)
print(1/6)
実行結果
0.1722
0.1656
0.1648
0.1655
0.1645
0.1674
0.16666666666666666
多少偏りはありますが、どの値も大体16.6%(0.166)に近い値となっています。
それでは重みありの検討です。
重みがあること以外は先ほどと同じです。
import random
cycle = 10000
val_list = [1, 2, 3, 4, 5, 6]
weight_list = [10, 1, 1, 1, 1, 1]
result_list = [random.choices(val_list, weights=weight_list)[0] for _ in range(cycle)]
print(result_list.count(1)/cycle)
print(result_list.count(2)/cycle)
print(result_list.count(3)/cycle)
print(result_list.count(4)/cycle)
print(result_list.count(5)/cycle)
print(result_list.count(6)/cycle)
print(1/6)
実行結果
0.6638
0.0646
0.0693
0.0704
0.0671
0.0648
0.16666666666666666
確かに「1」だけ他の値よりも10倍でやすくなっているのが分かります。
randomモジュールを使うとランダムに要素を取得するのも簡単ですし、さらに重みをつけてランダムに要素を取得するのも簡単なので、どんどん使っていきたいものです。
次回はPandasのデータフレームを辞書から作成する方法を紹介します。
ではでは今回はこんな感じで。
コメント