ベクトル(NumPy その1)

このノートブックではnumpyモジュールのエイリアス(短縮表記)としてnpを用いる.

import numpy as np

ベクトルのオブジェクト

NumPyのベクトルをnp.arrayで作成する.以下のコードは2次元ベクトル\( \boldsymbol{x} = \left(\begin{array}{c} x_0 \\ x_1 \\ x_2 \end{array}\right) = \left(\begin{array}{c} 1 \\ 2 \\ 3 \end{array}\right) \)を作成し,変数xに代入する.※ 通常,数学において先頭要素のインデックス番号は\(1\)であるが,Pythonでは先頭要素のインデックス番号が\(0\)なので,ベクトルや行列を数学で表現するときも先頭要素のインデックス番号は\(0\)とする.

x = np.array([1, 2, 3, 4, 5])
x
array([1, 2, 3, 4, 5])

作成されたオブジェクトの型はnumpy.ndarray

type(x)
numpy.ndarray

ベクトルの次元数(軸の数).xは1次元ベクトル.

x.ndim
1

各次元の要素数を表すタプル.xの1次元目には\(5\)つの要素が格納されている.

x.shape
(5,)

オブジェクトに含まれる要素数.xは1次元ベクトルなので1次元目の要素数に等しい.

x.size
5

各要素の型.xは整数を格納するベクトルとして定義されている.

x.dtype
dtype('int64')

NumPyのベクトルを作るときに要素の型を指定できる.

x = np.array([1, 2, 3, 4, 5], dtype='float')
x
array([1., 2., 3., 4., 5.])
x.dtype
dtype('float64')

ベクトルの要素

ベクトルxの要素\(x_1\)

x[1]
2.0

ベクトルx\(0\)番目から\(1\)番目までの要素を取り出したベクトル(スライス).

x[0:2]
array([1., 2.])

スライスの開始位置が\(0\)の場合は省略できる(リストと同様).

x[:2]
array([1., 2.])

要素を逆順に並べる.

x[::-1]
array([5., 4., 3., 2., 1.])

スライスにリストを指定してもよい.

x[[1,3]]
array([2., 4.])

要素に値を代入する.\(x_1 \leftarrow -1\)

x[1] = -1
x
array([ 1., -1.,  3.,  4.,  5.])

ベクトルのスライスに値を代入する.\((x_0, x_1) \leftarrow (2, 2)\)

x[:2] = 2.
x
array([2., 2., 3., 4., 5.])

ベクトルの演算

\(\boldsymbol{x} = \left(\begin{array}{c} 1 \\ 2 \\ 3 \end{array}\right), \boldsymbol{y} = \left(\begin{array}{c} 1 \\ -1 \\ 2 \end{array}\right) \) に対して,様々な演算を見ていく.

x = np.array([1, 2, 3])
y = np.array([6, 4, 2])

ベクトルの和: \(\boldsymbol{x} + \boldsymbol{y}\)

x + y
array([7, 6, 5])

ベクトルの差: \(\boldsymbol{x} - \boldsymbol{y}\)

x - y
array([-5, -2,  1])

ベクトルのスカラー倍: \(2\boldsymbol{x}\)

2 * x
array([2, 4, 6])

スカラーとベクトルの和: \(\boldsymbol{1} + \boldsymbol{x}\)

1 + x
array([2, 3, 4])

スカラーとベクトルの差: \(\boldsymbol{1} - \boldsymbol{x}\)

1 - x
array([ 0, -1, -2])

ベクトルとベクトルの要素積(アダマール積): \(\boldsymbol{x} \odot \boldsymbol{y} = \left(\begin{array}{c} x_0 y_0 \\ x_1 y_1 \\ \dots \\ x_{n-1} y_{n-1} \end{array}\right)\)

x * y
array([6, 8, 6])

ベクトルとベクトルの内積: \(\boldsymbol{x} \cdot \boldsymbol{y} = \displaystyle \sum_{i=0}^{n-1} x_i y_i\)

np.dot(x, y)
20

ベクトルとベクトルの内積は@演算子で書くこともできる(Python 3.5以上).

x @ y
20

ベクトルとベクトルの累乗: \(\left(\begin{array}{c}x_0^{y_0}\\x_1^{y_1}\\x_2^{y_2}\end{array}\right)\)

x ** y
array([ 1, 16,  9])

ベクトルの累乗: \(\boldsymbol{x}^2\)

x ** 2
array([1, 4, 9])

ベクトルの要素数が合わないなどで,演算が実行できないときはエラーとなる.

z = np.array([1, 2])
x + z
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-30-2d5f8479e2db> in <module>
----> 1 x + z

ValueError: operands could not be broadcast together with shapes (3,) (2,) 

