Ccmmutty logo
Commutty IT
7 min read

Numpy Tutorial

https://cdn.magicode.io/media/notebox/6dbd3e5b-430a-490b-91fb-a8b6ad31f4ad.jpeg
Numpyは行列計算などの数値計算をを効率的に行うことができるライブラリです。機械学習では必須となる知識なので,このnotebookで基本的な使い方を学びましょう。
ライブラリをインポートします。numpyは慣例的にnpとして扱います。
python
import numpy as np

1. Pythonの配列とnumpy.ndarrayの違い

まず,以下の2つのPythonの配列uu, vvを考えます。
python
u = [1, 2, 3, 4, 5]
v = [1, 4, 9, 16, 25]
この2つの配列をベクトルとして操作してみましょう。
これらのベクトルに対して,内積や和を計算する場合,標準のPythonでは自分で内積や和を返す関数を実装する必要があります。しかし,numpyにはすでにこれらの演算を行う関数が実装されています。
配列はnumpyのnp.array()という関数を用いることでnp.ndarrayに変換できます。np.ndarrayはベクトル,行列,テンソルに対して用意された型で,np.ndarrayに対しnumpyの各種関数を適用することで演算を行います。
具体的には,np.dot()で内積,+で和を求めることができます。
python
u = np.array(u)
v = np.array(v)

print(type(u), type(v))

print(np.dot(u, v))
print(u+v)
<class 'numpy.ndarray'> <class 'numpy.ndarray'> 225 [ 2 6 12 20 30]
行列は以下のようにして作成できます。np.ndarrayの形状はnp.ndarray.shapeで確認できます。ここでは2×3の行列を作成します。
python
a = np.array(
    [
     [1, 2, 3],
     [4, 5, 6]
    ]
)
print(a.shape)
(2, 3)

2. numpy.ndarrayの基本的な演算

python
u = np.array([1, 2, 3, 4, 5])
v = np.array([1, 4, 9, 16, 25])
print(u.shape)
print(v.shape)
(5,) (5,)

2.1. ユニバーサル関数

np.ndarrayの全要素に対して要素ごとに処理を行い,np.ndarrayを返す関数をユニバーサル関数と言います。
2.1.1. 四則演算
np.ndarrayに対してもpythonの基本的な演算子を使って計算することができます。
python
print(u + v)
print(u - v)
print(u * v)
print(u / v)
print(u**3)
[ 2 6 12 20 30] [ 0 -2 -6 -12 -20] [ 1 8 27 64 125] [1. 0.5 0.33333333 0.25 0.2 ] [ 1 4 9 16 25]
計算結果からわかるように,これらは要素ごと,つまりユニバーサルに計算されています。
2.2.2. 条件演算
python
print(u==3)
print(u==v)
print(u < v)
print(type(u < v))
[False False True False False] [ True False False False False] [False True True True True] <class 'numpy.ndarray'>
四則演算と同じように,これらもユニバーサルに計算されています。よって,返り値はbool値のnp.ndarrayとなります。
2.2.3. その他のユニバーサル関数
python
print(np.sin(u))
print(np.log(u))
print(np.exp(u))
[ 0.84147098 0.90929743 0.14112001 -0.7568025 -0.95892427] [0. 0.69314718 1.09861229 1.38629436 1.60943791] [ 2.71828183 7.3890561 20.08553692 54.59815003 148.4131591 ]
numpyにはこれら以外にも多数のユニバーサル関数が用意されています。興味があれば調べてみましょう。

2.2. ブロードキャスト

np.ndarrayの二項演算では,2つのnp.ndarrayの次元や長さを自動的に揃えて計算をします。これをブロードキャストといいます。
python
print(u)
print(3*u)
[1 2 3 4 5] [ 3 6 9 12 15]
このように,3をnp.ndarray([3, 3, 3, 3, 3])と自動的に変換して計算します。
python
c = np.array([3, 3, 3, 3, 3])
print(3 * u == c * u)
[ True True True True True]
ただし,常に自動的に揃えられるわけではないので注意してください。
python
w = np.array([1, 2])
print(w.shape)
print(u.shape)
print(w * u)
(2,) (5,)
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-30-9222f8abbfec> in <module>()
      2 print(w.shape)
      3 print(u.shape)
