NumPy, randomで乱数生成(np.random.rand, normalなど)
NumPyでは、numpy.random
モジュールを利用して乱数を生成できる。
NumPy1.17
以降はGenerator
インスタンスを利用する方法が推奨されているが、従来のnp.random.rand()
やnp.random.normal()
などの関数も使用可能(1.26.1
時点)。
Python標準ライブラリのrandomモジュールについては以下の記事を参照。
本記事のサンプルコードのNumPyのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。
import numpy as np
print(np.__version__)
# 1.26.1
numpy.randomの使い方
Generatorインスタンスを利用(バージョン1.17以降)
まず、NumPy1.17
以降で推奨されているGenerator
インスタンスを利用する方法を説明する。
基本的な使い方
np.random.default_rng()
でGenerator
インスタンスを生成する。
rng = np.random.default_rng()
print(rng)
# Generator(PCG64)
Generator
インスタンスから各種メソッドを呼ぶことで、様々な種類の乱数を生成できる。
例えば、random()
メソッドは0.0以上・1.0未満の浮動小数点数float
の一様分布の乱数を生成する。
引数size
で形状を指定する。デフォルト(size=None
)ではスカラー値、整数int
を指定すると一次元の配列ndarray
、タプルを指定するとその形状shape
の配列ndarray
が生成される。
random()
メソッドでは第一引数がsize
。
print(rng.random())
# 0.2281556131299135
print(type(rng.random()))
# <class 'float'>
print(rng.random(3))
# [0.3888496 0.9058742 0.74585675]
print(type(rng.random(3)))
# <class 'numpy.ndarray'>
print(rng.random((2, 3)))
# [[0.42818743 0.22573104 0.33022384]
# [0.64782123 0.82035051 0.31118108]]
print(type(rng.random((2, 3))))
# <class 'numpy.ndarray'>
例では省略しているが、タプルの要素を増やせば三次元以上の配列ndarray
も生成可能。
その他のメソッドについては後述。
シードの固定
np.random.default_rng()
の引数に任意の非負整数値をシードとして指定できる。省略した場合は毎回異なるシードで初期化される。
rng_1 = np.random.default_rng(1234)
print(rng_1.random())
# 0.9766997666981422
rng_2 = np.random.default_rng(1234)
print(rng_2.random())
# 0.9766997666981422
乱数シードについての詳細は公式ドキュメントを参照。
乱数生成器の変更
np.random.default_rng()
では、乱数生成器としてPCG64が使われる。
乱数生成器を選択したい場合はコンストラクタnp.random.Generator()
を使う。引数としてBitGenerator
を指定する。PCG64のほか、MT19937やSFC64などが提供されている。
- Random Generator - numpy.random.Generator — NumPy v1.26 Manual
- Bit Generators - Supported BitGenerators — NumPy v1.26 Manual
BitGenerator
の生成時にシードの指定が可能(もちろん省略してもよい)。乱数生成器が何であっても利用できるメソッドは同じ。
rng_mt = np.random.Generator(np.random.MT19937(1234))
print(rng_mt)
# Generator(MT19937)
print(rng_mt.random())
# 0.12038356302504949
レガシーな方法(RandomStateインスタンス、関数)
NumPy1.17
以降はGenerator
インスタンスの利用が推奨されているが、従来の方法も利用可能。
あくまでも後方互換性のために残されているものなので、これから新しいコードを書くのであれば、より高速で今後も改良されていくGenerator
を利用するほうがよい。
Generator
and its associated infrastructure was introduced in NumPy version 1.17.0. There is still a lot of code that uses the olderRandomState
and the functions innumpy.random
. While there are no plans to remove them at this time, we do recommend transitioning toGenerator
as you can. The algorithms are faster, more flexible, and will receive more improvements in the future. Random sampling (numpy.random) — NumPy v1.26 Manual
RandomStateインスタンスを利用
Generator
が導入される前はRandomState
が利用されていた。
np.random.RandomState()
でインスタンスを生成し、各種メソッドを呼ぶ。
rs = np.random.RandomState()
print(rs)
# RandomState(MT19937)
print(rs.rand())
# 0.07714411293114853
print(rs.rand(3))
# [0.41864167 0.24060533 0.33237037]
print(rs.rand(2, 3))
# [[0.44510064 0.81320106 0.79076827]
# [0.84813432 0.83270079 0.10677157]]
シードの指定も可能。
rs_1 = np.random.RandomState(1234)
print(rs_1.rand())
# 0.1915194503788923
rs_2 = np.random.RandomState(1234)
print(rs_2.rand())
# 0.1915194503788923
関数を利用
RandomState
のメソッドは関数として利用できるようになっている。
print(np.random.rand(2, 3))
# [[0.22135358 0.56604746 0.03200072]
# [0.04187504 0.32511305 0.0366836 ]]
シードの指定にはnp.random.seed()
を使う。
np.random.seed(1234)
print(np.random.rand())
# 0.1915194503788923
np.random.seed(1234)
print(np.random.rand())
# 0.1915194503788923
一様分布の乱数生成: np.random.rand, randintなど
0.0以上・1.0未満の浮動小数点数
0.0以上・1.0未満([0.0, 1.0)
)の浮動小数点数の一様分布の乱数はGenerator
のrandom()
メソッドで生成できる。
第一引数がsize
。
rng = np.random.default_rng()
print(rng.random())
# 0.11769302730981768
print(rng.random(3))
# [0.58905312 0.90484592 0.90395364]
print(rng.random((2, 3)))
# [[0.59463288 0.19670697 0.95594319]
# [0.94165422 0.18974122 0.33570092]]
従来のnp.random.random_sample()
やnp.random.rand()
に相当。np.random.rand()
では形状shape
をタプルではなく位置引数d0, d1, ..., dn
として順に指定する。
print(np.random.random_sample((2, 3)))
# [[0.34446051 0.76218429 0.37339732]
# [0.22533506 0.00148215 0.70198151]]
print(np.random.rand(2, 3))
# [[0.78823483 0.00620854 0.96619249]
# [0.32573769 0.36434893 0.04472163]]
任意の範囲の浮動小数点数
任意の範囲の浮動小数点数の一様分布の乱数はGenerator
のuniform()
メソッドで生成できる。
第一引数low
、第二引数high
、第三引数size
を指定する。low
は範囲に含まれるがhigh
は含まれない([low, high)
)。
rng = np.random.default_rng()
print(rng.uniform(-50.0, 50.0))
# 17.611381123655846
print(rng.uniform(-50.0, 50.0, 3))
# [ 5.80448109 6.64291183 22.27752257]
print(rng.uniform(-50.0, 50.0, (2, 3)))
# [[ 12.23855165 -9.97903127 -38.40667299]
# [-14.42414448 -45.04563195 14.37486871]]
従来のnp.random.uniform()
に相当する。
print(np.random.uniform(-50.0, 50.0, (2, 3)))
# [[-25.63149057 16.80691914 20.69418218]
# [ 32.53480087 -10.83462837 15.18192629]]
任意の範囲の整数
任意の範囲の整数の一様分布の乱数はGenerator
のintegers()
メソッドで生成できる。
第一引数low
、第二引数high
、第三引数size
を指定する。
第二引数high
を省略すると、0以上・low
未満([0, low)
)の範囲となる。
rng = np.random.default_rng()
print(rng.integers(100))
# 24
print(rng.integers(100, size=3))
# [ 9 25 27]
print(rng.integers(100, size=(2, 3)))
# [[78 2 42]
# [25 6 16]]
第二引数high
を指定すると、low
以上・high
未満([low, high)
)の範囲となる。
print(rng.integers(100, 200, (2, 3)))
# [[134 142 129]
# [154 180 103]]
引数endpoint
をTrue
にすると、上限値も範囲に含まれる([0, low]
または[low, high]
)。
print(rng.integers(100, 200, (2, 3), endpoint=True))
# [[170 157 172]
# [121 200 191]]
従来のnp.random.randint()
に相当する。ただし、randint()
には引数endpoint
は無く、常に上限値は範囲に含まれない。
print(np.random.randint(100, 200, (2, 3)))
# [[120 121 138]
# [159 140 197]]
正規分布の乱数生成: np.random.randn, normalなど
標準正規分布(平均0・標準偏差1)
平均0、標準偏差1(分散1)の正規分布(標準正規分布)に従う乱数はGenerator
のstandard_normal()
メソッドで生成できる。
第一引数がsize
。
rng = np.random.default_rng()
print(rng.standard_normal())
# 0.08496250507973527
print(rng.standard_normal(3))
# [ 1.21769711 1.81125807 -0.87641522]
print(rng.standard_normal((2, 3)))
# [[-1.79057437 0.30921794 0.78466028]
# [ 0.9669326 -0.23709503 0.17453728]]
従来のnp.random.standard_normal()
やnp.random.randn()
に相当。np.random.randn()
では形状shape
をタプルではなく位置引数d0, d1, ..., dn
として順に指定する。
print(np.random.standard_normal((2, 3)))
# [[ 1.59966341 -2.3255136 -0.90314338]
# [-0.90576614 0.45550908 -0.88593054]]
print(np.random.randn(2, 3))
# [[ 0.13158995 -0.34018141 0.26866075]
# [-0.35383739 -1.85442183 -0.1316313 ]]
任意の平均・標準偏差
任意の平均・標準偏差の正規分布(ガウス分布)に従う乱数はGenerator
のnormal()
メソッドで生成できる。
第一引数loc
(平均)、第二引数scale
(標準偏差)、第三引数size
を指定する。
rng = np.random.default_rng()
print(rng.normal(2, 2.5))
# 1.4099095964428612
print(rng.normal(2, 2.5, 3))
# [-1.02713245 2.80603029 6.84660003]
print(rng.normal(2, 2.5, (2, 3)))
# [[ 4.23662681 2.36596096 -0.08259898]
# [ 2.27105608 1.58751381 -2.42582859]]
従来のnp.random.normal()
に相当する。
print(np.random.normal(2, 2.5, (2, 3)))
# [[ 4.43180284 3.74464437 0.79083482]
# [-0.3631814 0.39375677 7.8085918 ]]
その他の分布
一様分布や正規分布の他にも、様々な分布に従う乱数を生成できる。一覧は公式ドキュメントを参照。
二項分布やベータ分布、ガンマ分布、ポアソン分布などがある。指定できるパラメータなどは公式ドキュメントを参照。
- numpy.random.Generator.binomial — NumPy v1.26 Manual
- numpy.random.Generator.beta — NumPy v1.26 Manual
- numpy.random.Generator.gamma — NumPy v1.26 Manual
- numpy.random.Generator.poisson — NumPy v1.26 Manual
rng = np.random.default_rng()
print(rng.binomial(10, 0.5, (2, 3)))
# [[3 7 5]
# [4 3 5]]
print(rng.beta(2, 2, (2, 3)))
# [[0.84643935 0.50674151 0.30812967]
# [0.52728096 0.76007311 0.26255972]]
print(rng.gamma(5, 1, (2, 3)))
# [[5.6484851 8.28210475 2.65957385]
# [2.00776839 6.65851101 7.77808412]]
print(rng.poisson(4, (2, 3)))
# [[1 6 3]
# [5 2 1]]