넘파이-Numpy-Numerical python
머신러닝의 대부분 알고리즘-선형대수, 통계 기반.
- >넘파이는 배열 기반의 빠른 연산 및 다양한 데이터 핸들링 기능을 제공.
넘파이 ndarray 개요 (p.14)
넘파의의 기반 데이터 타입은 ndarray.
이 ndarray를 이용하여 다차원 배열을 쉽게 생성하고, 다양한 연산을 수행.
이러한 ndarray는 넘파이의 array()함수를 이용하여 생성함.
생성된 ndarray배열의 shape변수는 ndarray의 크기(행과 열의수)를 튜플 형태로 가지고있으며 이를 통해 ndarray배열의 차원을 확인할 수 있다.
ndarray.shape는 ndarray의 차원과 크기를 튜플형태로 나타내준다.
→ 쉽게 생각하면, 리스트 한개로 구성되어 있으면 1차원, 리스트 안에 리스트로 되어있으면 2차원, 리스트안에 리스트안에 리스트 이러면 3차원.
import numpy as np
array1=np.array([1,2,3,4])
print(type(array1))
print(array1.shape)
>> <class 'numpy.ndarray'>
>> (4,)
array2=np.array([[1,2,3],[4,5,6]])
print(type(array2))
>> <class 'numpy.ndarray'>
>> (2, 3)
array3=np.array([[[1,2,0,0],[3,4,0,0],[5,6,0,0]],[[7,8,0,0],[9,10,0,0],[11,12,0,0]]])
print(type(array3))
print(array3.shape)
>> <class 'numpy.ndarray'>
>> (2, 3, 4)
Ndarray의 데이터 타입 (p.16)
ndarray내의 데이터값은 숫자, 문자열, 불형 모두 가능하다.
또한 숫자의 경우 int형(8,16,32 bit), unsigned int형(8,16,32 bit), float형(16,32,64,128 bit) complex 타입 모두 가능하다.
리스트와는 다르게 이러한 ndarray내의 데이터 타입은 같은 데이터 타입만 존재할 수 있다.
→ 이 때 다른타입의 데이터를 ndarray로 생성하면, 데이터 크기가 더 큰 데이터 타입으로 형 변환을 일괄적으로 적용한다.
즉, int와 float 형과 같이 다른 데이터 타입은 같이 있을 수 없다. 이러한 ndarray내의 데이터 타입은 dtype 속성으로 확인할 수 있다.
list1=[1,2,3]
print("list1의 타입은:",type(list1))
array1=np.array(list1)
print("array1의 타입은:",type(array1))
print("array1의 데이터 타입은:",array1.dtype)
>> list1의 타입은: <class 'list'>
>> array1의 타입은: <class 'numpy.ndarray'>
>> array1의 데이터 타입은: int32
list2=[1,2,'3']
array2=np.array(list2)
print("array2의 데이터 타입은:",array2.dtype)
>> array2의 데이터 타입은: <U11
list3=[1,2,3.0]
array3=np.array(list3)
print("array3의 데이터 타입은:",array3.dtype)
>> array3의 데이터 타입은: float64
바로 위의 예시처럼, int형과 문자형을 섞었을 때의 dtype은 문자형으로, int형과 float형을 섞었을 때의 dtype은 float형이 나오게 된다.
또한 이러한 ndarray의 데이터 타입을 강제로 변경할 수 있는데 artype()함수를 사용하면 된다.
이는 불필요한 데이터의 메모리를 아낄 때 사용된다.
ndarray를 편리하게 생성하기 -arange, zeros, ones (p.18)
특정 크기와 차원을 가진 ndarray를 임의의 연속값,0 혹은 1로 생성해야할 경우도 있다.
이럴 때 일일이 원소값을 적는게 아니라 arange,zeros,ones 함수를 이용하여 쉽게 생성할 수 있다.
arange()
arange()함수는 파이썬의 표준 함수 range()와 유사하게, 0부터 n-1까지의 값을 순차적으로 ndarray로 생성해준다.
시작값의 default는 0이나, 직접 정해줄 수도 있다.
sequence_array=np.arange(10)
print(sequence_array)
print(sequence_array.dtype,sequence_array.shape)
>> [0 1 2 3 4 5 6 7 8 9]
>> int32 (10,)
sequence_array2=np.arange(5,9)
print(sequence_array2)
print(sequence_array2.dtype,sequence_array2.shape)
>> [5 6 7 8]
>> int32 (4,)
zeros(), ones()
zeros()함수는 이름에서 알 수 있듯이 인자에 튜플형태의 shape값을 입력하면 모든 원소가 0인 해당 shape의 ndarray를 반환해준다. dtype을 정해주지 않으면 default값인 float64형의 데이터로만들어주고, 혹은 지정해줄 수 있다.
이와 동일하게 ones()함수는 1로 채워서 출력을 해준다.
zero_array=np.zeros((3,2),dtype='int32')
print(zero_array)
print(zero_array.dtype, zero_array.shape)
>> [[0 0]
[0 0]
[0 0]]
>> int32 (3, 2)
one_array=np.ones((3,2))
print(one_array)
print(one_array.dtype, one_array.shape)
>> [[1. 1.]
[1. 1.]
[1. 1.]]
>> float64 (3, 2)
Ndarray의 차원과 크기를 변경하는 reshape() (p.20)
reshape() 메서드는 ndarray를 특정 차원 및 크기로 변경할 수 있다.
현재 만들어진 ndarray로 불가능한 사이즈로 변경을 시도하면 에러가 난다.
이 때, -1을 인자로 사용하면 자동으로 현재 ndarray와 맞는 사이즈의 값으로 치환되서 사용된다.
array1=np.arange(10)
print(array1)
>> [0 1 2 3 4 5 6 7 8 9]
array2=array1.reshape(2,5)
print(array2)
>> [[0 1 2 3 4]
[5 6 7 8 9]]
array3=array1.reshape(5,2)
print(array3)
>> [[0 1]
[2 3]
[4 5]
[6 7]
[8 9]]
array4=array1.reshape(-1,5)
print(array4)
>> [[0 1 2 3 4]
[5 6 7 8 9]]
또한 ndarray를 보기 편하게, tolist()함수를 써서 리스트 형태로 표현할 수도 있다
array1=np.arange(10).reshape(2,5)
print(array1)
>> [[0 1 2 3 4]
[5 6 7 8 9]]
print(array1.tolist())
>> [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
넘파이의 ndarray의 데이터 세트 선택하기 -인덱싱(Indexing) (p.23)
- 특정한 데이터만 추출 → 원하는 위치의 인덱스 값을 지정하여 해당 위치의 데이터 반환.
또한 마이너스 기호를 이용하면 끝에서부터 인덱싱을 함. 단 -1부터 시작(-1은 제일 마지막 원소를 뜻함)
이차원, 삼차원의 경우 리스트안에 각 row, col을 써주면 됨
array1=np.arange(1,10)
print(array1)
>> [1 2 3 4 5 6 7 8 9]
value=array1[2] # 인덱스는 0부터 시작. 따라서 3번째 숫자.
print(value)
>> 3
value2=array1[-2] # 끝에서 2번째
print(value2)
>> 8
array2=np.arange(1,11).reshape(2,5)
print(array2)
>> [[ 1 2 3 4 5]
[ 6 7 8 9 10]]
value3=array2[1,1] # 두번째 행 두번째 열을 의미 (0이 시작이니까 1은 두번째임)
print(value3)
>> 7
- 슬라이싱→ 연속된 인덱스 상의 ndarray를 추출 start~end-1까지의 위치에 있는 ndarray 반환
‘:’ 기호를 이용하여 [start:end]형식으로 사용.
→ ‘:’ 기호 앞에 시작 인덱스를 생략하면 default=0으로 간주
→ ‘:’ 기호 뒤에 종료 인덱스를 생략하면 default=제일마지막으로 간주
→ ‘:’ 기호 앞뒤에 인덱스를 생략하면 자동으로 데이터 전체로 간주
array1=np.arange(1,10)
print(array1)
>> [1 2 3 4 5 6 7 8 9]
array2=array1[1:3]
print(array2)
>> [2 3]
array3=array1[:4]
print(array3)
>> [1 2 3 4]
array4=array1[1:5]
print(array4)
>> [2 3 4 5]
array5=array1[:]
print(array5)
>> [1 2 3 4 5 6 7 8 9]
이러한 슬라이싱은 다차원 ndarray에서도 가능하다.
array1d = np.arange(start=1, stop=10)
array2d = array1d.reshape(3,3)
print('array2d:\n',array2d)
>> array2d:
[[1 2 3]
[4 5 6]
[7 8 9]]
print(array2d[0:2, 0:2])
>>[[1 2]
[4 5]]
print(array2d[1:3, 0:3])
>>[[4 5 6]
[7 8 9]]
print(array2d[1:3, :])
>> [[4 5 6]
[7 8 9]]
print(array2d[:, :])
>> [[1 2 3]
[4 5 6]
[7 8 9]]
print(array2d[:2, 1:])
>> [[2 3]
[5 6]]
print(array2d[:2, 0])
>> [1 4]
- 팬시 인덱싱 → 일정한 인덱싱 집합을 리스트 또는 ndarray 형태로 지정해 해당 위치에 있는 데이터의 ndarray를 반환
- 으산 첫번째 array3의 경우, row는 0번째와 1번째를 선택하고, col은 2열을 선택했을므로,
- row 0번째 1번째는 [1,2,3],[4,5,6]을 가리키고 여기서 또 2열이므로, 3과 6을 반환한다.
array1d = np.arange(start=1, stop=10)
array2d = array1d.reshape(3,3)
print(array2d)
>> [[1 2 3]
[4 5 6]
[7 8 9]]
array3 = array2d[[0,1], 2]
print(array3.tolist())
>> [3, 6]
array4 = array2d[[0,2], 0:2]
print(array4.tolist())
>> [[1, 2], [7, 8]]
array5 = array2d[[0,1]]
print(array5.tolist())
>> [[1, 2, 3], [4, 5, 6]]
- 불린 인덱싱 → 특정 조건에 해당하는 여부 bool로 확인하여 True에 해당하는 위치에 있는 데이터의 ndarray를 반환
아래와 같이 조건문에 True에 해당하는 값들만반환되는 것을 볼 수 있다.
array1d = np.arange(start=1, stop=10)
print(array1d)
print(array1d > 5)
>> [1 2 3 4 5 6 7 8 9]
>> [False False False False False True True True True]
array2 = array1d[array1d > 5]
print(array2)
>> [6 7 8 9]
행렬의 정렬-sort()와 argsort() (p.33)
정렬
넘파이에서 행렬을 정렬하는데 여러가지 방법이 있는데 np.sort(0 / ndarray.sort() 그리고 정렬된 행렬의 인덱스를 반환하는 argsort()가 있다.
우선 np.sort와 ndarray.sort의 차이점은, np.sort()의 경우는 원행렬을 그대로 보존한 채, 정렬된 행렬을 반환해준다.
ndarray.sort()의 경우는 원 행렬 자체를 정렬하고, 반환값은 none이다. 따라서 이때 ndarray.sort()를 변수에 대입해줘서는 안된다.
org_array = np.array([ 3, 1, 9, 5])
print(org_array)
>> [3 1 9 5]
# np.sort( )로 정렬
sort_array1 = np.sort(org_array)
print (sort_array1)
>> [1 3 5 9]
print(org_array)
>> [3 1 9 5]
# ndarray.sort( )로 정렬
sort_array2 = org_array.sort()
org_array.sort()
print(sort_array2)
>> None
print(org_array)
>> [1 3 5 9]
이렇게 정렬된 행렬은 기본적으로 오름차순으로 정렬된다. 이를 내림차순으로 정렬하기 위해서는 끝에 [::-1]을 붙여주면 된다.
org_array = np.array([ 3, 1, 9, 5])
print(org_array)
>> [3 1 9 5]
sort_array1_desc = np.sort(org_array)[::-1]
print (sort_array1_desc)
>> [9 5 3 1]
행렬이 2차원 이상일 경우에는 axis 축 값 설정을 통해 row방향 혹은 column 방향으로 정렬을 수행할 수 있다.
정렬 인덱스 반환
원본 행렬이 정렬되었을 때, 기존 원본 행렬의 원소에 대한 인덱스가 필요할 때 np.argsort()를 이용한다.
np.argsort()는 위에서 설명한 것 처럼 정렬행렬의 원본 행렬의 인덱스를 반환해준다.
org_array = np.array([ 3, 1, 9, 5])
print(np.sort(org_array))
>> [1 3 5 9]
sort_indices = np.argsort(org_array)
print(type(sort_indices))
>> <class 'numpy.ndarray'>
print(sort_indices)
>> [1 0 3 2]
선형대수 연산 - 행렬 내적과 전치행렬 구하기 (p.37)
행렬 내적은 행렬 곱이며, 두 행렬 A와 B의 내적은 np.dot()을 이용하여 계산이 가능하다.
A = np.array([[1, 2, 3],[4, 5, 6]])
B = np.array([[7, 8],[9, 10],[11, 12]])
dot_product = np.dot(A, B)
print( dot_product)
>> [[ 58 64]
[139 154]]
전치행렬의 경우 원 행렬에서 행과 열 위치를 교환한 것을 말한다.
이는 넘파이의 transpose()를 이용하여 쉽게 구할 수 있다. (사실 전치행렬의 경우 원 행렬 뒤에 .T를 붙여줘도 나온다.)
A = np.array([[1, 2], [3, 4]])
print(A)
>>[[1 2]
[3 4]]
transpose_mat = np.transpose(A)
print(transpose_mat)
>> [[1 3]
[2 4]]
print(A.T)
>> [[1 3]
[2 4]]
'ML & DL > 파이썬 머신러닝 완벽 가이드' 카테고리의 다른 글
파이썬 머신러닝 완벽 가이드 Day 3 (데이터 핸들링 판다스) (0) | 2023.11.16 |
---|---|
파이썬 머신러닝 완벽 가이드 Day 2 (데이터 핸들링-판다스) (0) | 2023.11.16 |