[Python Tips]numpy配列の演算を理解する

numpyは行列演算を行うことができます。今回はnumpy配列を用いた行列演算の基礎を確認しましょう。

配列の要素同士の四則演算を行う

たとえば長さの同じリストaとリストbのそれぞれの要素の和を計算したいとき、純粋なPythonでは以下のように書きます。

a = [0, 1, 2, 3, 4]
b = [5, 6, 7, 8, 9]
val = [x + y for x, y in zip(a, b)]
print(val)
# [5, 7, 9, 11, 13]

これをnumpy配列で書き換えると以下のようになります。

import numpy as np
a = np.array([0, 1, 2, 3, 4])
b = np.array([5, 6, 7, 8, 9])
print(a + b)
# [5, 7, 9, 11, 13]

このように、a+bとするだけでそれぞれの要素に対して演算を行うことができます。
四則演算については同様の記述でそれぞれの要素に対して行うことができます。
(そのため、代数学における行列積をする場合は”*”ではなく”@”を用います)

また、配列同士のサイズが異なる場合、”特殊な場合を除いて”演算ができないためエラーとなります。

a = np.array([0, 1, 2, 3, 4])
c = np.array([5, 6, 7])
print(a + c)
# ValueError: operands could not be broadcast together with shapes (5,) (3,) 

要素数が合わなくても計算できる場合

次のような例の場合、要素数が異なっても演算することが可能です。

a = np.array([0, 1, 2, 3, 4])
d = np.array([2])
print(a * d)
# [0, 2, 4, 6, 8]

aは要素数5の配列、dは要素数1と要素数が一致していません。
これはnumpyのブロードキャストという形状の自動変換機能によるものです。

ブロードキャストは要素数が1である場合に多い方の要素数の数だけ同じ要素が並んだ配列とみなして演算を行う機能です。
結果的に計算は[0, 1, 2, 3, 4] * [2, 2, 2, 2, 2]を行ったのと同じ結果となります。
ブロードキャストの機能はこれだけではありません。

次元数が合わなくても計算できる場合

次のような例の場合、次元数が異なっても演算することが可能です。

a = np.array([0, 1, 2, 3, 4])
e = 2
print(a * e)
# [0, 2, 4, 6, 8]

aは1次元5要素の配列、eは無次元の定数です。ブロードキャスト機能は次元数が足りない場合、次元が合うように次元を増やすことができます。
無次元の定数2をかけても、要素数1の配列[2]をかけても、要素数5の配列[2, 2, 2, 2, 2]をかけても、演算結果は同じになります。

ブロードキャスト機能とは

ブロードキャスト機能が行うことはたった二つだけです。

  1. 同一次元の要素数が合わない場合、一方が要素数1であればもう一方の要素数に合わせる。
  2. 次元が合わない場合、次元が少ない方の配列(定数)のshapeの先頭に1を加える。

1, 2を行いshapeが同じ形になれば計算可能となります。計算結果は同じ形になったときの形状となります。
これを正しく理解すると以下のx, yの配列も演算可能であることが分かります。

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

print(x.shape)
# (2, 1, 2)
print(y.shape)
# (2, 2)

print(x * y)
"""
[[[ 0  5]
  [ 0  7]]
 [[ 8 15]
  [12 21]]]
"""
x.shape y.shape
step 0 (2, 1, 2) (2, 2)
step 1 (2, 1, 2) (1, 2, 2) yに次元を増やして次元数を合わせる。
step 2 (2, 1, 2) (2, 2, 2) 先頭の次元の要素数を合わせる
step 3 (2, 2, 2) (2, 2, 2) 2次元目の要素数を合わせる
shapeがそろったので計算可能。計算結果のshapeは(2, 2, 2)

簡単にすぐ理解できるものでもないですが、行っているのはたった二つのルールに即したことだけです。
これを理解しておくと書くのが面倒だった処理が簡単に実装できてしまうかも?

numpy配列を駆使して複雑な計算も簡単に行いましょう。

ライター:H.I