나보다 돈 많이 벌고 잘 사는 사람이 예쁘게 잘 만든 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

+ Recent posts