『Python数値計算ノート』ではアフィリエイトプログラムを利用して商品を紹介しています。

アダマール積

アダマール積(シューア積)

同じサイズの行列 $A,\ B$ に対して、成分ごとの積をとる演算をアダマール積(Hadamard product)またはシューア積(Schur product)とよび、$A\circ B$ で表します。名称はフランスの数学者ジャック・サロモン・アダマール(Jacques Salomon Hadamard)、ドイツ・イスラエルの数学者イサイ・シューア(Issai Schur)らに由来します。
 
たとえば、3×3サイズの行列同士のアダマール積は次のように表されます。
 \[\begin{bmatrix}a_{11}&a_{12} &a_{13}\\a_{21}&a_{22}&a_{23}\\a_{31}&a_{32}&a_{33}\end{bmatrix}\begin{bmatrix}b_{11}&b_{12}&b_{13}\\b_{21}&b_{22}&b_{23}\\b_{31}&b_{32}&b_{33}\end{bmatrix}=\begin{bmatrix}a_{11}b_{11}&a_{12}b_{12}&a_{13}b_{13}\\a_{21}b_{21}&a_{22}b_{22}&a_{23}b_{23}\\a_{31}b_{31}&a_{32}b_{32}&a_{33}b_{33}\end{bmatrix}\tag{1}\]
ほぼ自明のことですが、アダマール積は交換則と分配則
 \[\begin{align*}&A\circ B=B\circ A\tag{2}\\[6pt]&A\circ (B\circ C)=(A\circ B)\circ C\tag{3}\\[6pt]&A\circ (B+C)=A\circ B+A\circ C\tag{4}\end{align*}\]
を満たす演算です。

【NumPy】アダマール積

NumPy の配列に対して * 演算子を適用すると、成分ごとの積、すなわちアダマール積を計算します(行列積ではありません)。3×3サイズの配列を用意して、配列積 (アダマール積) を計算させてみましょう。

# NumPy_Hadamard_product

# In[1]

import numpy as np

a = np.array([[3, 1, 7],
              [0, 2, 5],
              [9, 4, 3]])

b = np.array([[2, 2, 6],
              [9, 6, 2],
              [8, 1, 4]])

# aとbのアダマール積
print(a*b)

# [[ 6  2 42]
#  [ 0 12 10]
#  [72  4 12]]

アダマール積を使うと、$a_{ij}b_{ij}$ の総和
 \[a_{11}b_{11}+a_{12}b_{12}+\ \cdots+\ a_{nn}b_{nn}\]
を簡潔なコードで実装できます。すなわち行列 $a_{ij}$ と $b_{ij}$ を用意しておいて、アダマール積をとってから、numpy.sum() ですべての成分の和をとります。たとえば、In[1] で定義した行列 a, b の成分ごとの積の和は以下のように計算できます。

# In[2]

# 行列 a, b の成分ごとの積の和
s = np.sum(a*b)

print(s)
# 160

これは機械学習などでも用いられる実践的な手法です。

sympy.matrix_multiply_elementwise()

SymPy では * 演算子は行列積を実行します。
アダマール積は matrix_multiply_elementwise() を使って計算します。

# SymPy_Hadamard_product

# In[1]

from sympy import Symbol, var, init_printing
from sympy.matrices import Matrix
from sympy.matrices import matrix_multiply_elementwise

init_printing()

# 一般表記の行列生成関数
def general_matrix(m, n, s):
    Symbol(s)
    elements = lambda i,j : var('{}{}{}'.format(s, i+1, j+1))
    return Matrix(m, n, elements)

a = general_matrix(3, 3, "a")
b = general_matrix(3, 3, "b")

# aとbのアダマール積を計算
aob = matrix_multiply_elementwise(a, b)

# a,b,aobを表示
display(a, b, aob)
\begin{align*}
&\left[\begin{matrix}a_{11} & a_{12} & a_{13}\\a_{21} & a_{22} &a_{23}\\a_{31} & a_{32} & a_{33}\end{matrix}\right]\\[6pt]&\left[\begin{matrix}b_{11} & b_{12} & b_{13}\\b_{21} & b_{22} &b_{23}\\b_{31} & b_{32} & b_{33}\end{matrix}\right]\\[6pt]&\left[\begin{matrix}a_{11} b_{11} & a_{12} b_{12} & a_{13} b_{13}\\a_{21} b_{21} & a_{22} b_{22} & a_{23} b_{23}\\a_{31} b_{31} & a_{32} b_{32} & a_{33} b_{33}\end{matrix}\right]\end{align*}

コメント