넘파이(Numpy)는 Python에서 벡터, 행렬 등 수치 연산을 수행하는 선형대수(Linear algebra) 라이브러리이다. 선형대수 관련 수치 연산을 지원하고 내부적으로는 C로 구현되어 있어 연산이 빠른 속도로 수행된다. 또한 Scipy와 함께 사용하면 공학용 소프트웨어인 MATLAB에 버금가는 기능을 지원한다고 알려져 있다.
선형대수의 데이터의 유형에는 스칼라(scalar), 벡터(vector), 행렬(matrix), 텐서(Tensor)가 있다.
numpy의 array로 벡터와 행렬, 텐서를 표현할 수 있다.
import numpy as np
arr = np.arange(0, 32)
#벡터
arr -> array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31])
#행렬
v= arr.reshape([4,8])
v -> 4행 8열의 행렬
#텐서
v = arr.reshape([4,2,4])
v ->
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]],
[[16, 17, 18, 19],
[20, 21, 22, 23]],
[[24, 25, 26, 27],
[28, 29, 30, 31]]])
#이런 텐서를 만나게 되면 괄호를 기준으로 차원을 생각해볼수 있다.
가장 작은 괄호는 텐서 크기의 가장 마지막 값을 가리킨다.(H x W x D에서 D)
arr = [1, 2, 3, 4, 5]
print(arr, type(arr)) -> [1, 2, 3, 4, 5] <class `list`>
np_arr = np.array(arr)
print(np_arr, type(np_arr)) -> [1 2 3 4 5] <class `numpy.ndarray`>
파이썬과 동일 다만 특이사항은 아래 블로그 인덱싱 부분 참고
https://laboputer.github.io/machine-learning/2020/04/25/numpy-quickstart/
a = np.arange(12)**2
print(a)
# [ 0 1 4 9 16 25 36 49 64 81 100 121]
i = np.array([1, 1, 3, 8, 5])
print(a[i])
#i라는 배열의 값들은 a라는 배열의 인덱스를 가리킨다.
# [ 1 1 9 64 25]
j = np.array([[3, 4], [9, 7]])
print(a[j])
#j라는 배열의 값들은 a라는 배열의 인덱스를 가리킨다.
# [[ 9 16]
# [81 49]]
palette = np.array([[0, 0, 0], # black
[255, 0, 0], # red
[0, 255, 0], # green
[0, 0, 255], # blue
[255, 255, 255]]) # white
image = np.array([[0, 1, 2, 0],
[0, 3, 4, 0]])
palette[image]
# array([[[ 0, 0, 0],
# [255, 0, 0],
# [ 0, 255, 0],
# [ 0, 0, 0]],
# [[ 0, 0, 0],
# [ 0, 0, 255],
# [255, 255, 255],
# [ 0, 0, 0]]])
,를 기준으로 차원을 구별할 수 있다.
arr = np.array([
[1, 2, 3, 4, 5],
[4, 5, 6, 7, 8],
[5, 6, 7, 8, 9],
[10, 11, 14, 15, 17]
])
#arr[1:3][2:4]이렇게 쓰면 안된다. 가운데를 ,로 구분해주면 기가막히게 행, 열, 깊이, 상위차원을 구분해서 잘라준다.
print(arr[1:3, 2:4]) ->
[[6 7]
[7 8]]
arr_A = np.array([1, 2, 3, 4, 5])
arr_B = np.array([6, 7, 8, 9, 10])
result = arr_A + arr_B -> [ 7 9 11 13 15]
result = arr_A * arr_B -> [ 6 14 24 36 50]
result = arr_A - arr_B -> [ 3 3 -1 1 -1]
result = arr_A / arr_B -> 몫 계산
result = arr_A % arr_B -> 나머지 계산
Numpy에서는 같은 모양의 배열이 아니더라도 (1)상수를 배열에 더하거나, (2)모양이 다른 배열끼리 덧셈 연산이 가능합니다(단, 특정 조건을 갖춘 배열이여야 합니다). 이와 같이 Numpy에서 배열의 모양이 다르더라도 자동으로 맞춰 연산하는 것을 브로드캐스팅이라고 합니다. 하지만 브로드캐스팅이 적용되려면 특정 조건을 갖춰야만 합니다.
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
arr[3:7] = 100
arr -> [ 1 2 3 100 100 100 100 8 9 10]
#더 높은 차원도 가능하다.
arr[2:6, 3:8] = 0
A.dot(B)
np.dot(A, B)
A @ B
두 계산의 결과는 행렬의 곱과 같다.
Numpy에선 특별한 관계연산을 사용한 인덱싱이 가능하다. 예시로 보자.
A = np.array([1, 2, 3, 4, 5, 4, 3, 2, 1])
print(A >= 4) -> [False False False True True True False False False]
A = np.array([1, 2, 3, 4, 5, 4, 3, 2, 1])
#bool 배열B를 생성한다. B를 A의 인덱스로 넣어준다.
B = (A >= 4)
print(A[B]) -> [4 5 4]
A = np.array([1, 2, 3, 4, 5, 4, 3, 2, 1])
A[(A > 1) & (A <= 3)] = 0
print(A) -> [1 0 0 4 5 4 0 0 1]
단, Numpy에서 논리 연산자를 사용하여 여러 조건식을 결합할 때, and 및 or가 아닌 & 및 |를 사용한다.
A = np.random.randint(0, 100, size=(3, 3, 3))
#A배열에서 요소의 값이 52거나 1인 자리에 True를 넣음
result = (A == 52) | (A == 1)
ndarray.shape : 배열의 각 축(axis)의 크기(순서대로 행, 열, 깊이), 객체값으로 리턴 //
ndarray.ndim : 축의 개수(Dimension)
ndarray.dtype : 각 요소(Element)의 타입
ndarray.itemsize : 각 요소(Element)의 타입의 bytes 크기
ndarray.size : 전체 요소(Element)의 개수
a = np.arange(15).reshape(3, 5)
print(a.shape)
# (3, 5)
print(a.ndim)
# 2
print(a.dtype)
# int64
print(a.itemsize)
# 8
print(a.size)
# 15
print(type(a))
# <class 'numpy.ndarray'>
np.zeros(shape) : 0으로 구성된 N차원 배열 생성 // A = np.zeros(shape=(2,3))
np.ones(shape) : 1로 구성된 N차원 배열 생성 // A = np.ones(shape=(2,3))
np.empty(shape) : 초기화되지 않은 N차원 배열 생성
numpy.arange(start(optional), stop, step(optional), dtype=None, *, like=None)
np.arange(3) array([0, 1, 2])
np.arange(3.0) array([ 0., 1., 2.])
np.arange(3,7) array([3, 4, 5, 6])
np.arange(3,7,2) array([3, 5])
np.linspace(): N 등분한 숫자 생성 // np.linspace(0, 99, 100), 0~99까지 100등분
정규 분포에 맞게 생성하는 함수로서 모양을 size 인자를 통해 전달하여 배열을 생성합니다. 이때 평균(mean)과 표준편차(std)값을 각각 loc, scale 인자를 통해 지정할 수 있습니다.
Example
rand_arr = np.random.normal(size=(3, 2))
rand_normal_arr = np.random.normal(loc = 3, scale = 0.25, size=(3, 2))
Parameters
loc : float or array_like of floats
scale : float or array_like of floats
size : int or tuple of ints, optional
임의의 정수들로 채워진 배열을 만들어줍니다. 이때 정수 범위는 start 이상 end 미만으로, size에 모양을 인자로 전달합니다.
Example
rand_int_arr = np.random.randint(1, 10, size=(3, 2))
Parameters
low : int or array-like of ints
high : int or array-like of ints, optional
size : int or tuple of ints, optional
dtype : dtype, optional
모양을 인자로 주어 배열을 생성합니다. 이때, randn()에 들어간 인자의 순서대로 차원의 크기가 정해집니다. 예를 들어, randn(3, 2)는 3 x 2 모양을 가진 2차원 배열을 생성합니다.
파이썬의 random패키지와 같이 seed를 고정하여 일정하게 랜덤 값을 유지할 수 있습니다.
Example
np.random.seed(0)
print(np.random.randn(3))
np.random.seed(2)
print(np.random.randn(3))
np.random.seed(0)
print(np.random.randn(3))
높이가 H, 너비가 W인 컬러 이미지에서 RGB 정보를 추출하여 만든 3차원 배열 img는 H x W x 3 모양을 가집니다. 그리고 img의 채널은 R, G, B 순으로 있습니다. 예를 들어, img[1, 1, 0]는 (1, 1) 위치에 있는 픽셀의 R 값에 접근합니다. 또, img[2, 1, 2]는 (2, 1) 위치에 있는 픽셀의 B 값에 접근합니다. img가 numpy.ndarray 타입으로 주어질 때, 위의 방법을 참고하여 img 를 흑백 이미지를 나타내는 H x W 모양의 2차원 배열로 변환하는 함수를 구현하세요.
import numpy as np
def solution(img):
#배열을 미리 0으로 만들어주고
answer = np.zeros(shape = (len(img),len(img[0])))
#각각의 인덱스 값에 알맞는 흑백의 명도 값을 넣어주었다.
#근데 뭔가 반대로 넣은거 같은데... 일단 보류
for w_index in range(len(img)):
for h_index in range(len(img[w_index])):
R, G, B = img[w_index][h_index]
N = 0.3*R + 0.5*G + 0.2*B
answer[w_index][h_index] = N
return answer