大規模高速計算を前提にC言語との接続を前提にしていて、配列処理に寄せることになる。
ndarrayで確保するメモリはPythonとは別(プロセス?)で確保される。
一通り流してみる。
shape()で配列の形を応答する。2行3列。
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を作る方法は以下。
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に渡せる。
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に数値計算用のオペランドが用意されていることがあって、
割と自然に書ける。
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をする必要がある。
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通り。
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次元が戻る。
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参照。
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)が用意されている。
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]]