Contents
randomモジュールとnumpy.randomモジュール
randomモジュールとnumpy.randomモジュールに関する自分なりの整理。
まずは大まかな違いから。
- randomモジュールはランダムな値(スカラー)をひとつ返す
- numpy.randomモジュールはランダムな値のテンソル(行列)を返す
つぎに細かい違い。
- randomモジュールの関数は引数にタプルをとらない(スカラーしか返さないので)
- numpy.randomモジュールの関数はテンソルの形状を指定するためにタプルを引数にとることがある
0以上1未満の浮動小数点数。
1 2 3 4 5 6 7 8 9 10 11 12 |
import random import numpy as np random.random() # 引数はとらない # 0.5041946933017601 np.random.rand() # 引数なしだとrandom.randomとおなじ。型もおなじfloat。 # 0.6887576297767313 np.random.rand(2, 3) # 引数にタプルはとらない。型はnumpy.ndarray。 # [[0.15779056 0.5504217 0.6798975 ] # [0.76120037 0.89513157 0.32411756]] |
任意の範囲の浮動小数点数。
1 2 3 4 5 6 7 8 9 10 11 12 |
random.uniform(10, 20) # 引数は必ず2つ。それ以外は例外になる。 # 14.260591290557045 # こちらは引数が1つでもいい。その場合はそれ以下(未満?)のランダムな値が返る。 np.random.uniform(10, 20, size=(2, 3)) # [[11.20708316 11.17868682 13.30127977] # [18.94582258 10.54308225 10.95161282]] # ↑の存在を忘れた場合はjavascriptな感じでつくってもいい。 (20 - 10) * np.random.rand(2, 3) + 10 # 範囲の幅で引き延ばしてから平行移動 # [[13.82931823 18.92855327 19.12684433] # [18.81660543 15.23233736 13.0839209 ]] |
任意の範囲の整数。
1 2 3 4 5 6 |
random.randint(10, 20) # 13 np.random.randint(10, 20, (2, 3)) # 第3引数を指定しないとスカラー(int型)が返る # [[12 15 16] # [14 12 17]] |
random.randrangeはrandom.randintとほぼおなじだし、個人的にあまり使わなそうなのでカット。
以下、対応関係。
用途 | random | numpy.random |
---|---|---|
0以上1未満の浮動小数点数 | random.random | np.random.rand |
任意の範囲の浮動小数点数 | random.uniform | np.random.uniform |
任意の範囲の整数 | random.randint | np.random.randint |
正規分布などについては今回はスルー。基本のみ。
random.choice/choices/sampleとnp.random.choiceを比較
random.choice
random.choiceはリスト(やタプル・文字列)から要素をひとつ選ぶ。オプションはない。
1 2 |
random.choice([1, 2, 3]) # 2 |
random.choices
random.choicesは複数の要素を重複ありで選ぶ。重複なしのオプションはない。
1 2 3 4 5 6 |
random.choices([1, 2, 3, 4, 5], k=3) # [5, 3, 3] # 重複ありなのでkは配列の長さより大きな値も指定できる random.choices([1, 2, 3, 4, 5], k=10) # [4, 5, 3, 5, 4, 4, 4, 1, 3, 2] |
よく使うオプションはweightsで、要素を選ぶ確率を指定することができる。
1 2 3 |
# 確率weightsにしたがって2個選ぶ。 random.choices([1, 2, 3, 4, 5], k=2, weights=[0.35, 0.35, 0.1, 0.1, 0.1]) # [1, 2] |
random.sample
random.sampleは複数の要素を重複なしで選ぶ。weightsオプションはない。
1 2 |
random.sample([1, 2, 3, 4, 5], k=3) # [2, 3, 1] |
np.random.choice
np.random.choiceは重複あり/なしで複数の要素を選べる。選ぶ個数はrandom.chocesのkとちがってsizeで、タプルで指定するとテンソルの形で返してくれる。重み(確率)を指定するオプションはp。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 重複あり(デフォルト) np.random.choice([1, 2, 3, 4, 5], size=3) # [5 1 5] # 重複なし np.random.choice([1, 2, 3, 4, 5], size=3, replace=False) # [3 5 2] # 重みを指定 np.random.choice([1, 2, 3, 4, 5], size=3, p=[0.6, 0.1, 0.1, 0.1, 0.1]) # [4 1 1] # sizeにタプルを指定 np.random.choice(np.array([1, 2, 3, 4, 5]), size=(2, 2)) # [[4 3] # [4 1]] |
すこし変わっているのは、0より大きい整数Nを指定すると0~N-1から選ぶ。戻り値の型はint。この機能いる?w
1 2 3 |
np.random.choice(5) # 3 # <class 'int'> |
ついでに
random.choicesにnumpy配列を与えてみたがふつうに動く。iterableだったらなんでも受け付ける感じなのかな。
1 2 3 |
random.choices(np.array([1, 2, 3, 4, 5]), k=2) # [1, 5] # <class 'list'> |
地味に便利な形状指定方法
たとえば学習用のトイデータを作成する場合、このようなコードを書くことがある。
1 2 |
X = np.random.uniform(-5, 5, size=(100, 1)) y = 2*X + 1 + 2*np.random.randn(100, 1) |
Xのサイズを調べてrandn関数に書かなければならないわけだが、これが面倒。
1 2 |
X = np.random.uniform(-5, 5, size=(100, 1)) y = 2*X + 1 + 2*np.random.randn(X.shape) |
こう書きたくなるが、タプルはだめよと怒られる。どうにかならないかなといろいろ試した結果、これでうまくいった。
1 2 |
X = np.random.uniform(-5, 5, size=(100, 1)) y = 2*X + 1 + 2*np.random.randn(*X.shape) |
タプルやリストに*をつけて関数の引数にわたすと展開される。ちなみに辞書型を展開するには**をつける。
np.arangeは
np.arangeはrange関数の少数まで指定できるバージョン。
ということはnp.linspaceにも対応するpythonのビルトイン関数があるかも、と思ったがないみたい。
軸の入れ替え(numpy.transpose / K.permute_dimensions)
2次元テンソルの軸の入れ替えは縦横入れ替えるだけなのでわかりやすいが、3次元以上になるとこんがらがる。ただ、深層学習でこれが登場するのは画像を扱っているときが多い。
(縦,横,チャネル)と(チャネル,縦,横)のふたつのパターンがあるが、これを相互変換するときに出てくることが多い。
(縦,横,チャネル)のテンソルxがあったとして
1 |
x = x.transpose(2, 0, 1) |
(チャネル,縦,横)に軸を入れ替える。これは意味的にはRGBの1枚の画像→R(赤成分)の画像、G(緑成分)の画像、B(青成分)の画像の3枚に分けたと考えると理解しやすい。
もっと一般的にいうと、最後の軸の特徴量ごとにテンソルを分離するということ。というのが現在の理解。
最後の軸(チャネルの軸)を手前(サンプル(バッチ)次元のひとつあと)に持ってくる以外の軸の入れかえっていまのところ見たことない。
一般的な場合でtransposeを理解するのは凡人には無理だが(任意の軸の入れ替えとか考えるとアタマがショートする)、現実に出てくるパターンに絞って理解することはできる。
numpy配列の保存と読み込み
1 2 3 4 5 6 7 |
# 保存 x, yはnumpy配列 np.savez('data.npz', x=x, y=y) # 読み込み data = np.load('data.npz') x = data['x'] y = data['y'] |
連番の行列を生成する
ランダムな要素からなる行列はかんたんにつくれる。
1 2 |
X = np.random.rand(2,3) # 2行3列 X = np.random.randn(2,3) # 2行3列 |
ただ、ランダムな要素だとなにか処理したあと、どの要素がどこにいったのか確認しづらい。連番からなる行列を生成したい。それにはnp.arangeで連番の配列を生成してからreshapeすればいい。トンチか。
1 2 |
X = np.arange(2*3) # [0,1,2,3,4,5] X = X.reshape(2,3) # 2行3列 |