[기초 라이브러리 사용 설명서] Numpy

bucket yang ·2023년 11월 24일
0

Python 데이터 분석

목록 보기
2/5

1. Numpy란

선형대수 기반 프로그램을 가능하게 하는 대표적인 파이썬 라이브러리로, 빠른 계산과 배열 연산 능력을 보장한다.

선형대수는 머신러닝의 주요 알고리즘 중 하나이며 많은 머신러닝 알고리즘은 넘파이를 기반으로 하기에 넘파이에 익숙해지는 것이 매우 중요하다.

2. ndarray 데이터 구조

(1) 다차원 배열

  • 다차원 배열을 지원한다.
  • 1차원 배열은 벡터, 2차원 배열은 행렬을 나타낸다. 이 때 행과 열의 수를 튜플 형태로 가진다.

(2) 고정된 데이터 타입

  • 배열의 모든 요소가 동일한 크기를 가지고 있다.

(3) 효율적인 연산

  • 벡터화 연산을 통해 반복문을 사용하지 않고 전체 배열에 대한 연산을 수행한다.

(4) 브로드캐스팅

  • 서로 다른 shape의 배열 간에도 일부 연산이 가능하도록 하는 기능이 있다.
  • 작은 배열이나 스칼라 값이 자동으로 큰 배열에 맞춰진다.

(5) 인덱싱, 슬라이싱

(6) 선형 대수 연산

3. np.array()

리스트와 같은 다양한 인자를 입력 받아서 ndarray로 변환하는 기능을 수행한다.
shape로 배열의 모양을 확인할 수 있으며 ndarray의 행과 열의 수는 튜플 형태이다.

a = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
a.shape
#(1, 3, 3)

4. 생성

numpy는 다차원 배열을 다루기 위한 강력하고 효율적인 데이터 구조 ndarray를 생성할 수 있다.
파이썬 리스트로 다차원 배열을 생성하거나 내장 함수를 이용할 수 있다.

(1) arange()

0부터 함수 인자 값 - 1 까지의 값을 순차적으로 ndarray의 데이터 값을 변환한다.

seq_array = np.arange(10)
print(seq_array, type(seq_array))

out[]: [0 1 2 3 4 5 6 7 8 9] numpy.ndarray

(2) zeros()

모든 값을 0으로 채운 배열을 만든다.

zero1 = np.zeros((2,4))

out[]: array([[0., 0., 0., 0.],[0., 0., 0., 0.]])

(3) ones()

모든 값을 1로 채운 배열을 만든다.

one1 = np.ones((2,4))

out[]: array([[1., 1., 1., 1.], [1., 1., 1., 1.]])

(4) random.randn()

인자만큼의 랜덤한 숫자 배열을 만든다. 인자에서 중첩 괄호는 사용할 수 없다.

random = np.random.randn(2,4)

out[]: array([[-0.48832617, -1.36402212, -1.05448545, 0.54592232],
[-0.71801095, -0.62745696, 1.47853492, 1.15583403]])

5. 속성

(1) dtype

dtype 함수로 데이터 타입 속성을 확인할 수 있다.

Numpy에서 사용되는 주요 데이터 타입은 다음과 같다.

  • int
  • float
  • str
  • bool
a.dtype
#dtype('int64')

ndarray는 동일한 데이터 타입을 가져야 한기 때문에, 만약 다양한 데이터 타입을 갖는 배열이 연산하는 경우에는 가장 범용적인 데이터 타입으로 자동 변환된다.

만약 리스트 내에 int형 값과 문자열이 섞여 있는 리스트 array2를 ndarray로 변환한 후 dtype을 출력해보면, 'U21'과 같은 문자열이 출력된다.
이는 유니코드 문자열을 나타내는 데이터 타입인데, 최대 길이가 21인 유니코드 문자열을 나타낸다.

(2) astype()

메모리를 절약해야 할 때 astype() 함수를 사용하여 ndarray 내 데이터 값들의 타입을 변경할 수 있다.

list1 = np.array([1.5, 2.4, 3.7])
print(list1.dtype)
float_list1 = list1.astype('int64')
print(float_list1.dtype)

