Remrinのpython攻略日記

python3に入門しました。python3についてあれこれとサンプルコードとか。

NumPyの使い方(12) 乱数、random

乱数を発生させるライブラリは主に2つ。

randomライブラリとNumPyのrandom
2つのライブラリの一番の違いは乱数の発生個数。

乱数の発生個数

randomモジュール :乱数1個
numpyは配列の形をsize=~の形のキーワード引数で乱数の個数を指定できる。
size 省略  →1個の乱数
size = 数値 →1次元配列
size = タプル→多次元配列

乱数の初期化

random.seed(数値)
np.random.seed(数値)
 
同じ初期値にすると、再現性のある乱数列になる。
 

小数(一様uniform)

0~1の乱数

random.random() 0~1の乱数乱数を1個生成。
np.random.rand(size) 0~1の乱数列。配列生成後に再計算すると範囲を変えられる

 
範囲を指定した乱数

random.uniform(low, high) low以上high未満の一様乱数を1個生成
np.random.uniform(low, high, size) low以上high未満の一様乱数

 

import numpy as np
import random

print(random.random())
# 0.9733563537374995

print(np.random.rand(3))
# [ 0.69962497  0.61950126  0.7944733 ]

print(np.random.rand(2, 3))
# [[ 0.29315148  0.06560949  0.56110618]
#  [ 0.62784039  0.19218867  0.07087768]]

np.random.uniform(1, 10, 3) 1以上10未満の一様乱数3個の配列。
# [ 8.77776521  4.21775806  9.269332  ]

 
・乱数で円周率を求める:
f:id:rare_Remrin:20170509174416p:plain
サンプルコードはこちら 
 
ランダムウォーク
 0~1の乱数を生成し、0.5以上なら+1、0.5未満なら-1を加えていく。

# coding: utf-8

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(1)            # 乱数の初期化。
w = np.random.rand(1000)     # 1000個の乱数生成
w = np.where(w > 0.5, 1, -1) # 0.5以上は1に、0.5未満は-1に変更
w = w.cumsum()               # 累積和を取る

print(w.min())    # -11
print(w.max())    # 35

print(w.argmin()) # 64   最初に-11になったインデックス
print(w.argmax()) # 368  最初に35になったインデックス

plt.plot(np.arange(1000), w) # 折れ線グラフとして表示
plt.scatter(w.argmin(), w.min(), marker="D", c="r")
plt.scatter(w.argmax(), w.max(), marker="D", c="r")
plt.text(w.argmin(), w.min(), "min", fontsize=16)
plt.text(w.argmax(), w.max(), "max", fontsize=16)
plt.show()

 
株価の変動のようなグラフになりますね。
seed()の値をいろいろ変えてみると面白そう。
 
f:id:rare_Remrin:20170516223745p:plain
 

小数(分布が一様ではない)

正規分布(ガウス分布)に従う乱数 normal distribution

random.normalvariate(mu, sigma) mu:平均、sigma標準偏差
random.gauss(mu, sigma) normalvariateより少し速い
np.random.normal(loc, scale=1.0, size) loc:平均、scale:標準偏差

 
・標準正規分布に従う standard normal distribution

np.random.randn(size) 標準正規分布(平均0、標準偏差1)

 
・β分布(ベータ分布)

random.betavariate(alpha, beta) β分布の乱数
np.random.beta(a, b, size)

 
・γ分布(ガンマ分布)

gammavariate(alpha, beta) alpha>0, beta>0
random.gammavariate(alpha, beta) ガンマ分布の乱数

 
・カイ2乗分布

np.random.chisquare(df,size) df:自由度

 
・指数分布

random.expovariate(lambd) lambdaは予約語なのでlambd
np.random.exponential(scale, size) scale:β=1/λ

 
・対数分布

random.lognormvariate(mu, sigma) 対数分布の乱数
np.random.lognormal(mean, sigma, size) mean:平均、sigma標準偏差

 