様々なベクトルの作成法

x = np.array([1, 2, 3])

零ベクトル: \(\boldsymbol{0}\)

np.zeros(4)
array([0., 0., 0., 0.])

xと同じ要素数の零ベクトル.

np.zeros_like(x)
array([0, 0, 0])

\(1\)ベクトル: \(\boldsymbol{1}\)

np.ones(4)
array([1., 1., 1., 1.])

xと同じ要素数の\(1\)ベクトル.

np.ones_like(x)
array([1, 1, 1])

任意の値で初期化したベクトル

np.full(4, -2.)
array([-2., -2., -2., -2.])

xと同じ要素数で任意の値で初期化したベクトル.

np.full_like(x, -2.)
array([-2, -2, -2])

\(0\)以上\(10\)未満の整数を並べたベクトル(np.arange関数の使い方はrange関数と同様).

np.arange(0, 10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

\(1\)から\(100\)未満の範囲で\(20\)ずつ整数を並べたベクトル.

np.arange(1, 100, 20)
array([ 1, 21, 41, 61, 81])

始点\(0\)から終点\(360\)までの範囲を等分して,始点と終点を含む\(5\)個の境界値を要素としたベクトル.

np.linspace(0, 360, 5)
array([  0.,  90., 180., 270., 360.])

始点\(0\)から終点\(360\)までの範囲を等分して,始点を含むが終点を含まない\(4\)個の境界値を要素としたベクトル.

np.linspace(0, 360, 4, endpoint=False)
array([  0.,  90., 180., 270.])

\([0, 1)\)の範囲の一様分布からランダムに要素をサンプルして作ったベクトル.

np.random.rand(4)
array([0.38399528, 0.74826769, 0.68007912, 0.67571172])

標準正規分布(平均\(0\),分散\(1\)の正規分布)からランダムに要素をサンプルして作ったベクトル.

np.random.randn(4)
array([ 0.53466592, -0.54565195,  0.02305556,  0.9635037 ])

正規分布(以下の例では平均\(0.5\),分散\(2\)の正規分布)からランダムに要素をサンプルして作ったベクトル.

np.random.normal(0.5, 2, 4)
array([ 1.99650715, -1.19212205, -0.46253724, -0.38194532])

数学関数

NumPyでは数学関数が用意されている.

x = np.array([1, -1, 2, -2, 3])
x
array([ 1, -1,  2, -2,  3])

ベクトルの要素の和: \(\displaystyle \sum_{i=0}^{N-1} x_i\)

np.sum(x)
3

ベクトルの要素の積: \(\displaystyle \prod_{i=0}^{N-1} x_i\)

np.prod(x)
12

ベクトルの累積和

np.cumsum(x)
array([1, 0, 2, 0, 3])

ベクトルの累積積

np.cumprod(x)
array([ 1, -1, -2,  4, 12])

ベクトルの要素の平均: \(\displaystyle \bar{x} = \frac{1}{N}\sum_{i=0}^{N-1} x_i\)

np.mean(x)
0.6

ベクトルの要素の分散: \(\displaystyle \sigma^2 = \frac{1}{N}\sum_{i=0}^{N-1} (x_i - \bar{x})^2 = \frac{1}{N}\sum_{i=0}^{N-1} x_i^2 - \bar{x}^2\)

np.var(x)
3.4400000000000004

ベクトルの要素の標準偏差: \(\displaystyle \sigma = \sqrt{\frac{1}{N}\sum_{i=0}^{N-1} (x_i - \bar{x})^2}\)

np.std(x)
1.854723699099141

ベクトルの要素の最小値: \(\displaystyle \min\limits_{i \in \{0, \dots, N-1\}} x_i\)

np.min(x)
-2

ベクトルの要素の最大値: \(\displaystyle \max\limits_{i \in \{0, \dots, N-1\}} x_i\)

np.max(x)
3

ベクトルの要素の最小値に対応するインデックス番号(何番目の要素が最小値か): ベクトルの要素の最小値: \(\displaystyle \mathop{\rm argmin}\limits_{i \in \{0, \dots, N-1\}} x_i\)

np.argmin(x)
3

ベクトルの要素の最大値に対応するインデックス番号(何番目の要素が最大値か): \(\displaystyle \mathop{\rm argmax}\limits_{i \in \{0, \dots, N-1\}} x_i\)

np.argmax(x)
4

なお,これまでの処理はndarrayクラスのメソッドとして呼び出すことも可能である.

x.sum()
3
x.mean()
0.6
x.var()
3.4400000000000004
x.std()
1.854723699099141
x.min()
-2
x.max()
3
x.argmin()
3
x.argmax()
4

ベクトルの\(l_0\)ノルム(非零の要素数): \(\|\boldsymbol{x}\|_0\)

np.linalg.norm(x, ord=0)
5.0

ベクトルの\(l_1\)ノルム(絶対値の和): \(\|\boldsymbol{x}\|_1 = \displaystyle \sum_{i=0}^{N-1} |x_i|\)

np.linalg.norm(x, ord=1)
9.0

ベクトルの\(l_2\)ノルム(絶対値の和): \(\|\boldsymbol{x}\|_2 = \displaystyle \sqrt{\sum_{i=0}^{N-1} x_i^2}\)

np.linalg.norm(x, ord=2)
4.358898943540674

ユニバーサル関数: 数学関数

NumPyにはベクトルのサイズによらず,要素ごとに数学的な計算を行うユニバーサル関数が用意されている.

x = np.array([1, -1, 2, -2, 3])
theta = np.linspace(0, 360, 13)   # [0, 30, 60, ..., 360]

ベクトルの累乗(**と同じ).

y = np.power(x, 4)
y
array([ 1,  1, 16, 16, 81])

ベクトルの平方根.

np.sqrt(y)
array([1., 1., 4., 4., 9.])

\(e\)に対する指数

y = np.exp(x)
y
array([ 2.71828183,  0.36787944,  7.3890561 ,  0.13533528, 20.08553692])

自然対数

np.log(y)
array([ 1., -1.,  2., -2.,  3.])

三角関数

np.sin(theta / 360 * 2 * np.pi)
array([ 0.00000000e+00,  5.00000000e-01,  8.66025404e-01,  1.00000000e+00,
        8.66025404e-01,  5.00000000e-01,  1.22464680e-16, -5.00000000e-01,
       -8.66025404e-01, -1.00000000e+00, -8.66025404e-01, -5.00000000e-01,
       -2.44929360e-16])
np.cos(theta / 360 * 2 * np.pi)
array([ 1.00000000e+00,  8.66025404e-01,  5.00000000e-01,  6.12323400e-17,
       -5.00000000e-01, -8.66025404e-01, -1.00000000e+00, -8.66025404e-01,
       -5.00000000e-01, -1.83697020e-16,  5.00000000e-01,  8.66025404e-01,
        1.00000000e+00])
np.tan(theta / 360 * 2 * np.pi)
array([ 0.00000000e+00,  5.77350269e-01,  1.73205081e+00,  1.63312394e+16,
       -1.73205081e+00, -5.77350269e-01, -1.22464680e-16,  5.77350269e-01,
        1.73205081e+00,  5.44374645e+15, -1.73205081e+00, -5.77350269e-01,
       -2.44929360e-16])

ユニバーサル関数: 絶対値,切り捨て,切り上げなど

x = np.linspace(-2, 2, 11)
x
array([-2. , -1.6, -1.2, -0.8, -0.4,  0. ,  0.4,  0.8,  1.2,  1.6,  2. ])

ベクトルの絶対値

np.abs(x)
array([2. , 1.6, 1.2, 0.8, 0.4, 0. , 0.4, 0.8, 1.2, 1.6, 2. ])

切り捨て

np.floor(x)
array([-2., -2., -2., -1., -1.,  0.,  0.,  0.,  1.,  1.,  2.])

切り上げ

np.ceil(x)
array([-2., -1., -1., -0., -0.,  0.,  1.,  1.,  2.,  2.,  2.])

原点方向へ切り捨て

np.fix(x)
array([-2., -1., -1., -0., -0.,  0.,  0.,  0.,  1.,  1.,  2.])

四捨五入

np.round(x)
array([-2., -2., -1., -1., -0.,  0.,  0.,  1.,  1.,  2.,  2.])

比較演算子でも要素ごとの比較演算が行われる.

x < 1
array([ True,  True,  True,  True,  True,  True,  True,  True, False,
       False, False])
x != 0
array([ True,  True,  True,  True,  True, False,  True,  True,  True,
        True,  True])

反復処理

x = np.arange(0, 10000)

ベクトルの要素に対する反復.

s = 0
for v in x:
    s += v
s
49995000
s = 0
for i in range(x.shape[-1]):
    s += x[i]
s
49995000

Pythonのインタプリタの実行速度は遅いので,NumPy上の演算や関数で済む処理をPythonの反復処理として実装してしまうと,大変遅くなる.したがって,やむを得ない場合を除き,for文は避ける.

%%timeit
np.sum(x)
7.55 µs ± 161 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%%timeit
s = 0
for v in x:
    s += v
1.5 ms ± 70.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
s = 0
for i in range(x.shape[-1]):
    s += x[i]
2.39 ms ± 137 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)