out[]:
float64
int64

(3) reshape()

ndarray를 특정 차원 및 크기로 변환한다. 인자로 지정된 사이즈 변경이 불가능할 때 오류가 발생한다.

seq_array = np.arange(10)
print(seq_array.reshape(2,5))

out[]: [[0 1 2 3 4][5 6 7 8 9]]

reshape(-1, 1)을 통해 차원을 변경할 수도 있다.
아래 코드에서 array3d의 차원을 2차원 (2,2,2)에서 1차원 (8,1)으로 축소한 것을 볼 수 있다.

seq_array = np.arange(8)
array3d = seq_array.reshape((2,2,2))
print(array3d)
array2d = array3d.reshape(-1,1)
print(array2d)

out[] : [[[0 1][2 3]] [[4 5][6 7]]] [[0][1] [2][3] [4][5] [6][7]]

(4) T

6. 연산

numpy의 연산은 각 원자의 값에 연산을 처리하지 않고, 배열에 연산을 처리하면 배열 안에 있는 각 값들에게 일괄로 연산이 처리가 된다. 이를 벡터화라고 한다.

arr = np.arange(10)
arr + 2

out[]: array([ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])

7. 비교

다차원 배열의 비교는 불리언 배열을 반환한다. 아래 코드와 같이 특정 데이터를 조회할 수 있다.

arr < 5

out[]: array([ True, True, True, True, True, False, False, False, False, False])

8. 조회 (인덱싱)

(1) 단일 값 추출

객체에 해당하는 위치의 인덱스 값을 [] 안에 입력한다.

array1 = np.arange(start=1, stop=10)

array1[3]

out[]: 4

다차원에서 단일 값을 추출할 수 있다.


array2 = array1.reshape(3, 3)
print('1행 1열 값: ', array2[0, 0])

out[]: 1행 1열 값: 9

(2) 슬라이싱

':'를 사용하여 연속 데이터를 추출한다.

arr = np.arange(10)

arr[3:9]

out[]: array([3, 4, 5, 6, 7, 8])

(3) 2차원 ndarray 슬라이싱

2차원 ndarray에서 슬라이싱으로 데이터에 접근할 때는 콤마(,)로 행과 열 인덱스를 지칭한다.

arr= np.arange(start = 1, stop= 10)
arr2 = arr.reshape(3,3)
arr2[0:2]

out[]: array([[1, 2, 3], [4, 5, 6]])

arr= np.arange(start = 1, stop= 10)
arr2 = arr.reshape(3,3)
arr2[0:3, 1:3]

out[]: array([[2, 3], [5, 6], [8, 9]])

arr= np.arange(start = 1, stop= 10)
arr2 = arr.reshape(3,3)
arr2[1:, :2]

out[]: array([[4, 5], [7, 8]])

arr= np.arange(start = 1, stop= 10)
arr2 = arr.reshape(3,3)
arr2[:3, 0]

out[]: array([1, 4, 7])

(4) 팬시 인덱싱

arr= np.arange(start = 1, stop= 10)
arr2 = arr.reshape(3,3)
arr2[[0]]

out[]: array([[1, 2, 3]])

arr= np.arange(start = 1, stop= 10)
arr2 = arr.reshape(3,3)
arr2[[0,2]]

out[]:

array([[1, 2, 3],
[7, 8, 9]])

arr= np.arange(start = 1, stop= 10)
arr2 = arr.reshape(3,3)
arr2[[0,2], 1]

out[]: array([2, 8])

arr= np.arange(start = 1, stop= 10)
arr2 = arr.reshape(3,3)
arr2[[0,2], 0:2]

out[]:

array([[1, 2],
[7, 8]])

9. 치환

arr_2d = np.array([[1, 2], ['a', 'b']])
print(arr_2d)
arr_2d[1][1] = 'K'
print(arr_2d)

out[]:

[['1' '2']['a' 'b']]

[['1' '2']['a' 'K']]

arr = np.arange(start=1, stop=10)
arr[arr < 5] = 10
print(arr)

out[]: [10 10 10 10 5 6 7 8 9]

10. 행렬의 정렬

(1) np.sort()

