[9/7] (1) Numpy 기초

박정훈·2021년 9월 8일
0

수업 일지

목록 보기
2/4

참고

  • 프로그래밍 수업 내용 정리와 복습, 기초적인 딥러닝 정보 저장을 위해 작성합니다
  • 고등학교 수학 정도의 지식을 가지고 있는 학생이 주된 대상입니다
  • Python에 대해서는 기본적인 내용(자료형, 제어문, 함수, 클래스)에 대한 학습을 마친 상태입니다

수업 환경

  • MacOS (학생) / Ubuntu 20.04 (선생님)
  • python 3.8
  • anaconda 4.10.3

Numpy 설치

terminal(pycharm 하단부에 있습니다)을 켜고, 아래 명령어를 실행합니다

pip install numpy

Note
저번 시간에 가상환경을 pycharm에 연동했습니다. terminal에 가상환경이 켜진 채 진행해야합니다. (terminal 좌측에 (venv_name) ~$)

설치 완료 후, python 파일에 가서 아래를 실행했을 때 오류가 나지 않으면 성공!

import numpy as np

numpy라는 라이브러리를 가져오는데, as 를 사용하면 별칭(np)로 가져올 수 있습니다.

Numpy Array

numpy의 array는 np.array() 메소드를 통해 생성합니다.

사칙 연산

python의 자료형인 list와는 비슷하면서도 다른데요, 연산에서 그 차이가 두드러집니다. list는 곱셈, 덧셈이 각각 list 이어붙이기와 반복이었지만, np.array()는 원소별 사칙연산입니다.

a = np.array([1, 2, 3])  # 1, 2, 3을 원소로 같은 1차원 배열 생성
print(a)  # [1, 2, 3]
print(type(a))  # <class 'numpy.ndarray'> -> numpy array의 type
b = np.array([2, 4, 6])

# 덧셈, 뺄셈, 곱셈, 나눗셈
print(a + b)  # [3, 6, 9]
print(a - b)  # [-1, -2, -3]
print(a * b)  # [2, 8, 18]
print(a / b)  # [0.5, 0.5, 0.5]

한편, array와 값 하나(ex. int형 값) 사이의 사칙연산도 가능합니다. 이때, 연산을 각 원소별로 수행합니다.

a = np.array([1, 2, 3])
print(a / 2)  # [0.5, 1.0, 1.5]

다차원 배열

python의 list에 n차원 리스트가 있듯이, numpy에도 다차원 배열이 존재합니다. 가장 대표적인 다차원 배열인 행렬(== 2차원 배열)은 다음과 같이 생성합니다. 여기서 차원은 가장 간단하게 말해서, 배열을 시작하는 괄호의 수(i.e. 한 값을 얻기 위해 인덱싱해야하는 횟수)를 의미합니다.

matrix = np.array(
    [[1, 2, 3],
     [4, 5, 6]]
)
print(matrix)
# [[1 2 3]
#  [4 5 6]]
print(A.shape)  # (2, 3)

Shape

numpy의 n차원 배열은 모두 shape이라는 값을 갖고, 말그대로 배열의 모양을 나타냅니다.

  • Shape의 특징
    : shape은 tuple이며, 길이는 배열의 차원과 같습니다.
    : shape의 각 값들은 해당 차원에서 배열의 원소의 수를 의미합니다.

예시로, 굉장히 간단한 2x2 크기의 이미지를 생각해볼까요?
각 픽셀은 이미지의 색깔에 대한 정보를 담고 있습니다. 색은 3원색으로 구성되죠?
색깔에 대한 정보는 [255, 128, 0]과 같은 하나의 리스트로 표현됩니다.
(각 원소는 R, G, B에 대한 0~255 사이의 값입니다)

이 이미지를 numpy array로 표현하면 다음과 같겠죠

img = np.array(
    [[[255, 0, 0], [0, 255, 0]],
     [[0, 0, 255], [255, 255, 0]]]
)  # 각 픽셀들이 빨간색, 초록색, 파란색, 노란색인 이미지
print(img.shape)  # (2, 2, 3)

