Python

【Python】randomモジュールを使った乱数の使い方を解説

この記事では、Pythonで擬似乱数を生成する方法を解説します。Pythonで乱数を扱うには、標準ライブラリのrandomモジュールを使います。乱数を使うことでジャンケンなどのちょっとした遊びも実装できます。それでは、乱数の使い方を見ていきましょう❗️

randomモジュール

Pythonで乱数を扱うにはrandomモジュールを使います。標準ライブラリなのでインポートするだけで使用可能です。

import random

randomモジュールには乱数を生成するための様々な関数が定義されています。

Linkrandom — 擬似乱数を生成する — Python ドキュメント

ランダムな整数を生成する

ランダムな整数を生成するには、以下の関数を使います。

randrange range(start, stop, step)の要素から、1つランダムに選んで返します。
randint randrange(a, b+1) のエイリアス
getrandbits k個のビット数の範囲から、1つランダムに選んで返します。

任意の範囲の整数からランダムに1つ取得

randrange()関数はrange()関数と同じ引数を取り、同様な範囲を生成します。そして、生成した範囲の中からランダムに要素を1つ取得します。

randrange(start,stop,step)

以下のコードでは、range()関数で生成した範囲とrandrange()関数で取得した値を見比べています。

import random

print(f'range: {list(range(5))}, value: {random.randrange(5)}')
print(f'range: {list(range(3, 8))}, value: {random.randrange(3, 8)}')
print(f'range: {list(range(1, 10, 2))}, value: {random.randrange(1, 10, 2)}')

実行結果

range: [0, 1, 2, 3, 4], value: 1
range: [3, 4, 5, 6, 7], value: 7
range: [1, 3, 5, 7, 9], value: 5

step引数を指定しない場合はrandint()関数を使う方が簡単。randint()関数はrandrange(a, b+1)のエイリアスです。

randint(a, b)

randrange()関数とは異なり、a < N <= bなことに注意しましょう。

import random

print(f'range: {list(range(1, 5+1))}, value: {random.randint(1, 5)}')

実行結果

range: [1, 2, 3, 4, 5], value: 5​

任意のビット数からランダムに整数を1つ取得

指定したビット数で生成される整数の中から1つ取得するにはgetrandbits()関数を使います。

getrandbits(k)

k個のビット数の範囲から生成される整数からランダムに1つ返します。

import random

# 0000 ~ 0011
print(random.getrandbits(2))

# 0000 ~ 1111
print(random.getrandbits(4))

実行結果

3
14

ランダムな実数を生成する

ランダムな実数を生成するには、以下の関数を使います。

random 0.0 ~ 1.0の範囲からランダムに実数を返します
uniform a ~ bの範囲内の実数をランダムに返します

0.0~1.0の範囲の実数をランダムに取得

0.0 ~ 1.0の範囲からランダムに実数を返します。

import random

print(random.random())

実行結果

0.8743999006747728

桁数が大きすぎる場合はround()関数を使って小数を丸める。

import random

print(round(random.random(), 2))

実行結果

0.27
【Python】小数点の切り上げ・切り捨て・四捨五入 この記事では、Pythonで小数点を切り上げ、切り捨て、四捨五入する方法を解説します。 切り上げ 小数点を切り上げる...

任意の範囲の実数をランダムに取得

任意の範囲の実数を1つランダムに取得するにはuniform()関数を使います。

uniform(a, b)

a ~ bの範囲内の実数をランダムに返します。a,bどちらが大きくても問題ありません。

import random

# uniform(2, 1)でも同じ
print(random.uniform(1, 2))

# 桁数が大きい場合はround関数を使う
print(round(random.uniform(1, 2), 2))

実行結果

1.3158320605493328
1.85

ランダムなバイト列を生成する

ランダムなバイト列を生成するには、randbytes()関数を使います。この関数はバージョン3.9で追加されました。

randbytes(n)

nバイトのバイト列がランダムに生成されます。

import random

for i in range(1, 6):
    print(f'{i}: {random.randbytes(i)}')

実行結果

1: b'\xf5'
2: b'\x04\xec'
3: b'\x1b\x04Z'
4: b'\xe0\xff\x9b\x9a'
5: b'He\x93\x10\x7f'

シーケンスの要素をランダムに取得する