원본 행렬은 그래도 유지한 채 정렬된 행렬을 반환한다.

arr = np.arange(start=1, stop=10)
arr[arr < 5] = 10

arr_sort = np.sort(arr)
print(arr_sort)
print(arr)

out[]:

[ 5 6 7 8 9 10 10 10 10][10, 10, 10, 10, 5, 6, 7, 8, 9]

(2) ndarray.sort()

원본 행렬 자체를 정렬하기에 반환 값은 None이다.

arr = np.arange(start=1, stop=10)
arr[arr < 5] = 10

print(arr)

arr.sort()
print(arr)

out[]:

[10 10 10 10 5 6 7 8 9][ 5 6 7 8 9 10 10 10 10]

(3)axis 축 값 설정

행렬 정렬을 수행하기 위해서 axis 축 값을 설정해야 한다.

  • axis = 0 -> 행 방향

아래 코드에서 첫 번째 행을 정렬하면 [1,7], 두 번째 행을 정렬하면 [2,6] 이기 때문에 최종적으로 정렬된 배열은 [[1, 7], [2, 6]] 이다.

array2 = np.array([[7, 1], [2, 6]])
print(np.sort(array2, axis = 0))

out[]: [[1, 7], [2, 6]]

  • axis = 1 -> 열 방향

아래 코드에서 첫 번째 열 [7,2]를 정렬하면 [2,7], 두 번째 행을 정렬하면 [1,6] 이기 때문에 최종적으로 정렬된 배열은 [[2, 1], [7, 6]] 이다.

array2 = np.array([[7, 1], [2, 6]])
print(np.sort(array2, axis = 1))

out[]: [[2, 1], [7, 6]]

(4) np.argsort()

정렬된 행렬의 인덱스를 반환한다.

org_array = np.array([4, 2, 8, 6])
np.argsort(org_array)

out[]: array([1, 0, 3, 2])

11. 선형대수 연산

(1) np.dot()

행렬의 내적을 구하기 위해서 np.dot() 함수를 사용한다.

아래 코드에서 a는 2 x 3 행렬이며, b는 3 x 2 행렬이다.
(내적의 조건: 첫 번째 행렬의 열 수가 두 번째 행렬의 행 수와 같아야 한다.)

행렬내적의 계산 과정은 다음과 같다.

[1, 2, 3][7, 9, 11] = 1 7 + 2 9 + 3 11 = 58
[1, 2, 3]
[8, 10, 12] = 1 8 + 2 10 + 3 12 = 64
[4, 5, 6]
[7, 9, 11] = 4 7 + 5 9 + 6 11 = 139
[4, 5, 6]
[8, 10, 12] = 4 8 + 5 10 + 6 * 12 = 154

a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[7, 8], [9, 10], [11, 12]])
print(np.dot(a,b))

out[]:

[[ 58 64][139 154]]

(2) np.transpose()

np.transpose() 함수는 원 행렬에서 행과 열의 위치를 교환한 행렬을 반환한다.

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

out[]:

array([[1, 3],
[2, 4]])

12. 배열 간 사칙연산

배열 내 같은 위치의 원소끼리 연산을 한다.

a = np.array([[11, 12, 13], [2, 3, 4]])
a+a

out[]:
[[22 24 26][ 4 6 8]]

13. broadcasting

동일한 배열 모양을 가진 서로 다른 배열끼리도 연산이 가능하다.

이 때 배열의 모양은 동일해야 한다. 동일하지 않으면 "ValueError: operands could not be broadcast together with shapes "과 같은 에러가 뜨게 된다.

더하기 이외에 빼기, 곱하기, 나누기 등 사칙연산이 모두 가능하다.

a = np.array([[11, 12, 13], [2, 3, 4]])
a+3

out[]:

array([[14, 15, 16],
[ 5, 6, 7]])

a = np.array([[11, 12, 13], [2, 3, 4]])
b = np.array([[2, 3, 4], [11, 12, 13]])
a+b

out[]:

array([[13, 15, 17],
[13, 15, 17]])

14. 집계

(1) sum()

(2) mean()

(3) prod()

(4) max(), min()

(5) std(), var()

0개의 댓글