16. NumPy (1): ベクトル#
このノートブックではnumpy
モジュールのエイリアス(短縮表記)としてnp
を用いる。
import numpy as np
16.1. 作成#
NumPyのベクトルをnp.arrayで作成する。以下のコードは2次元ベクトル
を作成し、変数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')
ベクトルを作成するときに要素の型を指定できる。
x = np.array([1, 2, 3, 4, 5], dtype='float')
x
array([1., 2., 3., 4., 5.])
x.dtype
dtype('float64')
16.2. スライス#
ベクトルx
の要素\(x_1\)
x[1]
2.0
ベクトルx
の\(0\)番目から\(1\)番目までの要素を取り出したベクトル\(\pmb{x}_{0:2}\)(スライス)。
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.])
16.3. 算術演算#
に対して、様々な演算を紹介する。
x = np.array([1, 2, 3])
y = np.array([6, 4, 2])
ベクトルの和
x + y
array([7, 6, 5])
ベクトルの差
x - y
array([-5, -2, 1])
ベクトルとベクトルの要素積(アダマール積)
x * y
array([6, 8, 6])
ベクトルとベクトルの内積
np.dot(x, y)
20
ベクトルとベクトルの内積は@
演算子で書くこともできる(Python 3.5以上)。
x @ y
20
ベクトルとベクトルの累乗
x ** y
array([ 1, 16, 9])
16.3.1. ブロードキャスティング#
ブロードキャスティングとは、ベクトルとスカラーなど、本来は形が合わずに計算ができないオブジェクト間において、算術計算時に自動的に形を合わせてくれる機能である。以下に紹介する例はスカラーとベクトル間で演算を行う例であるが、これらはブロードキャスティングにより説明できる。
スカラーとベクトルの和
1 + x
array([2, 3, 4])
スカラーとベクトルの差
1 - x
array([ 0, -1, -2])
ベクトルのスカラー倍
2 * x
array([2, 4, 6])
ベクトルの累乗
x ** 2
array([1, 4, 9])
ベクトルの要素数が合わないなどで、演算が実行できないときは例外が発生する。以下の例では、\(\pmb{x} \in \mathbb{R}^3, \pmb{z} \in \mathbb{R}^2\)のため、\(\pmb{x}+\pmb{z}\)の計算ができない。
z = np.array([1, 2])
x + z
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/tmp/ipykernel_205166/2063851844.py in <module>
1 z = np.array([1, 2])
----> 2 x + z
ValueError: operands could not be broadcast together with shapes (3,) (2,)
16.4. 様々な作成方法#
零ベクトル: \(\boldsymbol{0}\)
np.zeros(4)
array([0., 0., 0., 0.])
x
と同じ要素数の零ベクトル。
x = np.array([1, 2, 3])
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.12162432, 0.19088018, 0.24584746, 0.3852018 ])
標準正規分布(平均\(0\)、分散\(1\)の正規分布)からランダムに要素を抽出して作ったベクトル。
np.random.randn(4)
array([0.85354541, 1.09364516, 0.22995723, 0.15205818])
正規分布(以下の例では平均\(0.5\)、分散\(2\)の正規分布)からランダムに要素を抽出して作ったベクトル。
np.random.normal(0.5, 2, 4)
array([-1.03402695, 0.12491045, 2.41473327, -0.64760535])
16.5. 数学関数#
NumPyで用意されている数学関数を
を例に説明する。
x = np.array([1, -1, 2, -2, 3])
x
array([ 1, -1, 2, -2, 3])
ベクトルの要素の和
np.sum(x)
3
ベクトルの要素の積
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 s^2 = \frac{1}{N-1}\sum_{i=0}^{N-1} (x_i - \bar{x})^2 = \frac{1}{N-1}\sum_{i=0}^{N-1} x_i^2 - \bar{x}^2\)
np.var(x, ddof=1)
4.300000000000001
ベクトルの要素の(標本)標準偏差: \(\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.var(ddof=1)
4.300000000000001
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
16.6. ユニバーサル関数#
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])
16.7. 反復処理#
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)
5.43 µs ± 202 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%%timeit
s = 0
for v in x:
s += v
463 µs ± 25.2 µ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]
699 µs ± 16.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)