整数や実数以外のオブジェクトをランダムに取得するには、シーケンスに格納された要素をランダムに取得することで実現できます。

要素をランダムに取得する

シーケンスの要素をランダムに取得するには、random.choise()関数を使います。

random.choice(seq)

choice()関数は引数に指定されたシーケンスの要素をランダムに返します。引数に指定したシーケンスが空の場合はIndexErrorが発生します。

import random

l = [1, 2, 3, 4, 5]

for i in range(3):
    print(random.choice(l))

# 要素を抜き取っているわけではないので重複もあり得る
print(l)

実行結果

3
1
4
[1, 2, 3, 4, 5]

重複させたくない場合は、取得した要素を削除する。

import random

l = [1, 2, 3, 4, 5]

for i in range(3):
    choice_elem = random.choice(l)
    # 取得した要素を削除
    l.remove(choice_elem)
    print(choice_elem)

print(l)

実行結果

3
5
1
[2, 4]

確率を変更して要素を取得する

確率を変更してシーケンスの要素をランダムに取得したい場合は、random.choises()関数を使います。

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

population引数に指定したシーケンスからk個の要素をランダムに取得します。

また、重みを渡すことで要素が選ばれる確率を変更することができます。重みはweights引数、またはcum_weights引数にシーケンスを渡すことで指定できます。重みが渡されなかった場合は同じ確率で選択されます。

import random

# ガチャの中身
contents = ('超激レア', '激レア', 'レア')

# 累積的な重み(超激レア=10%, 激レア=20%, レア=70%)
cum_weights = (1, 3, 10)

# 10連ガチャ(k引数で回数を指定しています)
gacha10 = random.choices(contents, cum_weights=cum_weights, k=10)
print(gacha10)

実行結果

['レア', 'レア', '激レア', 'レア', '超激レア', '激レア', '激レア', 'レア', 'レア', 'レア']
  • 重みの長さは、populationに指定したシーケンスと同じにする
  • 相対的な重みは関数内で累積的な重みに変換されるので、最初から累積的な重みを渡すほうが効率が良い

重みの補足

重みには、「相対的な重み」と「累積的な重み」があります。どのように指定すればいいのか、もう少しだけ詳しく見ていきましょう!

相対的な重み

相対的な重みで「10%」「30%」「60%」の確率で要素を取得するには、以下のように指定します。

weights = (10, 30, 60)

確率は「要素の値 / 合計値」で計算されます。上記シーケンスの合計は100なので、10 / 100 = 0.130 / 100 = 0.360 / 100 = 0.6となっています。

なので、以下のような重みは先ほどの重みと同等です。

# 合計 50
weights = (5, 15, 30)
# 合計 10
weights = (1, 3, 6)
累積的な重み

累積的な重みで「10%」「30%」「60%」の確率で要素を取得するには、以下のように指定します。

cum_weights = (1, 4, 10)

確率は「左の要素から増えた値 / 末尾の要素の値」で計算されます。上記シーケンスの末尾の値は10なので、(1 - 0) / 10 = 0.1(4 - 1) / 10 = 0.3(10 - 4) / 10 = 0.6となっている。

なので、以下のような重みは先ほどの重みと同等である。

cum_weights = (5, 20, 50)
cum_weights = (10, 40, 100)

シーケンスの要素をランダムに並び替える

シーケンスの要素をランダムに並び替えるには、shuffle()関数を使います。並び替えたシーケンスを返すのではなく、引数に指定されたシーケンスを並び変えます。

import random

# 連番のリスト生成
nums = list(range(1, 6))
print(nums)

# シャッフル
random.shuffle(nums)
print(nums)

実行結果

[1, 2, 3, 4, 5]
[1, 4, 2, 5, 3]

まとめ

この記事では、Pythonの乱数の使い方を簡単に解説しました。

乱数を使うことで何かしら値が必要な時にランダムに値を生成することができます。

randomモジュールには、今回紹介したもの以外にたくさんの関数が定義されています。気になる方は、公式ドキュメントを参照してください。

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ

【Python】ジャンケンを実装してみよう!この記事では、Pythonでジャンケンを実装してみます。 ジャンケンについて考える まずは、ジャンケンについて少し整理しておきま...
最短3か月でエンジニア転職『DMM WEBCAMP COMMIT』