print(np.random.randn(3, 3))           #標準正規分布の3×3配列
# [[-0.52434526  0.16597271 -2.22295048]
#  [ 0.46995083 -0.64576356 -2.73155503]
#  [ 1.04575168  0.05712791 -0.46522963]]
               
print(np.random.normal(10, 5, (2, 3)))  #平均10、標準偏差5、2行3列
# [[ 15.15167613   9.56576376   5.79689885]
#  [ 18.18351327  17.17248557   3.4675871 ]]

 
mu(平均)=20、sd(標準偏差)=5の乱数を10000回発生させ、
ヒストグラム(青)で表示し、正規分布のグラフ(赤)と比較する。

import numpy as np
import matplotlib.pyplot as plt
mu, sd = 20, 5
s = np.random.normal(mu, sd, 10000)
count, bins, ignored = plt.hist(s, 40, normed=True)
plt.plot(bins, 1/(sd * np.sqrt(2 * np.pi)) *
               np.exp( - (bins - mu)**2 / (2 * sd**2) ),
         linewidth=2, color='r')
plt.show()

 
f:id:rare_Remrin:20170427015230p:plain
 

整数

random.randint(low, high) low以上、high以下の整数の乱数を1個生成
random.randrange(low, high, step) low以上、high未満、stepの乱数を1個生成
np.random.randint(low, high, size) low以上、high未満
np.random.random_integers 非推奨

 

np.random.randint(1, 10, 2)         #1以上10未満の整数2個のndarrayを生成。
np.random.randint(1, 10, (2, 3)    #2行3列のndarrayを生成。
np.random.randint(2, size=8)        #highを省略すると、lowの値をhigh扱い。
# array([1, 0, 0, 0, 1, 1, 1, 0])
np.random.randint(1, size=8)        #1未満の整数、つまり0のみ。
# array([0, 0, 0, 0, 0, 0, 0, 0])

 
・2項分布に従う

np.random.binomial(n, p, size) n:試行回数 p:確率

 

# コインを100回投げて表が出た回数
a = np.random.binomial(100, 0.5)
print(a)   # 48

#コインを100回投げて表が出た回数を10セット
print(np.random.binomial(100, 0.5, (2, 5))) 
# [[53 43 48 49 44]
#  [48 47 55 44 60]]

選択

random.choice(seq) seqから1個選択
np.random.choice(a) aから複数個選択

np.random.choice(a, size=None, replace=True, p=None)
a:1次元のndarrayまたはリストの場合、その要素からチョイス。
 数値の場合はnp.arange()で要素を準備
replace True:重複あり、False:重複なし
p:和が1となる重みづけのリスト。
 

seq1=[0123]
random.choice(seq1)              #1回チョイス
random.choice("hello")           #5文字の中から1文字チョイス
np.random.choice(seq1, 4)        #重複ありで4回チョイスした配列
np.random.choice([2, 4, 6],2)   #重複ありで2回チョイスした配列
np.random.choice([0, 1], (3, 3)) #size3×3の配列に0,1を埋める
np.random.choice(5, 2)           #np.randint(0, 5, 2)と同義

 
np.random.choiceで描いたバーンスレイのシダ。サンプルコードはこちら
f:id:rare_Remrin:20170506224421p:plain
 

シャッフル

random.shuffle(list) listをシャッフルする。返り値はNone
np.random.shuffle(x) listまたはarrayをシャッフルする。返り値はNone

 

arr = np.arange(10)
np.random.shuffle(arr)      #[1 7 5 2 9 4 3 6 0 8]

 

サンプリング

random.sample(population, k) populationの中からk個選んだリストを返す。
  populationはシーケンスまたはset。ハッシュ可能でなくてもよい。値はダブり可

random.sample("abcd", 3)    #['d', 'c', 'a']
random.sample("abcd", 6)    #ValueError: Sample larger than population
random.sample(range(1000), k=20)   #0-999から20個選ぶ

 
参考:numpyのドキュメント