このノートブックではnumpy
モジュールのエイリアス(短縮表記)としてnp
を用いる。
import numpy as np
x = np.array([
[1, 2, 3, 4],
[2, 3, 4, 5],
[3, 4, 5, 6]
])
x
array([[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]])
作成されたオブジェクトの型はnumpy.ndarray。
type(x)
numpy.ndarray
行列の次元数(軸の数)は2(x
は2次元の行列)。
x.ndim
2
各次元の要素数を表すタプル。x
の1次元目には$3$個、2次元目には$4$個の要素が格納されている。すなわち、$3 \times 4$の行列であることを表している。
x.shape
(3, 4)
オブジェクトに含まれる要素数。x
は$3 \times 4$の行列なので、全要素数は$12$。
x.size
12
x
の各要素は整数である。
x.dtype
dtype('int64')
x = np.array([
[1, 2, 3, 4],
[2, 3, 4, 5],
[3, 4, 5, 6]
])
行列$\pmb{X}$の$2$行$1$列目の要素$X_{2,1}$(インデックスが$0$から始まることに注意)。
x[2][1]
4
要素$X_{2,1}$に以下のようにアクセスすることも可能。
x[2,1]
4
行列$\pmb{X}$の1次元目(行)で1番目の行$\pmb{X}_{1,:}$を取り出す(1行目の行ベクトル)。
x[1]
array([2, 3, 4, 5])
行列$\pmb{X}$の2次元目(列)で1番目の列$\pmb{X}_{:,1}$を取り出す(1列目の列ベクトル)。
x[:,1]
array([2, 3, 4])
行列$\pmb{X}$の1行目および1列目まで$\pmb{X}_{0:2,0:2}$を取り出す(つまり、左上から$2 \times 2$の部分を取り出す)。
x[:2,:2]
array([[1, 2], [2, 3]])
スライスで取り出す要素をリストで指定してもよい。
x[[0,1,2],[0,1,2]]
array([1, 3, 5])
行列$\pmb{X}$の要素$X_{0,0} \leftarrow 0$
x[0][0] = 0
x
array([[0, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]])
行列$\pmb{X}$の0行目の行ベクトル$\pmb{X}_{0,:} \leftarrow \boldsymbol{0}$
x[0] = 0
x
array([[0, 0, 0, 0], [2, 3, 4, 5], [3, 4, 5, 6]])
行列$\pmb{X}$の0列の列ベクトル$\pmb{X}_{:,0} \leftarrow \boldsymbol{0}$
x[:,0] = 0
x
array([[0, 0, 0, 0], [0, 3, 4, 5], [0, 4, 5, 6]])
$\pmb{X}_{0,:} \leftarrow \left(\begin{array}{c} 0 & 1 & 2 & 3 \end{array}\right)$
x[0] = np.arange(4)
x
array([[0, 1, 2, 3], [0, 3, 4, 5], [0, 4, 5, 6]])
に対して、様々な演算を見ていく。
x = np.array([
[1, 2, 3],
[2, 3, 4],
], dtype='float')
y = np.array([
[1, 3, 5],
[2, 4, 6],
], dtype='float')
行列の和
$$ \pmb{X} + \pmb{Y} = \left(\begin{array}{c} 1 & 2 & 3 \\ 2 & 3 & 4 \end{array}\right) + \left(\begin{array}{c} 1 & 3 & 5 \\ 2 & 4 & 6 \\ \end{array}\right) = \left(\begin{array}{c} 1+1 & 2+3 & 3+5 \\ 2+2 & 3+4 & 4+6 \\ \end{array}\right) = \left(\begin{array}{c} 2 & 5 & 8 \\ 4 & 7 & 10 \\ \end{array}\right) $$x + y
array([[ 2., 5., 8.], [ 4., 7., 10.]])
行列の差
$$ \pmb{X} - \pmb{Y} = \left(\begin{array}{c} 1 & 2 & 3 \\ 2 & 3 & 4 \end{array}\right) - \left(\begin{array}{c} 1 & 3 & 5 \\ 2 & 4 & 6 \\ \end{array}\right) = \left(\begin{array}{c} 1-1 & 2-3 & 3-5 \\ 2-2 & 3-4 & 4-6 \\ \end{array}\right) = \left(\begin{array}{c} 0 & -1 & -2 \\ 0 & -1 & -2 \\ \end{array}\right) $$x - y
array([[ 0., -1., -2.], [ 0., -1., -2.]])
行列と行列のアダマール積
$$ \pmb{X} \odot \pmb{Y} = \left(\begin{array}{c} 1 & 2 & 3 \\ 2 & 3 & 4 \end{array}\right) \odot \left(\begin{array}{c} 1 & 3 & 5 \\ 2 & 4 & 6 \\ \end{array}\right) = \left(\begin{array}{c} 1 \times 1 & 2 \times 3 & 3 \times 5 \\ 2 \times 2 & 3 \times 4 & 4 \times 6 \\ \end{array}\right) = \left(\begin{array}{c} 1 & 6 & 15 \\ 4 & 12 & 24 \\ \end{array}\right) $$x * y
array([[ 1., 6., 15.], [ 4., 12., 24.]])
スカラーと行列の和
$$ 1 + \pmb{X} = \left(\begin{array}{c} 1 & 1 & 1 \\ 1 & 1 & 1 \end{array}\right) + \left(\begin{array}{c} 1 & 2 & 3 \\ 2 & 3 & 4 \end{array}\right) = \left(\begin{array}{c} 2 & 3 & 4 \\ 3 & 4 & 5 \\ \end{array}\right) $$1 + x
array([[2., 3., 4.], [3., 4., 5.]])
スカラーと行列の差
$$ 1 - \pmb{X} = \left(\begin{array}{c} 1 & 1 & 1 \\ 1 & 1 & 1 \end{array}\right) - \left(\begin{array}{c} 1 & 2 & 3 \\ 2 & 3 & 4 \end{array}\right) = \left(\begin{array}{c} 0 & -1 & -2 \\ -1 & -2 & -3 \\ \end{array}\right) $$1 - x
array([[ 0., -1., -2.], [-1., -2., -3.]])
行列のスカラー倍
$$ 2\pmb{X} = \left(\begin{array}{c} 2 & 2 & 2 \\ 2 & 2 & 2 \end{array}\right) \odot \left(\begin{array}{c} 1 & 2 & 3 \\ 2 & 3 & 4 \end{array}\right) = \left(\begin{array}{c} 2 \times 1 & 2 \times 2 & 2 \times 3 \\ 2 \times 2 & 2 \times 3 & 2 \times 4 \end{array}\right) = \left(\begin{array}{c} 2 & 4 & 6 \\ 4 & 6 & 8 \\ \end{array}\right) $$2 * x
array([[2., 4., 6.], [4., 6., 8.]])
転置行列
$$ Z = Y^\top = \left(\begin{array}{c} 1 & 3 & 5 \\ 2 & 4 & 6 \\ \end{array}\right)^\top = \left(\begin{array}{c} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{array}\right) $$z = y.T
z
array([[1., 2.], [3., 4.], [5., 6.]])
行列積
\begin{align*} XZ &= \left(\begin{array}{c} 1 & 2 & 3 \\ 2 & 3 & 4 \end{array}\right) \left(\begin{array}{c} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{array}\right) \\ &= \left(\begin{array}{c} 1 \times 1 + 2 \times 3 + 3 \times 5 & 1 \times 2 + 2 \times 4 + 3 \times 6 \\ 2 \times 1 + 3 \times 3 + 4 \times 5 & 2 \times 2 + 3 \times 4 + 4 \times 6 \\ \end{array}\right) \\ &= \left(\begin{array}{c} 22 & 28 \\ 31 & 40 \\ \end{array}\right) \end{align*}np.dot(x, z)
array([[22., 28.], [31., 40.]])
行列積$XZ$は@
演算子で書くこともできる。
x @ z
array([[22., 28.], [31., 40.]])
行列の累乗
$$ X^2 = \left(\begin{array}{c} 1 & 2 & 3 \\ 2 & 3 & 4 \end{array}\right)^2 = \left(\begin{array}{c} 1^2 & 2^2 & 3^2 \\ 2^2 & 3^2 & 4^2 \end{array}\right) = \left(\begin{array}{c} 1 & 4 & 9 \\ 4 & 9 & 16 \end{array}\right) $$x ** 2
array([[ 1., 4., 9.], [ 4., 9., 16.]])
行列の要素数が合わないなどで、演算が実行できないときはエラーとなる。例えば行列積$XY$を計算するには、$X$の列の数と$Y$の行の数が一致する必要がある。
x @ y
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-31-e6c6f87ceb97> in <module> ----> 1 x @ y ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 2 is different from 3)
零行列。
np.zeros((3, 4))
array([[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]])
$X$と同じ形状の零行列。
x = np.array([
[0, 1],
[1, 2],
[2, 3],
])
np.zeros_like(x)
array([[0, 0], [0, 0], [0, 0]])
要素がすべて$1$の行列。
np.ones((3, 4))
array([[1., 1., 1., 1.], [1., 1., 1., 1.], [1., 1., 1., 1.]])
$X$と同じ形状で要素がすべて$1$の行列。
np.ones_like(x)
array([[1, 1], [1, 1], [1, 1]])
任意の値で初期化した行列。
np.full((3, 4), -2.)
array([[-2., -2., -2., -2.], [-2., -2., -2., -2.], [-2., -2., -2., -2.]])
$X$と同じ形状で任意の値で初期化した行列。
np.full_like(x, -2.)
array([[-2, -2], [-2, -2], [-2, -2]])
単位行列(必ず正方行列となる)。
np.identity(4)
array([[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.], [0., 0., 0., 1.]])
対角要素が$1$、それ以外の要素が$0$である行列(正方行列でなくても作成できる)。
np.eye(3, 4)
array([[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.]])
np.eyeでも単位行列を作成できる。
np.eye(4)
array([[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.], [0., 0., 0., 1.]])
ベクトルから形状を変更して行列にする例。
np.arange(12).reshape(3, 4)
array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])
reshapeメソッドにおいて、いずれかの次元の要素数を-1とすると、他の次元の要素数に基づいてその次元の要素数が推定される。
np.arange(12).reshape(2, -1)
array([[ 0, 1, 2, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
$[0, 1)$の範囲の一様分布からランダムに要素をサンプルして作った行列。
np.random.rand(3, 4)
array([[0.41138273, 0.56472476, 0.74019377, 0.21415386], [0.72671417, 0.00608295, 0.73117914, 0.97736548], [0.27531559, 0.69205105, 0.1033887 , 0.94401989]])
標準正規分布(平均$0$、分散$1$の正規分布)からランダムに要素を抽出して作った行列。
np.random.randn(3, 4)
array([[-0.10454056, -0.14676112, -0.12848028, 0.62593397], [-0.82940938, -0.45294596, -0.3850291 , -1.75512478], [ 0.28350437, 0.54926243, -0.66035861, -0.50153151]])
正規分布(以下の例では平均$0.5$、分散$2$の正規分布)からランダムに要素を抽出して作った行列。
np.random.normal(0.5, 2, (3, 4))
array([[ 0.05489919, 0.4101351 , 2.20940252, -1.12757369], [ 0.18863236, 0.20804204, -0.58426747, 1.76459683], [-2.4958973 , 4.89609212, -3.17816385, 1.27884234]])
ベクトルのときに紹介した数学関数は行列でも使える。ただし、必要に応じて演算を行う単位を軸(axis)として指定する。
x = np.array([
[ 1, 12, 9, 4],
[ 8, 2, 3, 7],
[ 11, 5, 6, 10],
])
行列の要素の和。
np.sum(x)
78
行列の最初の次元のベクトル(行ベクトル)の和。
np.sum(x, axis=0)
array([20, 19, 18, 21])
行列の2番目の次元のベクトル(列ベクトル)の和。
np.sum(x, axis=1)
array([26, 20, 32])
行列の要素の積。
np.prod(x)
479001600
行列の最初の次元のベクトル(行ベクトル)の積。
np.prod(x, axis=0)
array([ 88, 120, 162, 280])
行列の2番目の次元のベクトル(列ベクトル)の積。
np.prod(x, axis=1)
array([ 432, 336, 3300])
行列の要素の累積和。
np.cumsum(x)
array([ 1, 13, 22, 26, 34, 36, 39, 46, 57, 62, 68, 78])
行列の最初の次元のベクトル(行ベクトル)の累積和。
np.cumsum(x, axis=0)
array([[ 1, 12, 9, 4], [ 9, 14, 12, 11], [20, 19, 18, 21]])
行列の2番目の次元のベクトル(列ベクトル)の累積和。
np.cumsum(x, axis=1)
array([[ 1, 13, 22, 26], [ 8, 10, 13, 20], [11, 16, 22, 32]])
行列の要素の累積積。
np.cumprod(x)
array([ 1, 12, 108, 432, 3456, 6912, 20736, 145152, 1596672, 7983360, 47900160, 479001600])
行列の最初の次元のベクトル(行ベクトル)の累積積。
np.cumprod(x, axis=0)
array([[ 1, 12, 9, 4], [ 8, 24, 27, 28], [ 88, 120, 162, 280]])
行列の2番目の次元のベクトル(列ベクトル)の累積積。
np.cumprod(x, axis=1)
array([[ 1, 12, 108, 432], [ 8, 16, 48, 336], [ 11, 55, 330, 3300]])
行列の要素の平均。
np.mean(x)
6.5
行列の最初の次元のベクトル(行ベクトル)の平均。
np.mean(x, axis=0)
array([6.66666667, 6.33333333, 6. , 7. ])
行列の2番目の次元のベクトル(列ベクトル)の平均。
np.mean(x, axis=1)
array([6.5, 5. , 8. ])
行列の要素の分散。
np.var(x)
11.916666666666666
行列の最初の次元のベクトル(行ベクトル)の分散。
np.var(x, axis=0)
array([17.55555556, 17.55555556, 6. , 6. ])
行列の2番目の次元のベクトル(列ベクトル)の分散。
np.var(x, axis=1)
array([18.25, 6.5 , 6.5 ])
行列の要素の標準偏差。
np.std(x)
3.452052529534663
行列の最初の次元のベクトル(行ベクトル)の標準偏差。
np.std(x, axis=0)
array([4.18993503, 4.18993503, 2.44948974, 2.44948974])
行列の2番目の次元のベクトル(列ベクトル)の標準偏差。
np.std(x, axis=1)
array([4.27200187, 2.54950976, 2.54950976])
行列の要素の最小値。
np.min(x)
1
行列の最初の次元のベクトル(行ベクトル)を取り出し、各要素の最小値を取り出したベクトル。
np.min(x, axis=0)
array([1, 2, 3, 4])
行列の2番目の次元のベクトル(列ベクトル)を取り出し、各要素の最小値を取り出したベクトル。
np.min(x, axis=1)
array([1, 2, 5])
行列の要素の最大値。
np.max(x)
12
行列の最初の次元のベクトル(行ベクトル)を取り出し、各要素の最大値を取り出したベクトル。
np.max(x, axis=0)
array([11, 12, 9, 10])
行列の2番目の次元のベクトル(列ベクトル)を取り出し、各要素の最大値を取り出したベクトル。
np.max(x, axis=1)
array([12, 8, 11])
行列の最小値に対応するインデックス番号。
np.unravel_index(x.argmin(), x.shape)
(0, 0)
行列の最大値に対応するインデックス番号。
np.unravel_index(x.argmax(), x.shape)
(0, 1)
x = np.array([
[ 0, 1],
[-1, 2],
])
theta = np.array([
[ 0, 90],
[-90, 180],
])
累乗(**
と同じ)。
y = np.power(x, 4)
y
array([[ 0, 1], [ 1, 16]])
平方根。
np.sqrt(y)
array([[0., 1.], [1., 4.]])
$e$に対する指数
y = np.exp(x)
y
array([[1. , 2.71828183], [0.36787944, 7.3890561 ]])
自然対数
np.log(y)
array([[ 0., 1.], [-1., 2.]])
三角関数
np.sin(theta / 360 * 2 * np.pi)
array([[ 0.0000000e+00, 1.0000000e+00], [-1.0000000e+00, 1.2246468e-16]])
np.cos(theta / 360 * 2 * np.pi)
array([[ 1.000000e+00, 6.123234e-17], [ 6.123234e-17, -1.000000e+00]])
np.tan(theta / 360 * 2 * np.pi)
array([[ 0.00000000e+00, 1.63312394e+16], [-1.63312394e+16, -1.22464680e-16]])
その他、要素の切り捨て、切り上げ、四捨五入などもベクトルの場合と同様なので省略する。
x = np.array([
[1, 2],
[2, 3],
[3, 4],
])
x
array([[1, 2], [2, 3], [3, 4]])
y = np.ones((3, 1))
y
array([[1.], [1.], [1.]])
z = np.array([0, 1])
z
array([0, 1])
行列・ベクトルを横に(水平に)連結。
np.hstack((x, y))
array([[1., 2., 1.], [2., 3., 1.], [3., 4., 1.]])
行列・ベクトルを縦に(垂直に)連結。
np.vstack((z, x))
array([[0, 1], [1, 2], [2, 3], [3, 4]])
x = np.array([
[1, 2, 3, 4],
[2, 3, 4, 5],
[3, 4, 5, 6]
])
元の行列・ベクトル(np.ndarray)からスライスで抽出した部分はビュー、すなわち元のオブジェクトへの参照となり、元のオブジェクトとメモリ領域を共有している。以下の例では行列x
から行ベクトルy
をビューとして抽出している。
y = x[2]
y
array([3, 4, 5, 6])
抽出されたビューy
の要素を変更してみる。
y[0] = 0
y
array([0, 4, 5, 6])
元の行列x
の該当する箇所x[2,0]
も変更されている。
x
array([[1, 2, 3, 4], [2, 3, 4, 5], [0, 4, 5, 6]])
ビューy
の全ての要素を変更する。
y[:] = 0
y
array([0, 0, 0, 0])
元の行列x
の行ベクトルx[2]
も変更されている。
x
array([[1, 2, 3, 4], [2, 3, 4, 5], [0, 0, 0, 0]])
なお、ビューy
の全体を変更しようとして以下のコードを実行すると、y
の要素が変更されるのではなく、y
に1
が代入されるだけなので混同しないこと。
y = 1
y
1
当然、元の行列x
の要素にも変化がない。
x
array([[1, 2, 3, 4], [2, 3, 4, 5], [0, 0, 0, 0]])
x
の部分行列をスライスで取り出した場合も挙動は同じ。
y = x[:2,:2]
y
array([[1, 2], [2, 3]])
y[:] = 0
y
array([[0, 0], [0, 0]])
x
全体のビューはviewメソッドで作成することもできる。
y = x.view()
y
array([[0, 0, 3, 4], [0, 0, 4, 5], [0, 0, 0, 0]])
y[:] = 1
y
array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]])
x
array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]])
スカラー(次元数$0$)やベクトル(次元数$1$)、行列(次元数$2$)を一般化したものをテンソルと呼ぶ。以下のコードは3次元のテンソル$\mathsf{X}$を定義している。
x = np.array([
[
[1, 2, 3],
[2, 3, 4]
],
[
[3, 4, 5],
[5, 6, 7]
],
])
行列の次元数(軸の数)は3($\mathsf{X}$は3次元のテンソル)。
x.ndim
3
各次元の要素数を表すタプル。$\mathsf{X}$の1次元目には$2$個、2次元目には$2$個、3次元目には$3$個の要素が格納されている。すなわち、$2 \times 2 \times 3$の行列であることを表している。
x.shape
(2, 2, 3)
$\mathsf{X}$の1次元目で1番目の要素(=行列)を取り出したスライス$\mathsf{X}_{1,:,:}$。
x[1,:,:]
array([[3, 4, 5], [5, 6, 7]])
これは以下のように書くこともできる。
x[1,...]
array([[3, 4, 5], [5, 6, 7]])
$\mathsf{X}$の3次元目で1番目の要素を取り出したスライス$\mathsf{X}_{:,:,1}$。
x[:,:,1]
array([[2, 3], [4, 6]])
これは以下のように書くこともできる。
x[...,1]
array([[2, 3], [4, 6]])
行列からテンソルへの変換。
x = np.array([
[1, 2],
[3, 4],
])
x
array([[1, 2], [3, 4]])
np.expand_dims(x, 0)
array([[[1, 2], [3, 4]]])
np.expand_dims(x, 1)
array([[[1, 2]], [[3, 4]]])
Python早見帳 © Copyright 2020-2022 by 岡崎 直観 (Naoaki Okazaki). この作品はクリエイティブ・コモンズ 表示 - 非営利 - 改変禁止 4.0 国際 ライセンスの下に提供されています。