이 image의 shape은 (2, 2, 3)입니다.

  • 처음 2는 가장 바깥 괄호 관점에서 봤을 때 원소의 수
  • 두 번째 2는 그 다음 괄호 관점에서 봤을 때 원소의 수
  • 세 번째 3은 가장 안쪽 괄호 관점에서 봤을 때 원소의 수

차원이 하나 늘어나면 원소의 수를 고려할 관점이 하나 늘어나기 때문에, shape의 길이가 1 증가해야겠죠? 조금 일반화 하면 다음과 같습니다.

n차원 배열의 shape이 (s1, s2, ..., sn)이면, si는 i번째 괄호에서 본 원소의 수

Broad casting

기본적으로 연산은 shape이 같은 배열끼리만 가능합니다. 그래야 원소 별로 연산을 할 수 있죠! 다만, numpy에서는 다른 shape을 가진 배열 간의 연산도 지원합니다. 이때, numpy가 shape을 자동으로 맞춰준답니다. 이를 브로드캐스팅이라고 부릅니다.

a = np.array([[1, 2], [3, 4]])
b = np.array([10, 20])
print(a + b)  # b를 [[10, 20], [10, 20]]으로 자동으로 확대
# [[11, 22]
#  [13, 24]]

아까 본 array와 값 하나(ex. int형 값) 간의 연산도 브로드캐스팅의 결과입니다.

a = np.array([1, 2, 3])  # shape: (3, )
print(a * 4)  # a * np.array([4, 4, 4])로 브로드캐스팅

Array 간단하게 만들기

큰 shape의 array를 다루고 싶은데, 그때마다 일일이 리스트를 만들면 힘들겠죠?
numpy는 shape을 주면 자동으로 array를 만들어주는 다양한 메소드를 가지고 있습니다.

a = np.arange(600)  # 0~599까지 원소로 갖는 1차원 배열 생성
a = a.reshape(30, 20)  # shape을 (30, 20)으로 변환

b = np.zeros(30, 20)  # shape이 (30, 20)이고 모든 원소가 0인 배열 생성
c = np.ones(30, 20)  # shape이 (30, 20)이고 모든 원소가 1인 배열 생성

np.arange는 python 내부의 range와 동일한 인자를 받습니다.

a = np.arange(600)
a2 = np.arange(40, 100)  # 시작 40, 끝 100 이전(=99)
a3 = np.arange(20, 100, 2)  # 시작 20, 끝 100 이전, step = 2(실수도 가능)

Array Indexing/Slicing

전통적인 indexing/slicing

list에서는 lst[0][1] 등으로 인덱싱했지만, numpy에서는 대괄호 안에 모두 집어넣을 수 있습니다.

a = np.arange(600).reshape(30, 20)  # 한번에 (30, 20)의 증가하는 배열 만들기
print(a[0, 3])  # a[0][3]과 동일

Slicing 역시 가능합니다.

a = np.arange(600).reshape(30, 20) 
print(a[2:4, 8:11])  # shape이 (2, 3)인 array. 직접 해보세요!

이를 이용해서 행렬의 column을 손쉽게 가져올 수 있습니다.

a = np.arange(600).reshape(30, 20) 
print(a[:, 12])  # 12번 column. shape: (30, )

Boolean(mask) indexing

numpy는 index 자리에 배열을 넣을 수 있습니다. 예제를 보면 이해가 빠를거에요

a = np.arange(10)
mask = np.array([False, True] * 5)
print(a[mask])  # [1 3 5 7 9]

인덱싱 자리가 true인 원소만 모아서 가져오는 것이죠
numpy array에 비교연산자(>, <, ==, !=)를 하면 boolean type을 갖는 배열을 쉽게 얻을 수 있고, boolean indexing을 응용할 수 있습니다.

a = np.arange(10)
mask = a % 2 == 1  # 위의 mask와 동일한 array 생성
print(a[mask])
print(a[a % 2 == 1])  # 줄여서 이렇게 표현 가능

Reference

profile
배우는 중입니다

0개의 댓글