python

Pythonでランダムな変数を作成する方法

Pythonでランダムな変数を作成する方法について紹介します。

標準で使えるrandomモジュールと、Numpyrandomパッケージの2つの方法について紹介します。

標準randomモジュールを使う方法

Pythonにデフォルトでインストールされる標準モジュールrandomを使った方法です。

まずは事前にインポートしておきます。

import random

ランダムな整数を1つ作成する

ランダムな値を作成する場合、randint()関数を使います。

50〜100までのランダムな数値を作成したい場合は、こんな感じで第1引数に最低値を、第2引数に最大値を指定します。

>>> random.randint(50, 100)
94

ランダムな少数を1つ作成する

ランダムな少数を1つ作成する場合、random()関数を使います。

random()関数に引数は指定できず、0以上1未満のランダムな少数値を作成します。

>>> random.random()
0.18448240416445205

0以上1未満ではなくて、たとえば1以上2以下のランダムな少数を作成したい場合は、uniform()関数を使います。

>>> random.uniform(1, 2)
1.6074269877987506

ランダムなアルファベットを作成する

これは少し応用で、a〜zまでのアルファベットをランダムに作成したいような場合は、文字コードをランダムに生成してから文字に変換することで実現できます。

文字コードの取得はord()関数で、数値から文字コードへはchr()関数です。

>>> a = ord('a')
>>> a
97
>>> z = ord('z')
>>> z
122
>>> some_char = random.randint(a, z)
>>> some_char
107
>>> chr(some_char)
'k'

numpyを使う方法

Python標準ライブラリでは変数を1つずつ作成することはできましたが、ランダムな値の配列を作成したい場合はNumpyを使うと便利です。

前準備

Numpyのライブラリをインストールしておきます。

pip install numpy

そしてプログラムでは、numpy.default_rngをインポートして、ランダムジェネレータであるnumpy.random.Generatorのインスタンスを作成しておきます。

# Numpyのインポート
import numpy as np
# ランダムジェネレータのインポート
from numpy.random import default_rng

# ランダムジェネレータのインスタンス化
rng = default_rng()

これで、以下で紹介する方法を利用できるようになります。

ランダムな整数の配列を作成する

Numpyでランダムな整数を作成するには、numpy.random.Generator.integers()メソッドを使います。

Numpyは配列を効率よく扱うことを目的としたライブラリのため、ランダムな値もNumpy配列(numpy.ndarray)で生成されます。

次の例では、1〜9までの数値を含んだ長さ10のndarrayを生成しています。

>>> values = rng.integers(low=1, high=10, size=10)
>>> values
array([3, 9, 3, 3, 6, 6, 9, 1, 8, 4])

ランダムな整数を1つ作成する

配列ではなく整数で作成したい場合も、同様にnumpy.random.Generator.integers()メソッドを使いますが、左辺代入で配列を展開するように工夫した記述が必要です。

>>> a, = rng.integers(low=1, high=10, size=1)
>>> a
3

同様に、変数2つに割り当てたい場合はこんな感じで。

>>> a, b = rng.integers(low=1, high=10, size=2)
>>> a
6
>>> b
3

ランダムな少数の配列を作成する

整数ではなく少数を作成したい場合は、numpy.random.Generator.random()メソッドを使います。

このメソッドは、0〜1までの間(1は含まない)の値の配列を作成します。

>>> rng.random(10)
array([0.4067598 , 0.21243005, 0.38749953, 0.30738665, 0.24476233,
       0.53791747, 0.47890178, 0.31185431, 0.71643237, 0.56840805])

小数点以下1桁にしたい場合は、floor関数を使いつつ、面倒だけど10で掛けたり割ったりが必要みたいです。

>>> a = rng.random(10)
>>> np.floor(a * 10) / 10
array([0.7, 0.6, 0.8, 0.7, 0. , 0.2, 0.4, 0.8, 0.5, 0.9])

ランダムな少数を1つ作成する

ランダムな整数の時と同様に、左辺代入で配列を展開すれば、配列ではなく直接変数に代入できます。

>>> a, = rng.random(1)
>>> a
0.8942128137437866

ランダムな文字の配列を作成する

標準モジュールで'a'〜'z'までのランダムなアルファベットを作成したように、Numpyではランダムな文字の配列を作成してみましょう。

これも応用が必要で、プログラムもちょっと長くなっちゃいます。

numpy.random.Generator.integers()メソッドを使って、'a'(intで97)〜'z'(intで122)の間のint配列を作成して、それをnumpy.vectorize()関数を使いそれぞれの値にchr()関数を適用して文字に変更することで、ようやくお目当てである文字の配列が出来上がります。

>>> b = rng.integers(low=ord('a'), high=ord('z')+1, size=10)
>>> b
array([113, 118, 117, 109, 102, 112, 103, 102, 109, 104])
>>> myfunc = lambda x: chr(x)
>>> vec = np.vectorize(myfunc)
>>> c = vec(b)
>>> c
array(['q', 'v', 'u', 'm', 'f', 'p', 'g', 'f', 'm', 'h'], dtype='<U1')

標準モジュールとNumpyの使い分け

標準モジュールでもNumpyでもランダムな変数を作ることができるわけですが、じゃあどっちを使えばいいのかというところを考えてみます。

Mersenne TwisterとPCG64

ランダムな値の生成というのは、乱数生成アルゴリズムを使って生成されています。そして使用するアルゴリズムによって、生成速度や偏りに影響が出ます。

標準ライブラリはMersenne Twister(マーセンヌ ツイスター)というアルゴリズムを使っています。

Numpyも2019年までは同様にMersenne Twisterを使っていましたが、バージョン1.17.0でより速度・バラつきの面で優秀なPCG64を標準アルゴリズムが採用されました。

0〜9の整数を100万回ランダムに生成したときの偏りをプロットしてみました。PCG64のほうが偏りなく、よりランダムに生成されていることがわかります。

ネットでNumpyのランダム変数生成方法を調べて見つかるブログ記事などでは、いまだに古いアルゴリズムが適用されてしまうプログラムが散見されるのでご注意を。

標準のrandomモジュールが適しているシチュエーション

  • ランダムな値を変数1つずつに生成したい
  • Numpyをインストールしたくない
  • 速度や値の偏りなどを気にしない

Numpyが適しているシチュエーション

  • ランダムな値を配列で生成したい(長さ1の配列で生成することもできる)
  • ランダムな値を多数作成したい(処理速度やアルゴリズムの面で有利)
  • 作成した配列をNumpy・pandas・scikit-learnなどで利用したい(互換性の面で有利)

ランダムというのは実はランダムじゃない

ランダムな変数というのは実は擬似的なランダムなのであって完全なランダムではない、つまり予測される可能性があるということで、セキュリティに影響する部分に利用するのは良くないとされています。

セキュリティに影響するような部分は暗号化の技術を使う必要があるので、secretモジュールを活用です。

-python

© 2022 ヂまるBlog