데이터 사이언스 분야에서 쉽게 접하는 것이 바로 Numpy 이다.
대체로 다차원 배열(ndarray)을 다룰 때 사용하는 모듈이기도 하다.
Numpy 를 깊게 배울 필요는 없지만 이런 기능이 있다고 알아둔다면 나중에 필요한 기능이 생각날 때 떠오를 수 있을 것이다.
Numpy 는 list 보다 빠르고 적은 메모리를 사용하여 좀 더 유리하다. 그리고 수학적인 계산(선형대수학, 통계 등)을 위한 함수가 많이 있어 상황에 맞게 유용하게 사용할 수 있다.
1. 다차원 배열 계산
그림과 같은 행렬이 있다고 가정하자. 각 배열의 원소마다 +1 씩 더하고 싶다면 어떤 코드를 작성해야 할까?
num = [[1,2,3], [4,5,6], [7,8,9]]
for i in range(len(num)):
for j in range(len(num[i])):
num[i][j] += 1
print(num)
-----------------------------------
[[2, 3, 4], [5, 6, 7], [8, 9, 10]]
많은 방식으로 구할 수 있겠지만 지금의 경우는 이중 반복문을 돌려 실행하는 방법이 있을 것이다. 만약 지금은 2차원 배열이지만 3차원... 4차원... 10차원 등등 차원이 커질 경우에도 계속 반복문을 중첩시키는 것이 바람직할까? 이런 경우에도 사용할 수 있는 것이 Numpy 이다.
import numpy as np
num = np.array([[1,2,3], [4,5,6], [7,8,9]])
num += 1
print(num)
---------------------------------------------
[[ 2 3 4]
[ 5 6 7]
[ 8 9 10]]
이차원 배열을 np.array 로 선언하고 +1 만으로 계산을 완성시켰다. 이와 같은 편리한 기능을 브로드캐스팅이라고 한다.
이외에도 많은 메소드 기능들이 들어있다.
- np.sum(다차원배열) : 배열 원소들의 총합
- np.mean(다차원배열) : 배열 원소들의 전체 평균
- np.mean(다차원배열, axis=0) : 각 열마다 원소들의 평균
- np.mean(다차원배열, axis=1) : 각 행마다 원소들의 평균
- 이외에도 많음.
# 배열
import numpy as np
arr = np.arange(10)
arr
------------------
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
numpy 의 배열은 range 가 아닌 arange 로 만들 수 있다.
arr[1:4] = 10
arr
-------------------
array([ 0, 10, 10, 10, 4, 5, 6, 7, 8, 9])
그리고 슬라이스를 통해 상수 값을 대입하면 브로드캐스팅이 일어난다.
여기서 중요한 점은 원본 배열의 뷰(View) 라는 것이고 뷰의 변경은 원본 배열과 연동된다.
copy_arr = arr[1:4]
copy_arr
--------------------
array([10, 10, 10])
copy_arr[1] = 20
arr
---------------------
array([ 0, 10, 20, 10, 4, 5, 6, 7, 8, 9])
다음과 같이 원본 배열 arr 의 일부 인덱스를 불러 copy_arr 에 넣었다.
그리고 copy_arr 의 1 위치에 대해 20으로 변경하고 원본 배열 arr을 보니 20으로 변경되어 있는 것을 확인할 수 있다.
그래서 만약 원본 배열의 복사본(연동 안되는 배열)을 선언하고 싶다면 copy( ) 를 이용해야 한다.
# 색인
색인 중에 특이한 팬시 색인(fancy index)이 있다.
array([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.],
[4., 4., 4., 4.],
[5., 5., 5., 5.],
[6., 6., 6., 6.],
[7., 7., 7., 7.]])
위와 같이 배열이 있다고 가정하자. 이 중에 원하는 줄만 가져오고 싶을 때 사용하는 것이 팬시 색인이다.
arr[[6,4,2,7]]
------------------
array([[6., 6., 6., 6.],
[4., 4., 4., 4.],
[2., 2., 2., 2.],
[7., 7., 7., 7.]])
다음과 같이 불러오게 되면 원하는 줄의 값들만 따로 불러와 array 를 만든다.
# 전치
arr = np.arange(15).reshape(3,5)
arr
----------------------------------
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
arr.T
--------------------
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
계산을 할 때 전치행렬을 쓰는 경우가 있다. 이럴 때 쓰는 것이 T(Transpose) 이다.
행렬의 내적은 np.dot(arr.T, arr) 로 구할 수 있게 된다.
# 단위행렬
np.eye(4)
-----------------------
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]])
단위행렬이 필요할 때 사용하느느 것은 eye( ) 이다. 행과 열이 항상 같아야 하므로 필요한 파라미터는 한 개이다.
# random
(1) rand : 0 과 1 사이의 랜덤한 ndarray 가 생성된다.
np.random.rand(3,3)
-----------------------
array([[0.88499933, 0.56020496, 0.7523721 ],
[0.38443715, 0.28231815, 0.42155364],
[0.48028346, 0.06235042, 0.50708997]])
(2) randn : rand 함수에서 더 나아간 함수이다. n 은 정규분포라는 뜻으로 정규분포의 랜덤 ndarray 가 생성된다.
np.random.randn(3,3)
--------------------
array([[ 0.49133662, -0.40500377, 0.52077561],
[ 0.18060573, -1.20984827, -2.4968032 ],
[ 1.70030765, -0.19023195, -0.35498264]])
(3) randint : 출력되는 숫자가 정수값으로 나오게 된다.
np.random.randint(1,10, size = (3,3))
-------------------------------------
array([[7, 3, 6],
[6, 5, 5],
[8, 1, 8]])
(4) choice : 1차원 ndarray 로부터 랜덤으로 샘플링한다.
np.random.choice(100, size = (3,3))
--------------------------------------
array([[33, 77, 31],
[44, 12, 11],
[22, 80, 80]])
이러한 랜덤함수들을 실행할 때마다 값이 바뀌는데 바뀌고 싶지 않을 때 사용하는 것이 seed( ) 이다.
np.random.seed(33)
seed 의 숫자는 어떠한 크기도 상관없다. seed 를 실행하고 랜덤 함수를 실행한 것은 항상 같은 값이 나오는 것을 알 수 있다.
2. 배열 형태 바꾸기
배열 형태를 바꾸는 대표적인 함수는 reshape( ) 이다.
np.arange(20).reshape(4,5)
----------------------------
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
0 부터 19까지의 숫자를 4행 5열로 바꾼 형태이다.
그렇다면 다차원 배열을 다시 1차원 배열로 돌리려면 어떻게 해야할까.
num = np.arange(20).reshape(4,5)
num.ravel()
-----------------------------
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])
정답은 ravel( ) 을 사용하는 것이다. 하지만 이것만이 아니라 flatten( ) 도 사용 가능하다.
num.flatten()
--------------------------
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])
그렇다면 ravel 과 flattern 의 차이점이 있어야 한다.
ravel 은 원본 데이터에 영향을 미친다. 만약 num 의 배열이 변경되면 원본인 x 배열 또한 변경된다는 것이다.
이외에도 order 속성이 존재한다.
- C : 행 우선 정렬
- F : 열 우선 정렬
num.ravel(order='F')
--------------------------------
array([ 0, 5, 10, 15, 1, 6, 11, 16, 2, 7, 12, 17, 3, 8, 13, 18, 4,
9, 14, 19])
'데이터 분석 > 자료구조(Data structure)' 카테고리의 다른 글
파이썬 - Pandas 기초 정리(DataFrame - 2) (0) | 2020.12.23 |
---|---|
파이썬 - Pandas 기초 정리(DataFrame - 1) (0) | 2020.12.22 |
파이썬 - Pandas 기초 정리(Series) (0) | 2020.12.21 |
파이썬 - Numpy 기초 정리(2) (0) | 2020.12.17 |
[자료구조] Heap(힙) (0) | 2020.08.28 |