Go together

If you want to go fast, go alone. If you want to go far, go together.

파이썬 머신 러닝 완벽 가이드

Numpy

NowChan 2021. 10. 9. 09:57

배운 내용

1. nd.array()

2. ndarray.shape

3. ndarray.ndim

4. ndarray.dtype

5. ndarray.astype()

6. ndarray.arange(), ndarray.zeros(), ndarray.ones()

7. ndarray.reshape()

8. ndarray.tolist()

9. ndarray[i, j]

10. ndarray[i : j, k:l]

11. Fancy Indexing

12. Boolean Indexing

13. np.sort(), ndarray.sort()

14. np.argsort()

15. np.dot()

16. np.transpose()


Numpy의 특징

배열 연산에 특화됐다.

C/C++의 저수준 언어와의 호환 API를 제공한다.

 

import numpy as np
## np로 numpy를 표현

 

np.array & ndarray.shape

np.array(객체)
ndarray.shape > 튜플로 차원, 크기를 나타냄

ex)
## 1
array1 = np.array([1, 2, 3])
array1.shape
## (3, )

## 2
array2 = np.array([[1, 2, 3], [2, 3, 4]])
array2.shape
## (2, 3)

## 3
array3 = np.array([[1, 2, 3]])
array3.shape
## (1, 3)

1번: 1차원 array가 3개의 데이터를 가지고 있음

2번: 2차원 array가 2개의 Row, 3개의 Column 가지고 있음

3번: 2차원 array가 1개의 Row, 3개의 Column 가지고 있음

 

ndarray.ndim

ndarray.ndim은 차원을 리턴함

print('{:0}, {:1}, {:2}'.format(array1.ndim, array2.ndim, array3.ndim))
## 1, 2, 2

 

ndarray.dtype

list1=[1, 2, 3]
array1 = np.array(list1)
print(type(list1))
## <class 'list'>

print(array1.dtype)
## int32

data type은 숫자, 문자, 불 값 등이 모두 가능하다. 단, 같은 타입끼리의 연산만 예외 없이 된다. 다른 타입의 경우 데이터 크기가 더 큰 데이터 타입으로 일괄 형 변환을 한다.

list2 = [1, 2, 'test']
array2 = np.array(list2)
print(array2, array2.dtype)
## ['1', '2', 'test'] <U11

list3 = [1, 2, 3.0]
array3 = np.array(list3)
print(array3, array3.dtype)
## [1. 2. 3.] float64

대용량 데이터를 ndarray에 담을 때 많은 데이터 용량이 사용되는 경우 astype()로 메모리 용량을 아낄 수 있다. float64 데이터를 int32로도 충분한 경우 int32로 형 변환한다.

 

ndarray.astype()

array_int = np.array([1, 2, 3])
array_float = array_int.astype('float64')
print(array_float, array_float.dtype)
## [1. 2. 3.] float64

 

ndarray.arange(), ndarray.zeros(), ndarray.ones()

##ndarray.arange()
sequence_array = np.arange(10)
print(sequence_array)
''' [0 1 2 3 4 5 6 7 8 9] '''
print(sequence_array.dtype, sequence_array.shape)
''' int32 (10, ) '''

##ndarray.zeros()
zero_array = np.zeros((3, 2), dtype='int32')
print(zero_array)
'''  [[0 0]
      [0 0]
      [0 0]] '''

print(zero_array.dtype, zero_array.shape)
'''  int32 (3, 2) '''

## ndarray.ones() | default값은 float
ones_array = np.ones((3, 2))
print(ones_array)
print(ones_array.dtype, ones_array.shape)
'''  [[1. 1.]
      [1. 1.]
      [1. 1.]]
      float64 (3, 2) '''

 

ndarray.reshape()

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]]
'''

1차원 ndarray를 2차원 ndarray로 변환해 줍니다. 지정된 사이즈로 변경이 불가능하면 오류를 발생합니다.

ex) array4= array1.reshape(4, 3)

array2= array1.reshape(-1, 5)
print(array2.shape)
''' (2, 5) '''

reshape의 인자로 -1을 주면, 호환이 되는 ndarray를 반환해 줍니다. 물론, -1을 사용하더라도 호환될 수 없는 형태는 변환할 수 없습니다.

ndarray.reshape()의 쓰임 및 tolist()

array1 = np.arange(8)
array3d = array1.reshape((2,2,2))
print(array3d.tolist())
'''
 [[[0, 1], [2, 3]], [[4, 5], [6, 7]]]
'''

# 3차원 ndarray를 2차원 ndarray로 변환
array5 = array3d.reshape(-1, 1)
print(array5.tolist())
'''
 [[0], [1], [2], [3], [4], [5], [6], [7]]
