4.Numpy配列の計算

(1)ユニバーサル関数

Pythonの最大の弱点はループ計算の遅さです。 この弱点を克服するには、Numpy配列を使ってベクトル化演算することです。 このように計算対象をベクトル化して、要素ごとに処理を行い、Numpy配列として返す関数をユニバーサル関数(ufunc)といいます。 ユニバーサル関数の例は次節以降で見ていくことにします。

(2)ブロードキャスト

また、Numpyでは異なるサイズの配列に対して加算、乗算などの以降演算を適用するルールが設けられており、それに基づき配列の変換を行うことをブロードキャストといいます。 ブロードキャストのルールはNumpy Manualに定義されています (https://numpy.org/doc/stable/reference/ufuncs.html Braodcasting)。

ブロードキャストの例1:
>>> a
array([1, 2, 3])
>>> b=5

>>> a+b
array([6, 7, 8])

これは、aが1×3行列、bはスカラーであり配列のサイズが異なります。 そこで、bに次の赤字部分を追加してa+bを計算しています。
\[ \begin{pmatrix} 1 & 2 & 3 \end{pmatrix} + 5 \rightarrow \begin{pmatrix} 1 & 2 & 3 \end{pmatrix} + \begin{pmatrix} 5 & \txc{red}{5} & \txc{red}{5} \end{pmatrix} \]

ブロードキャストの例2:
>>> a
array([1, 2, 3])
>>> c
array([[1., 1., 1.],
       [1., 1., 1.],
       [1., 1., 1.]])

>>> a+c
array([[2., 3., 4.],
       [2., 3., 4.],
       [2., 3., 4.]])

これは、aが1×3行列、cは3×3行列であり配列のサイズが異なります。 そこで、aに次の赤字部分を追加してa+cを計算しています。
\[ \begin{pmatrix} 1 & 2 & 3 \end{pmatrix} + \begin{pmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{pmatrix} \rightarrow \begin{pmatrix} 1 & 2 & 3 \\ \txc{red}{1} & \txc{red}{2} & \txc{red}{3} \\ \txc{red}{1} & \txc{red}{2} & \txc{red}{3} \end{pmatrix} + \begin{pmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{pmatrix} \]

ブロードキャストの例3:
>>> a2
array([[1],
       [2],
       [3]])

>>> a2+c
array([[2., 2., 2.],
       [3., 3., 3.],
       [4., 4., 4.]])

これは、aが3×1行列、cは3×3行列であり配列のサイズが異なります。 そこで、a2に次の赤字部分を追加してa2+cを計算しています。
\[ \begin{pmatrix} 1 \\ 2 \\ 3 \end{pmatrix} + \begin{pmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{pmatrix} \rightarrow \begin{pmatrix} 1 & \txc{red}{1} & \txc{red}{1} \\ 2 & \txc{red}{2} & \txc{red}{2} \\ 3 & \txc{red}{3} & \txc{red}{3} \end{pmatrix} + \begin{pmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{pmatrix} \]

ブロードキャストの例4:
>>> a
array([1, 2, 3])
>>> d
array([[1., 1.],
       [1., 1.],
       [1., 1.]])

>>> a+d
Traceback (most recent call last):
・・・
ValueError: operands could not be broadcast together with shapes (3,2) (3,)

2つの配列は、ブロードキャストのルールに基づく変形ができないため、エラーが帰ります。
\[ \begin{pmatrix} 1 & 2 & 3 \end{pmatrix} + \begin{pmatrix} 1 & 1 \\ 1 & 1 \\ 1 & 1 \end{pmatrix} \rightarrow ? \]

4.1.演算子

(1)主な演算子

意味 演算子 ufnc
算術演算子
加算(足し算) + numpy.add
減算(引き算) - numpy.subtract
乗算(掛け算) * numpy.multiply
除算(割り算) / numpy.divide
整数除算 // numpy.floor_divide
べき乗 ** numpy.power
剰余(余り) % numpy.mod
比較演算子
一致 == numpy.equal
不一致 != numpy.not_equal
小なり < numpy.less
以下 numpy.less_equal
大なり > numpy.greater
以上 numpy.greater_equal
ブール演算子
AND & numpy.bitwise_and
OR | numpy.bitwise_or
XOR ^ numpy.bitwise_xor
NOT ~ numpy.bitwise_not

節はじめに戻る


(2)算術演算の例

>>> a
array([[1, 2, 3],
       [4, 5, 6]])
>>> b
array([[2., 2., 2.],
       [2., 2., 2.]])

#配列同士の足し算
>>> a+b
array([[3., 4., 5.],
       [6., 7., 8.]])

#配列同士の積  → 要素ごとに掛け算を実施(アダマール積)
>>> a*b
array([[ 2.,  4.,  6.],
       [ 8., 10., 12.]])

#配列同士の割り算 → 要素ごとに割り算を実施
>>> a/b
array([[0.5, 1. , 1.5],
       [2. , 2.5, 3. ]])

#行列積を計算する場合 → np.dot(*, *)を使う
>>> np.dot(a,b)	#行列積のルールに次元が合わないのでエラー
Traceback (most recent call last):
 ・・・
ValueError: shapes (2,3) and (2,3) not aligned: 3 (dim 1) != 2 (dim 0)

>>> b2		#行列積のルールに基づき次元を合わせる
array([[2., 2.],
       [2., 2.],
       [2., 2.]])

>>> np.dot(a,b2)
array([[ 6.,  6.],
       [15., 15.]])

#ブロードキャストによる計算
>>> a
array([[1, 2, 3],
       [4, 5, 6]])
>>> c
array([1, 2, 3])

>>> a/c
array([[1. , 1. , 1. ],
       [4. , 2.5, 2. ]])

節はじめに戻る


(3)比較演算の例

>>> a
array([[1, 2, 3],
       [4, 5, 6]])
>>> b
array([[2., 2., 2.],
       [2., 2., 2.]])
>>> c
array([1, 2, 3])

#配列要素の大小比較
>>> a < b
array([[ True, False, False],
       [False, False, False]])

#配列要素の大小比較(ブロードキャスト)
>>> a < c
array([[False, False, False],
       [False, False, False]])

節はじめに戻る


(4)ブール演算の例

>>> a
array([[1, 2, 3],
       [4, 5, 6]])
>>> b
5
>>> c
array([1, 2, 3])

#ブール演算時、比較演算は()で閉じる必要あり
#&条件
>>> (a==c) | (a > b)
array([[ True,  True,  True],
       [False, False,  True]])

#or条件
>>> (a==c) | (a > b)
array([[ True,  True,  True],
       [False, False,  True]])

#比較演算を()で閉じないと...
>>> a > c & a!=b
Traceback (most recent call last):
・・・
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

節はじめに戻る


参考文献