머신러닝/Numpy

[Numpy] #5 요소별 연산, 브로드캐스팅(Broadcasting) ndarray 가지고놀기 기초문법 공부하기 5

doyou1 2021. 9. 28. 19:06
반응형
  • numpy 연산

 

앞선 포스팅에서 다뤘지만, 오늘은 조금 더 복잡하게 들어갈 예정이니, numpy 연산을 복습하고 가보도록 하자

 

import numpy as np

a = np.random.randint(1, 5, (5, ))
b = np.random.randint(1, 5, (5, ))	

print("a: ", a)		# a:  [1 1 3 3 1]
print("b: ", b, '\n')	# b:  [1 1 2 4 3] 
print("a + b: ", a + b)	# a + b:  [2 2 5 7 4]

변수 a, b는 np.random.randint(1, 5, (5, )) 1<=x<5 사이의 임의의 정수를 (5, )의 모양으로 배열 생성

이후 a + b 하게 되면

a + b = [ a[0]+b[0],
	a[1]+b[1], 
        a[2]+b[2], 
        a[3]+b[3], 
        a[4]+b[4] ]

위의 코드와 같이 연산이 진행된다.

 

이러한 맥락에서 다른 연산자들을 활용해보면

a - b = [ a[0]-b[0],
	a[1]-b[1], 
        a[2]-b[2], 
        a[3]-b[3], 
        a[4]-b[4] ]
        
a * b = [ a[0]*b[0],
	a[1]*b[1], 
        a[2]*b[2], 
        a[3]*b[3], 
        a[4]*b[4] ]
        
a / b = [ a[0]/b[0],
	a[1]/b[1], 
        a[2]/b[2], 
        a[3]/b[3], 
        a[4]/b[4] ]
        
a // b = [ a[0]//b[0],
	    a[1]//+b[1], 
        a[2]//b[2], 
        a[3]//b[3], 
        a[4]//b[4] ]
        
a % b = [ a[0]%b[0],
	a[1]%b[1], 
        a[2]%b[2], 
        a[3]%b[3], 
        a[4]%b[4] ]
        
a ** b = [ a[0]**b[0],
	a[1]**b[1], 
        a[2]**b[2], 
        a[3]**b[3], 
        a[4]**b[4] ]

이와 같은 방식으로 동일하게 연산이 진행되고,

a = np.arange(2*2).reshape((2, 2))
b = np.arange(2*2).reshape((2, 2))

print(a + b)	# [[0 2]
		# [4 6]]
        
a = np.arange(3*3).reshape((3, 3))
b = np.arange(3*3).reshape((3, 3))

print(a + b)	# [[ 0  2  4]
    		# [ 6  8 10]
		# [12 14 16]]

다차원 배열 역시 같은 방식으로 연산이 가능하다.

 

  • Broadcasting(브로드캐스팅)

- 앞선 방법도 행렬, 배열간의 연산을 간단히 구현할 수 있게 하지만, 더 활용도가 높은 개념이 있다.

- 그것이 Broadcasting이다. 한국말로 정확히 번역이 애매해 "브로드캐스팅"으로 칭하겠다.

 

- 브로드캐스팅을 설명하기 위해 하나의 상황을 가정하겠다.

 

- 문제1

어느 학생 3명의 국어, 영어, 수학시험을 보았고, 점수가 나왔다.

그런데, 국어, 영어, 수학 시험문제에 오류가 있어 과목에 따라 보정점수가 주어졌다.

해당 상황을 코드로 구현해보아라.

 

# student[0] : 국어, student[1] : 영어, student[2] : 수학
student_a = np.random.randint(0,100+1,3)
student_b = np.random.randint(0,100+1,3)
student_c = np.random.randint(0,100+1,3)

# 최초 점수
scores = np.array((student_a,student_b,student_c))
print(scores)
#         국 영 수
# 학생a [[21 29 75]
# 학생b [ 6 51 66]
# 학생c [33  7 91]]


# 보정 점수, 국어 : 15점, 영어 : 10점, 수학 : 5점
comp = np.array([15, 10, 5])
print(scores + comp)
#         국 영 수
# 학생a [[36 39 80]
# 학생b [21 61 71]
# 학생c [48 17 96]]

print(scores.shape, comp.shape)	# (3, 3) (3, )

문제는 위의 코드와 같이 구현할 수 있겠다.

생각보다 코드가 간단하지 않은가? 그런데 여기서 처음보는 코드 구조가 있다.

print(scores.shape, comp.shape)	# (3, 3) (3, )

scores와 comp의 모양이 다른데 어떻게 연산이 되는걸까?

 

관련 그림을 깔끔하게 그리고 싶었으나, 표로 대체하겠슴당.

 

random.randint()를 통해 생성한 값을 기준으로 설명해보겠다.

기존점수 국어 영어 수학
학생a 21 29 75
학생b 6 51 66
학생c 33 7 91
  국어 영어 수학
보정점수 15 10 5

표로 표현해보자면, 기존점수와 보정점수는 이런식으로 그려질 것이다.

그리고 행렬로 표현하면, 아래와 같이 그려진다.

 

$$ \left[\begin{matrix}21 & 29 & 75 \\ 6 & 51 & 66 \\ 33 & 7 & 91\\\end{matrix}\right] +  \left[\begin{matrix} 15 & 10 & 5\\\end{matrix}\right]$$

 

이러한 식으로 서로 모양이 같지 않은 행렬은 어떻게 계산되는 것일까?

 

$$ \left[\begin{matrix}21 & 29 & 75 \\ 6 & 51 & 66 \\ 33 & 7 & 91\\\end{matrix}\right] + \left[\begin{matrix}15 & 10 & 5 \\ 15 & 10 & 5 \\ 15 & 10 & 5\\\end{matrix}\right] = \left[\begin{matrix}36 & 39 & 80 \\ 21 & 61 & 71 \\ 48 & 17 & 96\\\end{matrix}\right]$$

 

- (3, 3)행렬과 (3, )행렬의 합은 뒷행렬이 (3, ) -> (3, 3)으로 늘어진 후, 각각의 요소에 대응하여 합계산을 하게 된다.

 

- 그렇다면 (3, 3)행렬과 (3, 1)행렬의 합도 가능할까?

a = np.arange(3*3).reshape((3, 3))
b = np.arange(3).reshape((3, 1))

print(a)
# [[0 1 2]
#  [3 4 5]
#  [6 7 8]]
print(b)
# [[0]
#  [1]
#  [2]]

print(a + b)
# [[ 0  1  2]
#  [ 4  5  6]
#  [ 8  9 10]]

 

$$\left[\begin{matrix}0&1&2\\3&4&5\\6&7&8\\\end{matrix}\right] + \left[\begin{matrix}0\\1\\ 2\\\end{matrix}\right]$$

 

이러한 식으로 행렬, 배열간의 합을 구해보고자 하면

 

$$\left[\begin{matrix}0&1&2\\3&4&5\\6&7&8\\\end{matrix}\right] + \left[\begin{matrix}0&0&0\\1&1&1\\2&2&2\\\end{matrix}\right] = \left[\begin{matrix}0&1&2\\4&5&6\\8&9&10\\\end{matrix}\right]$$

 

- (3, 3)행렬과 (3, 1)행렬의 합은 뒷행렬이 (3, 1) -> (3, 3)으로 늘어진 후, 각각의 요소에 대응하여 합계산을 하게 된다.

 

 

반응형