『Python数値計算ノート』ではアフィリエイトプログラムを利用して商品を紹介しています。

要素をランダムに抽出する関数

シーケンスの要素を無作為に抽出する関数

標準ライブラリの randomモジュール には、シーケンスからランダム(無作為)に要素を抽出する random.choice(), random.sample() があります。NumPyパッケージには配列から複数個の要素をランダムに取り出す numpy.choice() が用意されています。

random.choice()

random.choice(seq) は引数 seq に渡したシーケンス(文字列、リスト、タプルなど)から要素をランダムに一つ選んで返します(どの要素も等しい確率で選ばれます)。

random.choice(seq)

以下のコードは、リストから重複を許して 3 回連続で無作為抽出してます。

# PYTHON_RANDOM_CHOICE

# In[1]

# randomモジュールをインポート
import random

# 乱数を初期化
random.seed(0)

# 恒星リスト
stars = ["太陽", "シリウス", "アケルナル", "ベガ", "プロキオン"]

# 恒星リストから3回ランダムに要素を抽出(重複あり)
for k in range(3):
    x = random.choice(stars)
    print(x)

# ベガ
# ベガ
# 太陽

random.sample()

random.sample() は population に指定したシーケンスまたは集合から k 個の要素を重複なしで抽出して、それらを要素に持つ新しいリストを作成します。

random.sample(population, k)

以下のコードは set からランダムに要素を抽出してリストを生成します。

# PYTHON_RANDOM_SAMPLE

# In[1]

import random

# 乱数を初期化
random.seed(0)

# 恒星の集合(set)
stars = {"カノープス", "アルタイル", "カペラ", "デネブ", "カストル"}

# 3個の要素をランダムに抽出して新しいリストを作成(重複なし)
y = random.sample(stars, 3)

print(y)
# ['カノープス', 'デネブ', 'カペラ']

random.choices()

random.choices() は population に指定したシーケンスまたは集合から引数 k に指定した個数の要素を重複ありで無作為抽出し、それらを要素に持つ新しいリストを作成します。

random.choices(population, weights=None, cum_weights=None, k=1)

引数 weights に相対的な重みのシーケンスを渡すと、各要素が選ばれる確率を調整することができます。

# PYTHON_RANDOM_CHOICES

# In[1]

import random

# 乱数を初期化
random.seed(0)

# 恒星リスト
stars = ["アルデバラン", "スピカ", "リゲル", "ベテルギウス", "エルナト"]

# 相対的な重みのリスト
w = [1, 1, 2, 2, 4]

# 各要素に重みwをつけて、5個の要素をランダムに抽出してリストを作成
x = random.choices(stars, k = 5, weights = w)

print(x)
# ['エルナト', 'エルナト', 'ベテルギウス', 'リゲル', 'ベテルギウス']

上のサンプルコードでは相対的な重みのリストを [1, 1, 2, 2, 4] で指定しています。これによって、たとえばリストの 3 つめの要素(インデックス 2 の要素)”リゲル” は
 
 2/(1+1+2+2+4) = 2/10 = 1/5
 
の確率で選び出されることになります。random.choices() は引数 cum_weights で累積的な重みを指定することもできます (weights と同時に指定することはできません)。サンプルコードは割愛しますが、相対的な重み [1, 1, 2, 2, 4] は、累積的な重み [1, 2, 4, 6, 10] と等価です。

numpy.random.choice()

numpy.random.choice() は第 1 引数に渡した配列 a から要素を無作為に抽出します。

numpy.random.choice(a, size=None, replace=True, p=None)

デフォルト設定 (replace=True) では重複を許して取り出します。
replace は「引いたクジを元に戻す」という意味のキーワードです。

# NUMPY_RANDOM_CHOICE

# In[1]

# NumPyをインポート
import numpy as np

# 乱数シードを設定
np.random.seed(9)

# 恒星のリスト
stars = np.array(["カノープス",
                  "アルタイル",
                  "カペラ",
                  "デネブ",
                  "カストル"])

# リストから6個の要素をランダム抽出(重複あり)
# 戻り値は3行2列の配列
x = np.random.choice(stars, size=(3, 2))

print(x)
# [['カストル' 'カノープス']
#  ['デネブ' 'アルタイル']
#  ['カストル' 'デネブ']]

replace に Falsee を渡すと、重複なしで抽出します。

# In[2]

np.random.seed(9)

# リストから3個の要素をランダム抽出(重複なし)
# 戻り値は1次元配列
y = np.random.choice(stars, size=3, replace=False)

print(y)
# ['デネブ' 'カノープス' 'アルタイル']

各要素が抽出される確率を引数 p で指定できます。

# In[3]

np.random.seed(13)

# 各要素の抽出確率を設定
prob = np.array([0.5, 0.2, 0.1, 0.1, 0.1])

# 等確率で8要素を取り出して4行2列で返す
x = np.random.choice(stars, size=(4,2), p=prob)

print(x)
# [['カペラ' 'カノープス']
#  ['デネブ' 'カストル']
#  ['カストル' 'カノープス']
#  ['アルタイル' 'カペラ']]

a に整数を渡すと、a 未満の正整数のをランダム抽出します。

# In[4]

np.random.seed(15)

# 9以下の整数から無作為に5個の数字を抽出(重複あり)
x = np.random.choice(10, 5)

print(x)
# [8 5 5 7 0]

コメント

  1. HNaito より:

    下記は誤植と思われますので、ご確認ください。
    「random.choice( )」の説明文で、
    ランダムに選んで → ランダムに一つ選んで
    無作為抽出して新しいリストをつくります → 無作為抽出しています。
    「random.choices( )」の引数に「*,」 が入っていますが、なくてもよいのでは?
    残すのであれば説明は必要になりますが、細かすぎるような気がします。

    • あとりえこばと より:

      確かに「*,」はいらないですね。
      省いておきました。ありがとうございます。

  2. あとりえこばと より:

    【AIの独り言】「ランダムな選択」というのは、私たちの日常でもよくあることですよね。スーパーマーケットで商品を選ぶとき、何を食べるかを決めるとき、友達との活動を計画するとき、私たちは常に選択を迫られています。その中には、選ぶこと自体が楽しい瞬間もあるでしょう。Pythonのプログラミングにおいても、このランダムな選択は非常に役立ちます。例えば、シミュレーションやゲーム開発では、現実世界の偶発性を模倣するためにランダムな要素が利用されます。

    データのシャッフルやランダムなテストケースの生成などでも活用されることがあります。コード上でランダムな要素を選ぶことは、シンプルな方法で複雑な問題にアプローチする手段の一つでもあります。例えば、異なるアルゴリズムやアイデアをランダムに試すことで、最適な解に近づくかもしれません。このように、Pythonのrandom.choiceを使ってランダムな要素を選ぶことは、日常的な選択の一端をコード内に取り入れるような感覚でしょう。そして、その選ばれる瞬間には、時には予期せぬ発見やアプローチが待っていることもあるかもしれません。