'''
print(array5.shape)
''' (8, 1)'''

# 1차원 ndarray를 2차원 ndarray로 변환
array6 = array1.reshape(-1, 1)
print(array6.tolist())
'''
[[0], [1], [2], [3], [4], [5], [6], [7]]
'''

print(array6.shape)
''' (8, 1) '''

tolist()는 ndarray를 list로 변환해 출력해준다.


Indexing

단일 값 추출 : ndarray[i]

array1 = np.arange(start=1, stop=10)
print(array1)
''' [1 2 3 4 5 6 7 8 9] '''

value = array1[2]
print(value, type(value))
''' 3 numpy.int32 '''

print(array1[-1], array1[-2])
''' 9 8 '''

array1[0] = 9
array1[8] = 0
print(array1)
''' [9 2 3 4 5 6 7 8 0] '''

인덱스 -1은 맨 뒤의 데이터 값, -2는 맨 뒤에서 두 번째에 있는 값을 의미합니다.

인덱스를 통한 접근으로 리스트 값을 수정할 수 있다.

2차원 단일 값 추출 : ndarray[i, j]

array1d = np.arange(start=1, stop=10)
arrat2d = array1d.reshape(3, 3)
print(array2d)
''' 
      [[1 2 3]
       [4 5 6] 
       [7 8 9]]
'''

print(array2d[0,0])
''' 1 '''
print(array2d[1,0])
''' 4 '''
print(array2d[2,2])
''' 9 '''

row 방향의 축은 axis0, column 방향의 축은 axis1을 의미합니다.

차원이 늘어날 때 그 축의 방향은 axis2, axis3 ... 를 의미하게 됩니다.

즉, ndarray[ axis0으로 i, axis1으로 j ]를 의미합니다.

슬라이싱 : ndarray[i : j]

array1 = np.arange(start=1, stop=10)
array3 = array1[0:3]
print(array3)
''' [1 2 3] '''

print(type(array3))
''' <class 'numpy.ndarray'> '''

array4 = array1[3:]
print(array4)
''' [4 5 6 7 8 9] '''

array5 = array1[:3]
print(array5)
''' [1 2 3] '''

array6 = array1[:]
print(array6)
''' [1 2 3 4 5 6 7 8 9] '''

슬라이싱에서 [:]의 빈자리는 위와 같은 방식으로 인식한다.

2차원 슬라이싱 : ndarray[i : j, k:l]

array1d = np.arange(start=1, stop=10)
arrat2d = array1d.reshape(3, 3)
print(array2d)
'''
   [[1 2 3]
    [4 5 6]
    [7 8 9]]
'''

print(array2d[1:3, 0:3])
''' [[4 5 6]
     [7 8 9]]
'''
print(array2d[1:3, :])
'''  [[4 5 6]
      [7 8 9]]
'''

print(array2d[:2, 1:])
'''  [[2 3]
      [5 6]]
'''

# special case
print(array2d[:2, 0])
''' [1 4] '''

print(array2d[0])
''' [1 2 3] '''

print(array2d[1])
''' [4 5 6] '''

print(array2d[0].shape, array2d[1].shape)
''' (3, ) (3, ) '''

n차원 슬라이싱의 경우 단일 인덱스를 섞어 쓸 수 있다.

2차원 ndarray의 경우 뒤에 오는 index를 없애면, axis0(Row) 축의 Row를 반환하게 됩니다.

2차원 ndarray는 1차원을 반환하고, 3차원을 2차원을 ..

Fancy Indexing

array1d = np.arange(start=1, stop=10)
arrat2d = 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, 1], 0:2]
print(array4.tolist())
'''
[[1, 2], [4, 5]]
'''

array5 = array2d[[0, 1]]
print(array5.tolist())
'''
[[1, 2, 3], [4, 5, 6]]
'''

# 추가
print(array([5, 6, 7, 8]))
''' [6 7 8 9]  '''

Row나 Col 자리에 list나 ndarray를 넣어도 위치에 해당하는 ndarray를 반환하는 것을 말한다.

array5의 경우, array2d[[0, 1]]는 ((0, :), (1, :)) 인덱싱이 적용돼 [[1, 2, 3], [4, 5, 6]]을 반환합니다. 즉, Row=0, Row=1의 2차원 배열이 반환됩니다.

Boolean indexing

array1d = np.arange(start=1, stop=10)
array3 = array1d[array1d > 5]
print(array3)
''' [6 7 8 9] '''

array1d > 5
''' array([False False False False False  True  True  True  True]) '''
# ndarray 객체가 반환됨에 주의

'''
Step 1.
array1d(array([False False False False False  True  True  True  True]))

