머신러닝에서 자주 사용하는 파이썬 라이브러리인 Numpy를 알아보겠습니다.
Numpy는 파이썬의 수치 계산에 주로 사용되는 패키지입니다.

numpy의 설치는 이전 포스팅과 같이 pip를 통해 해주었습니다.

Numpy (http://www.numpy.org/)

Numpy는 파이썬으로 과학 계산을 하기 위해선 필수적인 패키지입니다.
다차원 계산을 위한 기능과, 선형 대수 연산, 푸리에 변환, 유사 난수 생성기 등 복잡한 수치적 계산을 간소화해줍니다.

  • 선형 대수 : 벡터, 행렬, 선형 변환 등
  • 푸리에 변환 : 시간의 함수를 주파수 성분으로 분해
  • 유사 난수 생성기 : 초깃값을 이용하여 이미 결정되어 있는 매커니즘에 의해 생성되는 난수. 초깃값을 알면 언제든 같은 값을 다시 만들 수 있기 때문에 유사 난수라고 함.

Numpy 임포트

Numpy는 다음과 같이 np라는 별칭을 붙여 임포트합니다.

import numpy as np

Numpy 배열

사이킷런에서 Numpy 배열은 기본 데이터 구조이므로, 사이킷런에서는 Numpy 배열 형태의 데이터를 입력으로 받습니다. 즉, 사이킷런을 사용하기 위해서는 데이터를 모두 Numpy 배열로 변환해주어야 합니다.

다음 코드는 Numpy 배열을 보여주는 예시입니다.

In [5]:
import numpy as np
x = np.array([[1,2,3],[4,5,6]])
print("x:\n", x)

Out [5]:
x:
[[1 2 3]
[4 5 6]]

이러한 Numpy 배열은 ndarray 클래스 객체라고도 합니다.

지정한 크기의 배열 생성

numpy.ndarray 클래스 객체의 초기화 방법으로는 보통 다음 두 가지를 사용합니다.

(1) 형태 및 요소의 데이터 타입을 지정하고, 모든 요소에 값을 넣어 초기화

이 방식은 큰 행렬에 미리 메모리를 할당하여 효율적으로 요소를 추가합니다.

numpy.zeros(shape, dtype = None)

shape에는 정수 튜플을 지정하는데요, 예를 들어 3×2×4 크기의 3차원 배열을 생성하려면 shape=(3,2,4)처럼 지정합니다.

  • 튜플 : 임의의 데이터 타입 변수 set를 변수 1개로 묶은 자료형(배열과 유사)

dtype에는 요소의 데이터 타입을 지정합니다. default 값은 None이고, None으로 지정하면 numpy.float64 또는 numpy.int32가 됩니다.
행렬 요소를 1로 채우려면 numpy.ones() 메서드를 사용합니다.

(2) 배열 요소를 지정하여 생성

numpy.array(object, dtype=None, copy=True, order=None, subok=False, ndmin=0)

이미 다른 타입의 객체 iterable(list, dictionary 등)을 ndarray 요소로 만들 수 있습니다.
object 이외의 요소는 보통 지정하지 않습니다.

In [9]:
#(3,)배열 (3,1) 이나 (1,3)은 아님에 주의
x = np.array([1,2,3])
print(x)

Out [9]:
[1 2 3]

In [10]:
#(2,3) 배열
A = np.array([[1,2,3],[4,5,6]])
print(A)

Out [10]:
[[1 2 3]
[4 5 6]]

생성한 배열의 타입과 데이터 타입은 shape, dtype 속성을 통해 구할 수 있습니다.

In [11]:
print(A.shape)
print(A.dtype)

Out [11]:
(2, 3)
int32

요소로 접근

ndarray 요소에는 []를 사용해 접근합니다.
다중 리스트와는 달리, [] 하나에 튜플로 모든 첨자를 입력할 수 있습니다.
2차원은 행렬과 동일하게 행 > 열 순서로 첨자를 지정합니다.

In [12]:
#approach by one element
print(A[1,2])

Out [12]:
6

행렬과 같이 슬라이싱도 가능합니다.

In [13]:
print(A[0]) # 0번째 행만 출력
print(A[:,0:1]) # 2차원 배열로 출력
print(A[:,0]) # 1차원 배열로 출력

Out [13]:
[1 2 3]
[[1]
[4]]
[1 4]

전치행렬 구하기 (Transpose)

전치행렬은 numpy.ndarray.T로 구합니다. 다차원에서도 구할 수 있습니다.
먼저, 2차원 배열의 전치행렬을 구해봅니다.

In [14]:
#Transpose ([1,2,3][4,5,6]) -> ([1,4][2,5][3,6])
print(A)
print(A.T)

Out [14]:
[[1 2 3]
[4 5 6]]
[[1 4]
[2 5]
[3 6]]

3차원 배열의 전치행렬도 구해봅니다.

In [15]:
#Transpose of 3-D Array
B = np.array([[1,2],[3,4],[5,6]])
print(B)
print(B.shape)
print('\n->\n')
print(B.T)
print(B.T.shape)
print('\n')

Out [15]:
[[[1 2]
[3 4]
[5 6]]]
(1, 3, 2)
->
[[[1]
[3]
[5]]
[[2]
[4]
[6]]]
(2, 3, 1)

행렬의 차원은 역순이 됩니다.

행렬의 형태 변경

numpy.ndarray.reshape() 메소드를 사용하면 동일한 요소 개수 하에서 ndarray 클래스 객체의 형태를 변경할 수 있습니다.

In [16]:
#(2,3) -> (1,6)
print(A.reshape(1,6))

Out [16]:
[[1 2 3 4 5 6]]

요소 개수가 일치하지 않으면 오류가 발생합니다.

In [17]:
#(1,3,2) -> (4,1,1)
print(B.reshape(4,1,1))

Out [17]:
ValueError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_7008/3012235982.py in
1 #(1,3,2) -> (4,1,1)
----> 2 print(B.reshape(4,1,1))
ValueError: cannot reshape array of size 6 into shape (4,1,1)

배열 연결하기

numpy.r_[] 를 사용해서 배열을 새로운 행에 결합할 수 있습니다. 여기서 r는 행을 의미합니다.

In [18]:
C = np.ones((2,3))
print(np.r_[A,C])

Out [18]:
[[1. 2. 3.]
[4. 5. 6.]
[1. 1. 1.]
[1. 1. 1.]]

열에 결합하려면, numpy.c_[] 를 사용합니다.

In [19]:
print(np.c_[A,C])

Out [19]:
[[1. 2. 3. 1. 1. 1.]
[4. 5. 6. 1. 1. 1.]]

numpy.concatenate()로도 배열을 연결할 수 있습니다.

In [20]:
print(np.concatenate((A.T, C.T), axis=0))

Out [20]:
[[1. 4.]
[2. 5.]
[3. 6.]
[1. 1.]
[1. 1.]
[1. 1.]]

In [21]:
print(np.concatenate((A.T, C.T), axis=1))

Out [21]:
[[1. 4. 1. 1.]
[2. 5. 1. 1.]
[3. 6. 1. 1.]]

axis 설정은 0부터 차원-1까지만 존재합니다.
3차원 배열을 통해 axis 설정을 알아봅시다.

In [23]:
D = np.array([A,C])
E = np.array([B.T.reshape(2,3), np.zeros((2,3))])
np.concatenate((D,E), axis=0)

Out [23]:
array([[[1., 2., 3.],
[4., 5., 6.]],

[[1., 1., 1.],
[1., 1., 1.]],

[[1., 3., 5.],
[2., 4., 6.]],

[[0., 0., 0.],
[0., 0., 0.]]])

In [25]:
np.concatenate((D,E), axis=1)

Out [25]:
[[[1. 2. 3.]
[4. 5. 6.]
[1. 3. 5.]
[2. 4. 6.]]

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

23과 25는 axis=0, axis=1 설정만 다릅니다.
23의 경우에는 결과값이 (4,2,3) 차원이고, 25의 경우에는 결과값이 (2,4,3) 차원입니다.

axis=2로 설정하면 어떤 차원의 결과값이 출력될까요?

In [26]:
AX2 = np.concatenate((D,E), axis=2)
print(AX2)
np.shape(AX2)

Out [26]:
[[[1. 2. 3. 1. 3. 5.]
[4. 5. 6. 2. 4. 6.]]

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

(2,2,6) 차원으로 배열이 연결되었습니다.
배열 연결 시, 결과의 데이터 타입은 큰 쪽과 일치됩니다.

사칙연산

동일한 형태의 ndarray끼리는 각 요소마다 사칙연산을 수행할 수 있습니다.

In [30]:
F = B.T.reshape(2,3)
print("# 덧셈")
print(A+F)
print("# 뺄셈")
print(A-F)
print("# 곱셈")
print(A*F)
print("# 나눗셈")
print(A/F)

Out [30]:
# 덧셈
[[ 2 5 8]
[ 6 9 12]]
# 뺄셈
[[ 0 -1 -2]
[ 2 1 0]]
# 곱셈
[[ 1 6 15]
[ 8 20 36]]
# 나눗셈
[[1. 0.66666667 0.6 ]
[2. 1.25 1. ]]

행렬곱을 사용하려면 numpy.dot(A,B) 또는 A.dot(B)를 사용합니다.
사칙연산의 경우, 배열 크기가 완전히 일치하지 않더라도 자동으로 크기를 확장한 후 계산합니다.

In [31]:
G = np.array([1,2,3])
print(A+G) # C가 (1,3) -> (2,3) 으로 확장

Out [32]:
[[2 4 6]
[5 7 9]]

[참고자료]

▫ 「머신 러닝 부트캠프 with 파이썬」 시스템계획연구소, (주)도서출판길벗, 2018-07-16
▫ 「Introduction to Machine Learning with Python」, Andreas Müller, O'Reilly, 2021-07-19

profile
세양쥐는 코딩하는 찍찍쥐

0개의 댓글