大規模高速計算を前提にC言語との接続を前提にしていて、配列処理に寄せることになる。
ndarrayで確保するメモリはPythonとは別(プロセス?)で確保される。
一通り流してみる。
shape()で配列の形を応答する。2行3列。
1 2 3 4 5 6 7 8 9 10 |
import numpy as np data = np.random.randn(2,3) shape = data.shape print(shape) print(data) # (2, 3) # [[ 0.79004157 0.45749364 0.90854549] # [-1.91791968 2.80050094 -0.60338724]] |
ndarrayを作る
ndarrayを作る方法は以下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
data1 = [1,2,3,4,5] data2 = [6,7,8,9,10] data = np.array([data1,data2]) print(data) # [[ 1 2 3 4 5] # [ 6 7 8 9 10]] rng = np.arange(5) print(rng) # [0 1 2 3 4] ones = np.ones((5,5)) print(ones) # [[1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.]] # 零行列 zeros = np.zeros((3,5)) print(zeros) # [[0. 0. 0. 0. 0.] # [0. 0. 0. 0. 0.] # [0. 0. 0. 0. 0.]] # 未初期化の配列確保 empties = np.empty((5,3)) print(empties) # [[-1.72723371e-077 -1.72723371e-077 2.24419447e-314] # [ 2.24421423e-314 2.24421423e-314 2.24563072e-314] # [ 2.24421559e-314 2.24563072e-314 2.24421570e-314] # [ 2.24563072e-314 2.24421558e-314 2.24563072e-314] # [ 2.24421562e-314 2.24563072e-314 2.24421577e-314]] # 指定値で埋める fulls = np.full((2,3),5) print(full) # [[5 5 5] # [5 5 5]] # 単位行列 identities = np.identity(5) print(identities) # [[1. 0. 0. 0. 0.] # [0. 1. 0. 0. 0.] # [0. 0. 1. 0. 0.] # [0. 0. 0. 1. 0.] # [0. 0. 0. 0. 1.]] |
ndarrayのデータ型
ndarrayで確保されるメモリのデータ型。
実際に型に従ってメモリが確保されているため、簡単にCに渡せる。
1 2 3 4 5 6 7 8 9 10 11 12 |
ary = np.array((1,2,3),dtype=np.float64) print(ary) # [1. 2. 3.] # float64をint32でキャスト ary_int = ary.astype(np.int32) print(ary_int) # [1 2 3] # キャストできないとコケる ary_str = np.array(['hoge','fuga']) ary_str_int = ary_str.astype(np.int32) # ValueError: invalid literal for int() with base 10: 'hoge' |
ベクトル演算
配列に寄せる醍醐味。Pythonに数値計算用のオペランドが用意されていることがあって、
割と自然に書ける。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
ary = np.array([[1,2,3],[4,5,6]]) print(ary * ary) # [[ 1 4 9] # [16 25 36]] print(ary - ary) # [[0 0 0] # [0 0 0]] print(ary * 2) # [[ 2 4 6] # [ 8 10 12]] print(ary ** 2) # [[ 1 4 9] # [16 25 36]] |
スライスとView
巨大なメモリへのアクセス高速化のために、np.arrayに対するスライスによるアクセスは、
同じメモリを指すViewを返す。Viewに対する操作は元のメモリを変更する。
Copyする場合は明示的にCopyをする必要がある。
1 2 3 4 5 6 7 8 |
ary = np.arange(10) print(ary) # [0 1 2 3 4 5 6 7 8 9] ary[5] = 500 print(ary) # [ 0 1 2 3 4 500 6 7 8 9] ary[3:5] = 999 print(ary) # [ 0 1 2 900 900 500 6 7 8 9] copied = ary.copy() print(copied) # [ 0 1 2 900 900 500 6 7 8 9] |
2次元のnp.array。要素へのアクセスの仕方は2通り。
1 2 3 4 5 6 7 |
ary2d = np.array([[1,2,3],[10,20,30]]) print(ary2d) # [[ 1 2 3] # [10 20 30]] print(ary2d[1]) # [10 20 30] print(ary2d[1][0]) # 10 print(ary2d[1,0]) # 10 |
n次元arrayへスカラーでインデックス参照するとn-1次元が戻る。
スライス参照はn次元が戻る。
1 2 3 4 5 6 7 8 |
ary2d = np.array([[1,2,3],[10,20,30],[100,200,300]]) print(ary2d[1]) # [10 20 30] print(ary2d[:2]) # [[ 1 2 3] # [10 20 30]] print(ary2d[1,:2]) # [10,20] |
Viewの選択
ndarrayから欲しいViewを選択するために色々と条件をつけられる。
例えば、bool index参照。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
data = np.random.randn(7,4) print(data) # [[-0.69179761 -1.30790477 1.7224557 -0.67436315] # [ 0.45457462 0.24713663 -0.84619583 -0.31182853] # [-1.36397651 0.51770088 -1.8459593 -1.75146057] # [ 2.38626251 -0.4747874 -0.49951212 0.61803437] # [ 1.00048197 1.21838773 -0.4828001 0.9952139 ] # [ 0.17838262 1.687342 0.81501139 -1.12800811] # [ 0.65216988 -2.57185067 0.29802975 0.28870091]] recs = np.array(['apple','orange','banana','mountain','river','moon','snow']) print(recs=='mountain') # [False False False True False False False] print(data[recs=='mountain']) # [[ 2.38626251 -0.4747874 -0.49951212 0.61803437]] |
reshape
reshape()を使って行列の形を変える。例えば1×15のndarrayを3×5のndarrayに変換。
もちろんCopyではなくView。これは頻出っぽい。
ちなみに、転値は専用のメソッド(T)が用意されている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
data1 = np.arange(15) print(data1) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] data2 = data1.reshape(3,5) print(data2) # [[ 0 1 2 3 4] # [ 5 6 7 8 9] # [10 11 12 13 14]] data3 = data2.T print(data3) # [[ 0 5 10] # [ 1 6 11] # [ 2 7 12] # [ 3 8 13] # [ 4 9 14]] |