나보다 돈 많이 벌고 잘 사는 사람이 예쁘게 잘 만든 numpy 모듈을 굳이 굳이 for문으로 만들어 보자.
numpy를 for문으로 구현하기 위해서는 디지털 논리회로로 생각하면 쉽다.
예를 들어 행렬이 아래와 같이 있고, 행렬곱을 한다고 하면 다음과 같다.
1 2 2 3 (1*2 + 2*1) (1*3 + 2*4)
3 4 1 4 (3*2 + 4*1) (3*3 + 4*4)
위의 행렬곱을 요소로 생각하면 다음과 같다.
00 01 00 01 (00*00+01*10) (00*01+01*11)
10 11 10 11 (10*00+11*10) (10*01+11*11)
요소를 활용해 행렬곱을 나타낸 식을 세로로 세우면 다음과 같다.
a[0] a[1] b[0] b[1] 실제 위치
[0] [1] [2] [3]
00*00 0 0 0 0
+ 01*10 0 1 1 0
------------------------
00*01 0 0 0 1
+ 01*11 0 1 1 1
------------------------
10*00 1 0 0 0
+ 11*10 1 1 1 0
------------------------
10*01 1 0 0 1
+ 11*11 1 1 1 1
[0]은 00001111
[1][2]는 01010101
[3]은 00110011 로 위치가 변한다.
따라서 for문을 3개 중첩할 때
for i :
for j :
for k :
[0]에는 [i]를 / [1][2]에는 [k]를 / [3]에는 [j]를 넣으면 된다.
a[0][1] * b[2][3]
a[ i][k] * b[k][ j]
곱행렬을 넣을 행렬을 선언하기 위해서 알아야 하는 기본적인 개념은
행렬 (2*4) 와 (4*2) 의 행렬 곱은 (2*2) 가 나온다는 것이다.
즉, 첫번째 행렬의 행과 두번째 행렬의 열로 행렬이 구성된다.
행렬 (i*j) 와 (n*m) 의 행렬 곱은 (i*m) 로 나온다.
따라서 np_dot이라는 빈 array, 혹은 list를 구현할 때 a[0]의 크기와 b[1]의 크기로 np_dot을 생성한다.
# 행렬곱만 list로 구현
import numpy as np
def np_dot(a,b) : # 행렬곱함수
np_dot= np.zeros((a.shape[0],b.shape[-1])) # np_dot이라는 곱행렬을 담을 빈 행렬 만듦
for i in range(len(a)) :
for j in range(a.shape[0]) : # 행렬의 shape은 (n,n)임을 참고
for k in range(a.shape[1]) :
np_dot[i][j] += a[i][k]*b[k][j] # 디지털 논리회로 참고
return np_dot
print(np_dot(a,b))
# ------------------------------------------------------------------------------------------------
# list로 행렬곱 구하기
def np_dot(a,b) :
a_shape = [len(a),len(a[0])]
b_shape = [len(b),len(b[0])]
# np_dot 생성
np_dot = []
for i in range(a_shape[0]) :
np_dot.append([0]*b_shape[-1])
# 행렬곱 수행
for i in range(len(a)) :
for j in range(a_shape[0]) :
for k in range(a_shape[1]) :
np_dot[i][j] += a[i][k]*b[k][j]
return np_dot
# 세로 출력
for i in np_dot(a,b) :
print(i)
# 가로 출력
print(np_dot(a,b))
'코딩 > 문제' 카테고리의 다른 글
문제6. (파이썬) 합병정렬 (0) | 2020.06.05 |
---|---|
문제5. (파이썬) 삽입정렬 (0) | 2020.06.04 |
문제4. (파이썬) 버블정렬 (0) | 2020.06.03 |
문제3. (파이썬) 이진탐색 (0) | 2020.06.02 |
문제2. (파이썬) matrix_convolution 구현 (0) | 2020.06.01 |