----> 4 print(w * u)


ValueError: operands could not be broadcast together with shapes (2,) (5,) 
長さが2と5のnp.ndarrayはどう揃えればいいか分からないのでエラーとなります。
行列とベクトルに対してもブロードキャストは有効です。
python
a = np.array(
    [
     [1, 2, 3, 4, 5],
     [6, 7, 8, 9, 0]
    ]
)
print(a.shape)
print(u.shape)
print(a * u)
(2, 5) (5,) [[ 1 4 9 16 25] [ 6 14 24 36 0]]

2.3. その他の基本的な関数

python
print(np.max(u))
print(np.sum(u))
print(np.mean(u))
print(np.std(u))
# np.concatenateによってnp.ndarrayを結合できます。
print(np.concatenate([u, v]))
5 15 3.0 1.4142135623730951 [ 1 2 3 4 5 1 4 9 16 25]

3. numpy.ndarrayの操作

python
u_list = [1, 2, 3, 4, 5]
u = np.array(u_list)
a = np.array(
    [
     [1, 2, 3, 4, 5],
     [6, 7, 8, 9, 10],
     [11, 12, 13, 14, 15]
    ]
)
print(u.shape)
print(a.shape)
(5,) (3, 5)

3.1. インデックスを用いた値の取得

np.ndarrayでもpythonの配列と同じように[]を使うことによって,任意の位置の値を取得できます。行列では行の位置と列の位置を指定することで値を取得できます。インデックスは0から始まることに注意してください。
python
print(u[2])
print(u[-2])

print(a[0, 4])
3 4 5
np.ndarrayでは,複数のインデックスをリストにして指定することで複数の値を同時に取得できます。これはpythonの配列ではエラーとなります。
python
print(u[[0, 1, 3]])
print(u_list[[0, 1, 3]])
[1 2 4]
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-43-68bebaed8f33> in <module>()
      1 print(u[[0, 1, 3]])
----> 2 print(u_list[[0, 1, 3]])


TypeError: list indices must be integers or slices, not list
二次元配列(行列)では,np.ix_を用いることで各軸のインデックスを別々に指定できます。以下の例では[0, 1], [0, 3], [2, 1], [2, 3]に対応する要素を部分行列として抽出できます。
python
print(a[np.ix_([0, 2], [1, 3])])
[[ 2 4] [12 14]]

3.2. スライス

np.ndarrayは基本的に,pythonの配列と同じようにstart: end: stepでスライスすることができます。
python
print(u)
print('[:3:2]', u[:3:2])
print('[1::2]', u[1::2])
print('[1:3:]', u[1:3:])
print('[1:3]', u[1:3])
print('[1:]', u[1:])
[1 2 3 4 5] [:3:2] [1 3] [1::2] [2 4] [1:3:] [2 3] [1:3] [2 3] [1:] [2 3 4 5]
二次元配列(行列)では,それぞれの軸(行と列)に対するスライスを指定します。
python
print(a[0:2, 0:3])
[[1 2 3] [6 7 8]]

3.3. ブールインデックス参照

インデックスにbool値のnp.ndarrayや配列を指定すると,Trueに対応する要素だけを抽出したnp.ndarrayを返します。
python
bool_idx_1d = [False, False, True, False, True]
print(u[bool_idx_1d])

bool_idx_2d = np.ix_([True, False, True], [False, False, True, False, True])
print(a[bool_idx_2d])
[3 5] [[ 3 5] [13 15]]
条件演算子と合わせて用いることで,特定の条件を満たす要素のみを抽出できます。
python
print(u[u > 3])

Discussion

コメントにはログインが必要です。