はじめに¶
様々なアルゴリズムを実装する際に漸化式は出るけど実装時にうまくいかない。ということは良くあります。また、Python
を使って実装する場合、そのほとんどが行列の取り扱いです。(柔軟であるが故にエラーを吐かずに動いてしまう…笑)
そこで、まずは行列計算のチートシートを作成します。(随時加筆修正していきます。)
In [1]:
import numpy as np
基本事項
In [2]:
N = 3
A = np.arange(N)
B = np.arange(N).reshape(-1,N) # np.expand_dims(A, axis=0), A[None,:]
C = np.arange(N).reshape(N,-1) # np.expand_dims(A, axis=1), A[:,None]
D = np.arange(N*N).reshape(N,N)
In [3]:
print(f"A = {A}")
print(f"B = {B}")
print(f"C = {C}")
print(f"D = {D}")
In [4]:
print(f"A.shape = {A.shape}")
print(f"B.shape = {B.shape}")
print(f"C.shape = {C.shape}")
print(f"D.shape = {D.shape}")
In [5]:
print(f"A.ndim = {A.ndim}")
print(f"B.ndim = {B.ndim}")
print(f"C.ndim = {C.ndim}")
print(f"D.ndim = {D.ndim}")
ndim |
ex. | |
---|---|---|
scalar | $(0)$ | 1 ,2 ,... |
vector | $1$ | A |
matrix | $\geq2$ | B ,C ,D |
内積(行列積)
vector & scalar / matrix & scalar¶
- スカラーが絡むと、各要素とスカラーの積となる。
shape
の変化はない。- どちらから掛けてもエラーは起こらない。
In [6]:
print(f"np.dot(A,2) = {np.dot(A,2)}") # vector & scalar
print(f"np.dot(B,2) = {np.dot(B,2)}") # matrix & scalar
print(f"np.dot(C,2) = {np.dot(C,2)}") # matrix & scalar
print(f"np.dot(D,2) = {np.dot(D,2)}") # matrix & scalar
vector & vector¶
- 内積となる。
- 結果はスカラーとなる。
shape
が異なると、エラーが起きる。
In [7]:
print(f"np.dot(A,A) = {np.dot(A,A)}") # vector & vector
In [8]:
np.dot(A, np.arange(N-1)) # shape=(3,) & shape=(2,)
vector & matrix¶
- 行列積となる。
- ベクトルは、位置によって変換のされ方が異なる。
- 左がベクトルの場合:
np.dot((x,) (y,z)) = np.dot((1,x) (y,z))
- 右がベクトルの場合:
np.dot((y,z) (x,)) = np.dot((y,z) (x,1))
- 左がベクトルの場合:
- 行列積であるので、結果の
shape
はnp.dot((x,y) (y,z)) = (x,z)
となる。 - 上で
y
が異なるとエラーが生じる。
In [9]:
print(np.dot(A,B)) # np.dot((3,)(1,3))
print(np.dot(A,C)) # np.dot((3,)(3,1))
print(np.dot(B,A)) # np.dot((1,3)(3,))
print(np.dot(C,A)) # np.dot((3,1)(3,))
matrix & matrix¶
c = np.dot(a,b)
a.shape=(a1,a2,...,aN,X)
b.shape=(b1,b2,...,X,bM)
c.shape=(a1,a2,...,aN,b1,b2,...,bM)
c[i1,i2,...,iN,j1,j2,...,jM] == a[i1,i2,...,iM,:].dot(b[j1,j2,...,jM-1,:,jM])
In [10]:
import itertools
def checkNPdot(shape1, shape2):
""" 計算可能なshapeの関係を列挙する。 """
a = np.arange(np.prod(shape1))
b = np.arange(np.prod(shape2))
for comb1 in itertools.permutations(shape1, len(shape1)):
for comb2 in itertools.permutations(shape2, len(shape2)):
try:
print(f"{comb1}.dot({comb2}) = {(a.reshape(comb1).dot(b.reshape(comb2))).shape}")
except:
pass
以下で具体的に見ていく!
np.dot(2D, 3D)
¶
c = np.dot(a,b)
a.shape=(i,X)
b.shape=(j,X,k)
c.shape=(i,j,k)
c[i,j,k] == a[i,:].dot(b[j,:,k])
In [11]:
a = np.arange(6).reshape(2,3)
b = np.arange(24).reshape(2,3,4)
c = np.dot(a,b)
In [12]:
print(f"a.shape = {a.shape}")
print(f"b.shape = {b.shape}")
print(f"np.dot(a,b).shape = {c.shape}")
In [13]:
I,J,K = c.shape
In [14]:
np.all([c[i,j,k]==a[i,:].dot(b[j,:,k]) for i in range(I) for j in range(J) for k in range(K)])
Out[14]:
np.dot(3D,2D)
¶
c = np.dot(a,b)
a.shape=(i,j,X)
b.shape=(X,k)
c.shape=(i,j,k)
c[i,j,k] == a[i,j,:].dot(b[:,k])
In [15]:
a = np.arange(24).reshape(4,2,3)
b = np.arange(6).reshape(3,2)
c = np.dot(a,b)
In [16]:
print(f"a.shape = {a.shape}")
print(f"b.shape = {b.shape}")
print(f"np.dot(a,b).shape = {c.shape}")
In [17]:
I,J,K = c.shape
In [18]:
np.all([c[i,j,k] == a[i,j,:].dot(b[:,k]) for i in range(I) for j in range(J) for k in range(K)])
Out[18]:
np.dot(3D,3D)
¶
c = np.dot(a,b)
a.shape=(i,j,X)
b.shape=(k,X,l)
c.shape=(i,j,k,l)
c[i,j,k,l] == a[i,j,:].dot(b[k,:,l])
In [19]:
a = np.arange(24).reshape(2,3,4)
b = np.arange(60).reshape(3,4,5)
c = np.dot(a,b)
In [20]:
print(f"a.shape = {a.shape}")
print(f"b.shape = {b.shape}")
print(f"np.dot(a,b).shape = {c.shape}")
In [21]:
I,J,K,L = c.shape
In [22]:
np.all([c[i,j,k,l] == a[i,j,:].dot(b[k,:,l]) for i in range(I) for j in range(J) for k in range(K) for l in range(L)])
Out[22]:
np.dot(2D,4D)
¶
c = np.dot(a,b)
a.shape=(i,X)
b.shape=(j,k,X,l)
c.shape=(i,j,k,l)
c[i,j,k,l] == a[i,:].dot(b[j,k,:,l])
In [23]:
a = np.arange(6).reshape(2,3)
b = np.arange(120).reshape(2,4,3,5)
c = np.dot(a,b)
In [24]:
print(f"a.shape = {a.shape}")
print(f"b.shape = {b.shape}")
print(f"np.dot(a,b).shape = {c.shape}") # c[i,j,k,l] == a[i,j,:].dot(b[k,:,l])
In [25]:
I,J,K,L = c.shape
In [26]:
np.all([c[i,j,k,l] == a[i,:].dot(b[j,k,:,l]) for i in range(I) for j in range(J) for k in range(K) for l in range(L)])
Out[26]:
np.dot(3D,4D)
¶
c = np.dot(a,b)
a.shape=(i,j,X)
b.shape=(k,l,X,m)
c.shape=(i,j,k,l,m)
c[i,j,k,l,m] == a[i,j,:].dot(b[k,l,:,m])
In [27]:
a = np.arange(24).reshape(2,3,4)
b = np.arange(360).reshape(3,5,4,6)
c = np.dot(a,b)
In [28]:
print(f"a.shape = {a.shape}")
print(f"b.shape = {b.shape}")
print(f"np.dot(a,b).shape = {c.shape}")
In [29]:
I,J,K,L,M = c.shape
In [30]:
np.all([c[i,j,k,l,m] == a[i,j,:].dot(b[k,l,:,m]) for i in range(I) for j in range(J) for k in range(K) for l in range(L) for m in range(M)])
Out[30]:
np.dot(4D,4D)
¶
c = np.dot(a,b)
a.shape=(i,j,k,X)
b.shape=(l,m,X,n)
c.shape=(i,j,k,l,m,n)
c[i,j,k,l,m,n] == a[i,j,k,:].dot(b[l,m,:,n])
In [31]:
a = np.arange(120).reshape(2,3,4,5)
b = np.arange(360).reshape(3,4,5,6)
c = np.dot(a,b)
In [32]:
print(f"a.shape = {a.shape}")
print(f"b.shape = {b.shape}")
print(f"np.dot(a,b).shape = {c.shape}")
In [33]:
I,J,K,L,M,N = c.shape
In [34]:
np.all([c[i,j,k,l,m,n] == a[i,j,k,:].dot(b[l,m,:,n]) for i in range(I) for j in range(J) for k in range(K) for l in range(L) for m in range(M) for n in range(N)])
Out[34]:
外積
c = np.outer(a,b)
c[i][j] = a.reshape(-1,)[i]*b.reshape(-1,)[j]
In [35]:
c = np.outer(a,b)
In [36]:
print(f"a.shape = {a.shape}")
print(f"b.shape = {b.shape}")
In [37]:
Na = np.prod(a.shape)
Nb = np.prod(b.shape)
In [38]:
print(f"Na = {Na}")
print(f"Nb = {Nb}")
In [39]:
print(c.shape)
In [40]:
np.all([c[i][j] == a.reshape(-1,)[i]*b.reshape(-1,)[j] for i in range(Na) for j in range(Nb)])
Out[40]:
In [ ]: