np.matmul() 함수
- Numpy dot 메소드에서
np.dot()
함수를 사용하여 행렬 곱 연산을 했습니다. 그러나 3, 4차원의 배열에서 np.dot()
을 사용하여 연산을 하면 의도치 않은 결과가 도출될 수 있습니다.
- 고차원 배열에서
Numpy
의 np.dot()
와 np.matmul()
메소드를 살펴보고 둘의 차이점에 대해 알아봅시다.
np.dot()와 np.matmul()의 차이
- 2 x 2 x 2 모양을 가진 3차원 두 배열을 생성하고
np.dot()
과 np.matmul()
를 사용하여 연산해보겠습니다.
>>> import numpy as np
>>> A = np.array([
[[3, 1],
[3, 3]],
[[1, 1],
[3, 2]]])
>>> B = np.array([
[[3, 3],
[3, 3]],
[[1, 3],
[2, 1]]])
>>> print(np.dot(A, B))
[[[[12 12]
[ 5 10]]
[[18 18]
[ 9 12]]]
[[[ 6 6]
[ 3 4]]
[[15 15]
[ 7 11]]]]
>>> print(np.matmul(A, B))
[[[12 12]
[18 18]]
[[ 3 4]
[ 7 11]]]
np.dot() 연산 과정
np.dot()
은 각 A의 행 벡터와 B의 열 벡터끼리 모두 내적 연산을 합니다.
np.matmul() 연산 과정
np.matmul()
은 뒤에서 2개의 차원에 해당하는 배열끼리 행렬 곱 연산을 합니다.
브로드캐스팅 스칼라
- 배열과 상수의 연산에서 어떻게 브로드캐스팅이 적용되는지 살펴봅시다.
스칼라
- 스칼라란 단일 차원(0차원)의 값을 의미합니다. 즉, 방향이 없고 오로지 크기만을 가지는 값으로 상수로 표현이 가능합니다.
배열과 상수 사이의 덧셈 연산
3 x 3
배열에 10
을 더하는 코드를 살펴보겠습니다.
>>> import numpy as np
>>> A = [
[1, 1, 1],
[2, 2, 2],
[3, 3, 3]
]
>>> A = np.array(A)
>>> result = A + 10
>>> print(result)
[[11 11 11]
[12 12 12]
[13 13 13]]
- 상수
10
은 A
의 모양에 맞춰 3 x 3
의 모양을 가진 2차원의 배열로 확장됩니다. 그리고 각 요소별로 덧셈 연산을 행합니다. 이는 덧셈 뿐만 아니라 곱셈, 나눗셈, 뺄셈, 그리고 나머지 연산에도 적용됩니다.
브로드캐스팅 - 같은 차원의 다른 모양
- 같은 차원이지만 다른 모양을 가진 배열 간의 연산에서 어떻게 브로드캐스팅이 적용되는지 살펴봅시다.
같은 차원의 다른 모양을 가진 2차원 배열(행렬)의 경우
- 2차원 배열(행렬) 간의 덧셈 연산을 해봅시다. 예시로
3 x 3
배열(A)과 1 x 3
배열(B) 사이에 덧셈 연산, 그리고 3 x 3
배열(A)과 2 x 3
배열(C) 사이에 덧셈 연산을 행하는 코드를 살펴보겠습니다.
>>> import numpy as np
>>> A = [
[10, 10, 10],
[20, 20, 20],
[30, 30, 30]
]
>>> B = [
[1, 2, 3]
]
>>> C = [
[2, 2, 3],
[4, 5, 6],
]
>>> A = np.array(A)
>>> B = np.array(B)
>>> C = np.array(C)
>>> result = A + B
>>> print(result)
[[11 12 13]
[21 22 23]
[31 32 33]]
>>> result = A + C
ValueError: operands could not be broadcast together with shapes (3,3) (2,3)
1 x 3
배열 B는 3 x 3 배열 A 모양의 맞춰 0차원을 기준으로 확장(1->3)하여 연산합니다.
- 그러나
2 x 3
배열 C는 3 x 3
배열 A 모양에 맞추지 못한다고 에러가 발생합니다. 이는 브로드캐스팅이 차원의 크기가 1일 때만 적용이 되기 때문입니다. 따라서 B는 0차원의 크기가 1이여서 브로드캐스팅이 적용되지만, C는 0차원의 크기가 2이므로 브로드캐스팅이 적용되지 않습니다.
브로드캐스팅 - 다른 차원의 배열
- 차원이 다른 배열들 간의 연산을 할 때 브로드캐스팅이 어떻게 적용되는지 살펴봅시다.
차원이 다른 배열 간의 연산
- 다른 차원의 배열들 간의 연산을 해봅시다. 예시로
2 x 1 x 3
모양을 가진 3차원 배열(A)과 2 x 3
모양을 가진 2차원 배열(B) 사이에 덧셈 연산, 그리고 배열(A)과 1 x 2
모양을 가진 2차원의 배열(C) 사이에 덧셈 연산을 하는 코드를 살펴보겠습니다.
>>> import numpy as np
>>> A = np.array(
[[[3, 2, 1]],
[[0, 1, 3]]]
)
>>> B = np.array(
[[0, 2, 1],
[2, 2, 3]]
)
>>> C = np.array([[1, 2]])
>>> result = A + B
>>> print(result)
[[[3 4 2]
[5 4 4]]
[[0 3 4]
[2 3 6]]]
>>> result = A + C
ValueError: operands could not be broadcast together with shapes (2,1,3) (1,2)
2 x 3
모양을 가진 2차원 배열 B는 0차원의 크기가 2, 1차원의 크기가 3입니다. 그러나 2 x 1 x 3
모양을 가진 3차원의 배열 A에 맞춰 3차원으로 확장되면 0차원에는 배열 A의 0차원 크기인 2가 되고, 1차원에는 기존 배열의 0차원 크기(2)가, 2차원에는 기존 배열의 1차원 크기(3)가 됩니다.
- 실습에서 확인했던 것처럼 배열 A의 1차원의 크기가 1이므로 배열 B의 1차원의 크기에 맞춰 2로 확장됩니다.
- 그러나 A + C의 경우 브로드캐스팅이 적용되지 않는다고 에러가 발생합니다. 이는 브로드캐스팅이 적용될 때 마지막 차원부터 맞춰지기 때문입니다. 즉, 배열 A의 2차원의 크기인 3과 C의 1차원의 크기인 2가 맞지 않아 발생한 것입니다.
브로드캐스팅 정리
- 브로드캐스팅 적용 조건에 대해서 정리해봅시다.
브로드캐스팅 적용 조건
- 같은 레벨의 차원끼리 비교했을때 크기가 다르더라도 차원의 크기가 1이면 브로드캐스팅이 가능하다.
- 차원의 레벨이 다르더라도 뒤에서부터 비교하여 크기가 같거나 차원의 크기가 1이면 브로드캐스팅이 가능하다.
- 위 두가지 조건을 벗어난 배열 간의 연산에서는 브로드캐스팅을 할 수 없습니다.
any(), all()
- 배열을 검사해주는 any()와 all()메소드에 대해 살펴봅시다.
any() 메소드
any()
메소드는 주어진 배열에 True
가 하나라도 있으면 True
를 반환하고, True
가 하나도 없다면 False
를 반환합니다. 예시로 배열에 4 이상의 수가 있는지 검사하는 코드를 살펴봅시다.
>>> import numpy as np
>>> A = np.array([1, 2, 3, 4, 5, 4, 3, 2, 1])
>>> print(A >= 4)
[False False False True True True False False False]
>>> print((A >= 4).any())
True
all() 메소드
all()
메소드는 주어진 배열의 모든 요소가 True
라면 True
를 반환하고, 하나라도 False
가 있다면 False
를 반환합니다. 위에서 살펴본 코드에 any()
대신 all()
을 넣어보겠습니다.
>>> import numpy as np
>>> A = np.array([1, 2, 3, 4, 5, 4, 3, 2, 1])
>>> print(A >= 4)
[False False False True True True False False False]
>>> print((A >= 4).all())
False
np.matmul() 연산과정 결과에서 2번째 행의 결과가
a111b111 + a112b121 a111b112 + a112b122 인데
a121b111 + a121b121 a121b112 + a122b122 를 잘 못 쓰신건가요?