Step 2.
array1d([5, 6, 7, 8]) => Fancy Indexing 참조

Step 3.
[6, 7, 8, 9]
'''

Step 1. ndarray[ 조건 ]은 array1d > 5를 예로 들면, 예제와 같은 boolean이 담긴 ndarray가 반환된다.

Step 2. True 값에 해당하는 인덱스값만 저장한다.

Step 3. 저장된 인덱스 데이터 세트로 ndarray를 조회한다.

 

행렬의 정렬

 

np.sort(), ndarray.sort()

# np.sort()
org_array = np.array([3, 1, 9, 5])
print(org_array)
''' 
[3 1 9 5]
'''

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()
print(sort_array2)
''' None '''
print(org_array)
''' [1 3 5 9] '''

# 내림차순 정렬 [::-1]
sort_array1_desc = np.sort(org_array)[::-1]
print(sort_array1_desc)
''' [9 5 3 1] '''

np.sort()는 원본은 그대로 두고 정렬된 복사본을 반환한다. 

ndarray.sort()는 원본을 정렬한다.

내림차순으로 정렬하려면 [::-1]을 뒤에 붙인다.

 

2차원 행렬의 정렬 (n차원 행렬)

arrat2d = np.array([[8, 12], 
                    [7, 1]])
sort_array2d_axis0 = np.sort(array2d, axis=0)
print(sort_array2d_axis0)
''' 
      [[7 1]
       [8 12]]
'''

sort_array2d_axis1 = np.sort(array2d, axis=1)
print(sort_array2d_axis1)
'''
      [[8 12]
       [1 7]]
'''

axis값을 뒤에 인자로 넣어주면, 그 방향으로 정렬된 n차원 배열이 반환된다.

 

argsort()

org_array = np.array([ 3, 1, 9, 5])
sort_indices = np.argsort(org_array)
print(type(sort_indices))
'''
<class 'numpy.ndarray'>
'''
print(sort_indices)
'''
[1 0 3 2]
'''

# 내림차순
sort_indices2 = np.argsort(org_array)[::-1]
print(sort_indices2)
'''
[2 3 0 1]
'''

argsort는 정렬된 행렬에 대해 원본 행렬의 index를 ndarray형으로 반환한다.

[3, 1, 9, 5]의 index는 [0 , 1, 2, 3]

정렬된 [1, 3, 5, 9]의 원본 index는 [1, 0, 3, 2]

 

argsort() 활용

import numpy as np

name_array = np.array(['John', 'Mike', 'Sarah', 'Kate', 'Samuel'])
score_array = np.array([78, 95, 84, 98, 88])

sort_indices_asc = np.argsort(score_array)
print(sort_indices_asc)
'''
[0 2 4 1 3]
'''
print(score_array[sort_indices_asc])
'''
[78 84 88 95 98]
'''
print(name_array[sort_indices_asc])
'''
['John' 'Sarah' 'Samuel' 'Mike' 'Kate']
'''

Numpy는 Pandas의 DataFrame 칼럼이나 RDBMS의 TABLE 칼럼과 같은 메타 데이터를 가질 수 없다. 실제 값과 그 값이 뜻하는 메타 데이터를 별도로 ndarray에 저장해야한다. 위의 예시를 보면, 학생의 이름과 성적을 각각 별도의 ndarray에 담은 것을 볼 수 있다. 이때 argsort()가 유용하게 쓰인다.

 

선형대수 연산

 

행렬 내적 (행렬 곱) 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]]
'''

 

전치 행렬 np.transpose()

A = np.array([[1, 2],
              [3, 4]])            
transpose_mat = np.transpose(A)
print(transpose_mat)
'''
[[1 3]
 [2 4]]
'''

 

그 외에 궁금한 점

array1d = np.arange(start=1, stop=10) 
arrat2d = array1d.reshape(3, 3) 

## special case 
print(array2d[:2, 0]) 
## [1 4]

special case의 경우, [[1], [4]]가 아닌 [1 4]가 된다. 이유는 잘 모르겠다. [[1 4]]면 이해 했다.

 

출처: 파이썬 머신러닝 완벽 가이드 (권민철)

'파이썬 머신 러닝 완벽 가이드' 카테고리의 다른 글

피마 인디언 당뇨병 예측  (0) 2021.11.05
평가  (0) 2021.10.27
타이타닉 생존자 예측  (0) 2021.10.20
사이킷런 scikit-learn  (0) 2021.10.15
Pandas  (0) 2021.10.10