Numpy 라이브러리

Numpy 는 파이썬이 계산과학분야에 이용될 때 핵심 역할을 하는 라이브러리로, 고성능의 다차원 배열 객체와 이를 다룰 도구를 제공합니다. scikit-learn 에서 Numpy 배열은 기본 데이터 구조입니다.

용어 정리

본격적으로 사용법을 알기 전에 용어를 알도록 합시다.

  • axis : 각 차원의 축
  • rank : 축의 개수
  • shape : 배열의 축 길이
  • size : 배열의 사이즈

코드를 통해 이제 각 의미를 더 알아봅시다.

소스코드로 알아보기

import

우선 넘파이를 사용하기 위해서는 numpy를 불러와야합니다.

import numpy as np

numpy를 보통 np로 alias합니다.

배열

Numpy의 가장 핵심은 배열 객체입니다. 배열 객체의 생성과 각 객체가 어떻게 생겼는지 알아봅시다.

array

기본적인 배열을 의미합니다. 다음과 같이 생성 맟 초기화 할 수 있습니다.

import numpy as np

a = np.array([1, 2, 3])    # rank가 1인 배열 생성

type 그리고 shap을 확인해보면 다음과 같습니다.

print(type(a))            # 출력 "<type 'numpy.ndarray'>"
print(a.shape)            # 출력 "(3,)"
print(a[0], a[1], a[2])   # 출력 "1 2 3"
a[0] = 5                   # 요소를 변경
print(a)                  # 출력 "[5, 2, 3]"

b = np.array([[1,2,3],[4,5,6]])   # rank가 2인 배열 생성
print(b.shape)                     # 출력 "(2, 3)"
print(b[0, 0], b[0, 1], b[1, 0])   # 출력 "1 2 4"

zeros / ones / full

원하는 값으로 채워진 배열을 만들기 위해 사용됩니다.

  • zeros : 0
  • ones : 1
  • full : 파라미터 지정값
# zeros
a = np.zeros(5)
b = np.zeros((3,4))

print(a)
# [0. 0. 0. 0. 0.]

print(b)
# [[0. 0. 0. 0.]
# [0. 0. 0. 0.]
# [0. 0. 0. 0.]]
# ones
c = np.ones(5)
d = np.ones((3,4))

print(c)
# [1. 1. 1. 1. 1.]

print(d)
# [[1. 1. 1. 1.]
# [1. 1. 1. 1.]
# [1. 1. 1. 1.]]
# full
e = np.full((3,2),7)
print(e)
#[[7 7]
# [7 7]
# [7 7]]

eye

단위 행렬로 만드는 함수입니다. 정사각행렬에 주대선의 원소들이 1인 행렬입니다.

a = np.eye(2)

print(a)

#[[1. 0.]
# [0. 1.]]

배열 인덱싱

넘파이 배열을 인덱싱하는 방법에 대해서 알아봅시다.

슬라이싱

파이썬 배열과 마찬가지로 슬라이싱을 할 수 있습니다.

import numpy as np

# 아래와 같은 요소를 가지는 rank가 2이고 shape가 (3, 4)인 배열 생성
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# 배열의 중간 행에 접근하는 두 가지 방법이 있습니다.
# 정수 인덱싱과 슬라이싱을 혼합해서 사용하면 낮은 rank의 배열이 생성되지만,
# 슬라이싱만 사용하면 원본 배열과 동일한 rank의 배열이 생성됩니다.
row_r1 = a[1, :]    # 배열a의 두 번째 행을 rank가 1인 배열로
row_r2 = a[1:2, :]  # 배열a의 두 번째 행을 rank가 2인 배열로
print(row_r1, row_r1.shape)  # 출력 "[5 6 7 8] (4,)"
print(row_r2, row_r2.shape)  # 출력 "[[5 6 7 8]] (1, 4)"

# 행이 아닌 열의 경우에도 마찬가지입니다:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape)  # 출력 "[ 2  6 10] (3,)"
print(col_r2, col_r2.shape)  # 출력 "[[ 2]
                            #       [ 6]
                            #       [10]] (3, 1)"

정수 배열 인덱싱

슬라이싱은 배열에서 부분배열로 만드는 방법이라면, 인덱싱을 이용하면 새로운 배열을 만들 수 있습니다.

import numpy as np

a = np.array([[1,2], [3, 4], [5, 6]])

# 정수 배열 인덱싱의 예.
# 반환되는 배열의 shape는 (3,)
print (a[[0, 1, 2], [0, 1, 0]])  # 출력 "[1 4 5]"

# 정수 배열 인덱싱을 사용할 때,
# 원본 배열의 같은 요소를 재사용할 수 있습니다:
print (a[[0, 0], [1, 1]])  # 출력 "[2 2]"

다음과 같은 방법으로 활용할 수 있습니다.

import numpy as np

# 요소를 선택할 새로운 배열 생성
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])

print (a)  # 출력 "array([[ 1,  2,  3],
           #             [ 4,  5,  6],
           #             [ 7,  8,  9],
           #             [10, 11, 12]])"

# 인덱스를 저장할 배열 생성
b = np.array([0, 2, 0, 1])


