logo

行列のアダマール積 📂行列代数

行列のアダマール積

定義

二つの行列 A,BMm×nA, B \in M_{m \times n}アダマール積Hadamard product ABA \odot Bを以下のように定義する。

AB=[a11a1nam1amn][b11b1nbm1bmn]:=[a11b11a1nb1nam1bm1amnbmn] A \odot B = \begin{bmatrix} a_{11} & \cdots & a_{1n} \\ \vdots & \ddots & \vdots \\ a_{m1} & \cdots & a_{mn} \end{bmatrix} \odot\begin{bmatrix} b_{11} & \cdots & b_{1n} \\ \vdots & \ddots & \vdots \\ b_{m1} & \cdots & b_{mn} \end{bmatrix} := \begin{bmatrix} a_{11}b_{11} & \cdots & a_{1n}b_{1n} \\ \vdots & \ddots & \vdots \\ a_{m1}b_{m1} & \cdots & a_{mn}b_{mn} \end{bmatrix}

[AB]ij:=[A]ij[B]ij [A \odot B]_{ij} := [A]_{ij} [B]_{ij}

説明

\odotTeX\TeXのコードは\odotだ。

要素毎の積elementwise productともよく呼ばれる。行列の積とは異なり、同じサイズでなければ定義されず、交換法則も成立する。

  • AB=BAA \odot B = B \odot A
  • (AB)C=A(BC)(A \odot B) \odot C = A \odot (B \odot C)
  • A(B+C)=AB+ACA \odot (B + C) = A \odot B + A \odot C
  • k(AB)=(kA)B=A(kB)k(A \odot B) = (kA) \odot B = A \odot (kB)

ベクトルのアダマール積

二つのベクトル x\mathbf{x}yRn\mathbf{y} \in \mathbb{R}^{n} のアダマール積を以下のように定義する。

xy=[x1y1xnyn] \mathbf{x} \odot \mathbf{y} = \begin{bmatrix} x_{1}y_{1} \\ \vdots \\ x_{n}y_{n} \end{bmatrix}

定義自体は行列のアダマール積における n×1n \times 1 行列に対する特別な場合だ。対角行列に対しては、以下の式が成立する。

xy=diag(x)y=diag(y)x \mathbf{x} \odot \mathbf{y} = \diag(\mathbf{x})\mathbf{y} = \diag(\mathbf{y})\mathbf{x}

ベクトルと行列のアダマール積

ベクトル xRn\mathbf{x} \in \mathbb{R}^{n} と行列 Y=[y1yn]\mathbf{Y} = \begin{bmatrix} \vert & & \vert \\ \mathbf{y}_{1} & \cdots & \mathbf{y}_{n} \\ \vert & & \vert \end{bmatrix} の間のアダマール積を以下のように定義する。

xY=[ ⁣ ⁣ ⁣ ⁣xy1xyn ⁣ ⁣ ⁣ ⁣] \mathbf{x} \odot \mathbf{Y} = \begin{bmatrix} \!\!\vert & & \!\!\vert \\ \mathbf{x} \odot \mathbf{y}_{1} & \cdots & \mathbf{x} \odot \mathbf{y}_{n} \\ \!\!\vert & & \!\!\vert \end{bmatrix}

簡単に言えば、行列の各列に対してベクトルとのアダマール積を取ることだ。定義からすぐに下の式を得る。

xY=diag(x)Y \mathbf{x} \odot \mathbf{Y} = \diag(\mathbf{x}) \mathbf{Y}

これらの二つの定義を見れば、ベクトル x\mathbf{x} に対して x\mathbf{x} \odot 自体を x:=diag(x)\mathbf{x} \odot := \diag(\mathbf{x}) の行列として定義することが無理なく理解できる。

プログラミング言語では

このような要素毎pointwiseの演算は、既存の演算記号にドットpoint.を追加する形で実装されている。この表記は非常に直感的で、例えば乗算が*ならば、点毎の乗算は.*だ。

ジュリア

julia> A = [1 2 3; 4 5 6]
2×3 Matrix{Int64}:
 1  2  3
 4  5  6

julia> B = [2 2 2; 2 2 2]
2×3 Matrix{Int64}:
 2  2  2
 2  2  2

julia> A.*B
2×3 Matrix{Int64}:
 2   4   6
 8  10  12

マトラブ

>> A = [1 2 3; 4 5 6]
A =
     1     2     3
     4     5     6

>> B = [2 2 2; 2 2 2]
B =
     2     2     2
     2     2     2

 
>> A.*B
ans =
     2     4     6
     8    10    12

しかし、Pythonの場合はジュリアやマトラブのような科学計算のための言語ではないため、同じようには実装されていない。乗算記号 * は要素毎の乗算を意味し、行列の積は @ で書く。

>>> import numpy
>>> A = np.array([[1, 2, 3], [4, 5, 6]])
>>> B = np.array([[2, 2, 2], [2, 2, 2]])
>>> A*B
array([[ 2,  4,  6],
       [ 8, 10, 12]])
>>> import torch
>>> A = torch.tensor([[1, 2, 3],[4, 5, 6]])
>>> B = torch.tensor([[2, 2, 2],[2, 2, 2]])
>>> A*B
tensor([[ 2,  4,  6],
        [ 8, 10, 12]])