-
6. Element-wise Operations and Broadcasting공부/likelion 2021. 10. 1. 20:23
Index
1. 벡터끼리 사칙연산, 논리연산, 내장연산
2. 요소별 곱셉을 이용한 마스킹
3. 브로드캐스팅
- 차원이 같은 경우
- 차원이 다른 경우
4. 결론
1. 벡터끼리 사칙연산, 논리연산, 내장연산
#1차원 랜덤 백터를 생성 후 사칙연산 a = np.random.randint(1, 5, (5, )) b = np.random.randint(1, 5, (5, )) print(a) print(b) print("a + b: ", a + b) print("a - b: ", a - b) print("a * b: ", a * b) print("a / b: ", a / b) print("a // b: ", a // b) print("a % b: ", a % b) print("a ** b: ", a ** b)
일반적으로 동일한 차원인 경우, 일반적인 연산이 잘된다.
# 1차원 벡터끼리 논리연산 a = np.random.randint(1, 5, (5, )) b = np.random.randint(1, 5, (5, )) print(a) print(b) print("a > b: ", a > b) print("a >= b: ", a >= b) print("a < b: ", a < b) print("a <= b: ", a <= b) print("a == b: ", a == b) print("a != b: ", a != b)
#1차원 벡터끼리 내장 연산 a = np.random.randint(1, 5, (5, )) b = np.random.randint(1, 5, (5, )) print(a) print(b) print("a + b: ", a.__add__(b)) print("a - b: ", a.__sub__(b)) print("a * b: ", a.__mul__(b)) print("a / b: ", a.__truediv__(b)) print("a // b: ", a.__floordiv__(b)) print("a % b: ", a.__mod__(b)) print("a ** b: ", a.__pow__(b))
2차원 벡터끼리 사칙연산도 잘 될까?
#2차원 벡터끼리 사칙 연산하기 M = np.random.randint(1, 5, (2, 3)) N = np.random.randint(1, 5, (2, 3)) print(M,end='\n\n') print(N,end='\n\n') print("M + N: \n", M + N,end='\n\n') print("M - N: \n", M - N,end='\n\n') print("M > N: \n", M > N,end='\n\n') print("M >= N: \n", M >= N,end='\n\n')
2차원 벡터끼리도 사칙 연산이 잘되는 것을 알 수 있다.
2. 요소별 곱셉을 이용한 마스킹
#요소별 곱셉을 이용한 마스킹 a = np.arange(5) mask = np.array([0, 1, 0, 1, 0]) print("input: ", a) print("mask: ", mask) print("output: ", a*b)
동일 차원에 대해서 곱셈이 잘 되기 때문에 이를 응용해서
특정 값만 벡터에 남기는, '마스킹'이라는 테크닉도 가능하다.3. 브로드캐스팅
- 차원이 같은 경우broadcasting이라는 의미는 방송하다- 이런 의미보다는, 차원을 전파하다, 흩뿌린다는 의미이다.
#Broadcasting case = 차원을 흩뿌리다 #case 1. 두 배열의 차원의 축 수(ndarray.ndim)가 서로 같은 경우 #2차원과 1차원 벡터 A = np.arange(9).reshape(3, 3) B = 10*np.arange(3).reshape((-1, 3)) C = A + B print("A: {}/{}\n{}".format(A.ndim, A.shape, A), end = '\n\n') print("B: {}/{}\n{}\n".format(A.ndim, B.shape, B)) print("A + B: {}/{}\n{}".format(A.ndim, C.shape, C))
1차원의 경우 다른 차원의 크기와 상관없이 자동적으로 브로드캐스팅이 되는 것을 볼 수 있다.
A = np.arange(9).reshape(3, 3) B = 10*np.arange(3).reshape((3, -1)) C = A + B print("A: {}/{}\n{}".format(A.ndim, A.shape, A), end = '\n\n') print("B: {}/{}\n{}\n".format(A.ndim, B.shape, B)) print("A + B: {}/{}\n{}".format(A.ndim, C.shape, C))
축이 달라도 마찬가지. 그렇다면 과연 3차원일때는 어떻게 작동할까?
#3차원일 경우 #부족한 차원에 대하여 기존의 값들이 복사되어 더해진다. A = np.arange(18).reshape((2, 3, 3)) B = 10*np.arange(9).reshape((1, 3, 3)) C = A + B print("A: {}/{}\n{}".format(A.ndim, A.shape, A), end = '\n\n') print("B: {}/{}\n{}\n".format(A.ndim, B.shape, B)) print("A + B: {}/{}\n{}".format(A.ndim, C.shape, C))
부족한 차원(z)이 자동적으로 다른 객체의 해당 차원 값과 동일하게 계산되어 더해진다.
#이런 경우에는 가장 적은 차원, y축을 기준으로 값이 복사되어 더해진다. #기준이 되는 객체의 차원이 다른 객체의 차원의 약수여야만 더해지는듯하다 A = np.arange(18).reshape((2, 3, 3)) B = 10*np.arange(6).reshape((2, 1, 3)) C = A + B print("A: {}/{}\n{}".format(A.ndim, A.shape, A), end = '\n\n') print("B: {}/{}\n{}\n".format(A.ndim, B.shape, B)) print("A + B: {}/{}\n{}".format(A.ndim, C.shape, C))
low축(y)인 경우에도 마찬가지이다.
A = np.arange(18).reshape((2, 3, 3)) B = 10*np.arange(6).reshape((2, 3, 1)) C = A + B print("A: {}/{}\n{}".format(A.ndim, A.shape, A), end = '\n\n') print("B: {}/{}\n{}\n".format(A.ndim, B.shape, B)) print("A + B: {}/{}\n{}".format(A.ndim, C.shape, C))
x축, column의 경우에도 잘 더해지는 것을 볼 수 있다.
- 차원이 다른 경우
위의 경우는 (2,2,3), (2,1,3)처럼 차원의 전체 수는 같지만 내부 값이 다른 경우였다면,
이번에는 차원 자체의 수가 아에 다른 경우를 살펴보자.#ndim = 차원의 축 수 #그 둘이 서로 같지 않은 경우 a = np.array(3) #스칼라 u = np.arange(5) #벡터 print("shapes: {}/{}".format(a.shape, u.shape)) print("a: ", a) print("u: ", u, '\n') print("a*u: ", a*u)
스칼라와 벡터의 경우, 자동으로 브로드캐스팅이 되기 때문에 잘 작동한다. 그렇다면 다른 연산들은 어떨까?
#축이 같지 않은 경우에도 연산이 통할까? a = np.array(3) #스칼라 u = np.arange(1,5) #벡터 shapes = "shapes: {}/{}" print(shapes.format(a.shape, u.shape)) print("a + u: ", a + u) print("a - u: ", a - u) print("a * u: ", a * u) print("a / u: ", a / u) print("a // u: ", a // u) print("a % u: ", a % u) print("a ** u: ", a ** u,'\n\n') #논리연산 print('논리연산') print("a > u: ", a > u) print("a >= u: ", a >= u) print("a < u: ", a < u) print("a <= u: ", a <= u) print("a == u: ", a == u) print("a != u: ", a != u)
잘되는 것을 볼 수 있다. 스칼라와 벡터끼리 연산을 할 경우,
벡터 전체가 아닌 요소와 스칼라를 계산하는 것을 잊지 말자.#차원의 축 수가 같지 않은 벡터끼리 연산의 경우 #브로드캐스팅은 각 배열의 차원의 축 중 같은 값을 기준으로, 다른 축에 대하여 값을 복사하여 더한다. #(2,)와 (3,2)의 경우, 각 배열의 차원 값 중 값이 2로 같으므로, 다른 차원이 가지고 있는 값을 가져와 차원을 복사하여 더하는 듯하다. A = np.array([10, 20]) B = np.arange(6).reshape((3, 2)) C = A + B print("A: {}/{}\n{}".format(A.ndim, A.shape, A), end = '\n\n') print("B: {}/{}\n{}\n".format(A.ndim, B.shape, B)) print("A + B: {}/{}\n{}".format(A.ndim, C.shape, C))
(2, ) 의 경우, 자동적으로 (1,2)과 동일하게 연산되어 다른 배열의 차원 값인 (3,2)으로 브로드캐스팅 되었다.
즉, 기본적으로 축을 지정하지 않으면 x,y,z 순으로 들어간다고 볼 수 있겠다.
#3차원일 경우도 마찬가지. 3*4가 같으므로, 값이 2인 차원에 대해서 맞춘다 A = np.arange(2*3*4).reshape((2, 3, 4)) B = 10*np.arange(3*4).reshape((3, 4)) C = A + B print("A: {}/{}\n{}".format(A.ndim, A.shape, A), end = '\n\n') print("B: {}/{}\n{}\n".format(A.ndim, B.shape, B)) print("A + B: {}/{}\n{}".format(A.ndim, C.shape, C))
A에 비해 B는 z 축 차원이 없으므로, 배열 값을 복사하여 브로드캐스팅한다. 그렇다면 1차원과 3차원처럼 2차원 이상 차이가 나면 어떻게 될까?
#3차원과 1차원 벡터의 경우도 동일 A = np.arange(2*3*4).reshape((2, 3, 4)) B = 10*np.arange(4) C = A + B print("A: {}/{}\n{}".format(A.ndim, A.shape, A), end = '\n\n') print("B: {}/{}\n{}\n".format(A.ndim, B.shape, B)) print("A + B: {}/{}\n{}".format(A.ndim, C.shape, C))
이런 경우 먼저 y축에 대하여 브로드캐스팅한다음, z축으로 브로드캐스팅을 한번 더 거쳤다고 생각하면 이해하기 쉬울듯하다.
4. 결론
브로드캐스팅(Broadcasting)은 모양이 다른 배열들 간의 연산이 어떤 조건을 만족했을 때 가능해지도록 배열을 자동적으로 변환하는 것이라고 정의할 수 있다.
브로드캐스팅은, 2가지의 조건을 가지고 있다고 볼 수 있다.
- 차원의 크기가 1일때 가능하다
두 배열 간의 연산에서 최소한 하나의 배열의 차원이 1일 때 가능하다. - 차원의 짝이 맞을 때 가능하다
배열이 다른 배열에 대하여 특정 차원 축의 길이가 동일하면 브로드캐스팅이 가능하다.
레퍼런스
[1]
Broadcast Visualization — astroML 0.4 documentation
Broadcast Visualization Figure A.1 A visualization of NumPy array broadcasting. Note that the extra memory indicated by the dotted boxes is never allocated, but it can be convenient to think about the operations as if it is. # Author: Jake VanderPlas # Lic
www.astroml.org
'공부 > likelion' 카테고리의 다른 글
중간과제2. 코사인 유사도를 이용한 색상 추출의 타당성(실습) (0) 2021.10.03 중간 과제2 : 코사인 유사도를 이용한 색상 추출의 타당성(개념) (0) 2021.10.03 5. Changing ndarrays (0) 2021.09.30 4. Meta-data of ndarrays (0) 2021.09.29 3. making ndarray (0) 2021.09.28 - 차원의 크기가 1일때 가능하다