# b에 저장된 인덱스를 이용해 각 행에서 하나의 요소를 선택합니다
print (a[np.arange(4), b])  # 출력 "[ 1  6  7 11]"

# b에 저장된 인덱스를 이용해 각 행에서 하나의 요소를 변경합니다
a[np.arange(4), b] += 10

print (a)  # 출력 "array([[11,  2,  3],
           #             [ 4,  5, 16],
           #             [17,  8,  9],
           #             [10, 21, 12]])

불리안 배열 인덱싱

불리안 즉 조건을 통해 원하는 정보만 가져올 수도 있습니다.

import numpy as np

a = np.array([[1,2], [3, 4], [5, 6]])

bool_idx = (a > 2)  # 2보다 큰 a의 요소를 찾습니다;
                    # 이 코드는 a와 shape가 같고 불리언 자료형을 요소로 하는 numpy 배열을 반환합니다,
                    # bool_idx의 각 요소는 동일한 위치에 있는 a의
                    # 요소가 2보다 큰지를 말해줍니다.

print(bool_idx)      # 출력 "[[False False]
                     #       [ True  True]
                     #       [ True  True]]"

# 불리언 배열 인덱싱을 통해 bool_idx에서
# 참 값을 가지는 요소로 구성되는
# rank 1인 배열을 구성할 수 있습니다.
print (a[bool_idx])  # 출력 "[3 4 5 6]"

# 위에서 한 모든것을 한 문장으로 할 수 있습니다:
print (a[a > 2])     # 출력 "[3 4 5 6]"

자료형

생략

연산

넘파이는 행렬간 연산을 효율적으로 해주기에 유용하며, 앞으로 사용해야하는 다양한 연산이 있지만 그 중에서도 기본은 다음과 같습니다.

기본 연산

넘파이에서 기본적인 연산의 경우에는 각 대응되는 원소간의 연산으로 이루어집니다. 배열에서의 각 원소가 독립적으로 계산되는 것 입니다.

import numpy as np

x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)

# 요소별 합; 둘 다 다음의 배열을 만듭니다
# [[ 6.0  8.0]
#  [10.0 12.0]]
print (x + y)
print (np.add(x, y))

# 요소별 차; 둘 다 다음의 배열을 만듭니다
# [[-4.0 -4.0]
#  [-4.0 -4.0]]
print (x - y)
print (np.subtract(x, y))

# 요소별 곱; 둘 다 다음의 배열을 만듭니다
# [[ 5.0 12.0]
#  [21.0 32.0]]
print (x * y)
print (np.multiply(x, y))

# 요소별 나눗셈; 둘 다 다음의 배열을 만듭니다
# [[ 0.2         0.33333333]
#  [ 0.42857143  0.5       ]]
print (x / y)
print (np.divide(x, y))

# 요소별 제곱근; 다음의 배열을 만듭니다
# [[ 1.          1.41421356]
#  [ 1.73205081  2.        ]]
print (np.sqrt(x))

dot 연산

import numpy as np

x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])

v = np.array([9,10])
w = np.array([11, 12])

# 벡터의 내적; 둘 다 결과는 219
print (v.dot(w))
print (np.dot(v, w))

# 행렬과 벡터의 곱; 둘 다 결과는 rank 1인 배열 [29 67]
print (x.dot(v))
print (np.dot(x, v))

# 행렬곱; 둘 다 결과는 rank 2인 배열
# [[19 22]
#  [43 50]]
print (x.dot(y))
print (np.dot(x, y))

sum 연산

다양한 연산이 존재하지만 sum은 그 중에서도 유용한 기능을 가지고 있습니다.

import numpy as np

x = np.array([[1,2],[3,4]])

print (np.sum(x))  # 모든 요소를 합한 값을 연산; 출력 "10"
print (np.sum(x, axis=0))  # 각 열에 대한 합을 연산; 출력 "[4 6]"
print (np.sum(x, axis=1))  # 각 행에 대한 합을 연산; 출력 "[3 7]"

변환

전치

연산이 아니라도 전처리를 하기 위해 변환이 필요합니다. 그 중에서 가장 많이 사용되는 것은 전치입니다. 주대각선을 기준으로 뒤집는 연산입니다. 2차원 행열에서는 행과 열이 바뀌는 것을 의미합니다.

import numpy as np

x = np.array([[1,2], [3,4]])
print (x)    # 출력 "[[1 2]
           #          [3 4]]"
print (x.T)  # 출력 "[[1 3]
           #          [2 4]]"

# rank 1인 배열을 전치할 경우 아무 일도 일어나지 않습니다:
v = np.array([1,2,3])
print (v)    # 출력 "[1 2 3]"
print (v.T)  # 출력 "[1 2 3]"

브로드캐스팅

numpy의 가장 큰 장점은 크기가 다른 배열에서도 연산을 가능하게 해줍니다. 이를 브로드캐스팅이라고 합니다.

하지만 귀찮으니까 나중에 정리하겠습니다.

REF.

AI koera - CS231n 번역 - Python Numpy Tutorial

핸즈온 머신러닝 - 넘파이 튜토리얼

Leave a Comment