4 분 소요

2. 넘파이

  • 넘파이의 기반 데이터 타입 : ndarray
  • ndarray를 이용해 넘파이에서 다차원 배열을 쉽게 생성하고 다양한 연산을 수행할 수 있다.

image

1) ndarray 생성

import numpy as np

array1 = np.array([1,2,3])
print(type(array1))
print(array1.shape)
----------------------------
<class 'numpy.ndarray'>
(3,)     : 1차원 array로 3개의 데이터를 가지고 있음을 뜻함
array2 = np.array([[1,2,3],[2,3,4]])
print(type(array2))
print(array2.shape)
----------------------------
<class 'numpy.ndarray'>
(2, 3)     : 2차원 array로 2개의 로우와 3개의 칼럼으로 구성되어 있음을 뜻함
array3 = np.array([[1,2,3]])
print(type(array3))
print(array3.shape)
----------------------------
<class 'numpy.ndarray'>
(1, 3)       : 2차원 array로 1개의 로우와 3개의 칼럼으로 구성되어 있음

2) ndim : ndarray의 차원 확인

print(array2.ndim)
----------------------------
2

3) ndarray의 데이터 타입

  • ndarray 내의 데이터 값은 숫자 값, 문자열 값, 불 값 등 모두 가능
  • 숫자형
    • int형 (8bit, 16bit, 32bit)
    • unsigned int형 (8bit, 16bit, 32bit)
    • float 형(16bit, 32bit, 64bit, 128bit)
    • 더 큰 숫자 값이나 정밀도 → complex 타입
  • ndarray 내의 데이터 타입은 연산의 특성상 같은 데이터 타입만 가능함. 즉, 한 개의 ndarray 객체에 int와 float가 함께 있을 수 없다.
  • dtype : ndarray의 데이터 타입 확인

      list1 = [1,2,3]
      print(type(list1))
        
      array1 = np.array(list1)
      print(type(array1))
      print(array1.dtype)
        
      ------------------------
      <class 'list'>
      <class 'numpy.ndarray'>
      int32
    
  • 만약 다른 데이터 유형이 섞여있는 리스트를 ndarray로 변경하면 데이터 크기가 더 큰 데이터 타입으로 형 변환을 일괄 적용한다.

      list2 = [1, 2, 'test']
      array2 = np.array(list2)
      print(array2.dtype)
      print(array2)
      ---------------------------
      <U11
      ['1' '2' 'test']
    
      list3 = [1, 2, 3.0]
      array3 = np.array(list3)
      print(array3.dtype)
      print(array3)
      ---------------------------
      float64
      [1. 2. 3.]
    

4) ndarray 형변환

  • ndarray 내 데이터 값의 타입을 변경할 수 있다.
array_int = np.array([1,2,3])
array_float = array_int.astype('float64')
print(array_float, array_float.dtype)
------------------------------------------
[1. 2. 3.] float64
array_float1 = np.array([1.1,2.1,3.1])
array_int1 = array_int.astype('int32')
print(array_int1, array_int1.dtype)
-------------------------------------------
[1 2 3] int32

5) ndarray를 편리하게 생성하기

  • arange(x) : 0부터 x까지의 값을 순차적으로 담는다.

      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_array = np.arange(2, 10)
      print(sequence_array)
      print(sequence_array.dtype, sequence_array.shape)
      -----------------------------------------------
      [2 3 4 5 6 7 8 9]
      int32 (8,)
    
  • zeros() : 함수 인자로 튜플 형태의 shape 값을 입력하면 해당 shape의 모든 값을 0으로 채운 ndarray를 반환한다.
  • ones() : zeros와 유사하나 모든 값을 1로 채운 값을 반환한다.

      zero_array = np.zeros((3,2), dtype='int32')
      zero_array
      ---------------------------------------------
      array([[0, 0],
             [0, 0],
             [0, 0]])
    
      one_array = np.ones((3,2), dtype='int32')
      one_array
      ---------------------------------------------
      array([[1, 1],
             [1, 1],
             [1, 1]])
    

6) reshape(): ndarray의 차원 및 크기 변경

array1 = np.arange(10)
array2 = array1.reshape(2, 5)
print(array2)
-----------------------------
[[0 1 2 3 4]
 [5 6 7 8 9]]
array1 = np.arange(10)
print(array1)

## -1을 입력하면, 5열에 맞는 행의 수가 알아서 맞춰진다. 
array2 = array1.reshape(-1,5)
print('array2 shape:',array2.shape)

array3 = array1.reshape(5,-1)
print('array3 shape:',array3.shape)
--------------------------------------
[0 1 2 3 4 5 6 7 8 9]
array2 shape: (2, 5)
array3 shape: (5, 2)

7) indexing

  • 단일값 추출

      array1 = np.arange(10)
      print(array1)            # [0 1 2 3 4 5 6 7 8 9]
      print(array1[1])         # 1
    
      array1 = np.arange(1, 10)
      array2d = array1.reshape(3,3)
      print(array2d)
      ---- 
      [[1 2 3]
       [4 5 6]
       [7 8 9]]
        
      print(array2d[2,2])   # 9
    
  • slicing
    • 넘파이에서 ndarray 내의 일부 데이터 세트나 특정 데이터만을 선택할 수 있도록 한다.
      array1 = np.arange(1, 10)
      array2d = array1.reshape(3,3)
        
      print(array2d[0:2,0:2])
      --------------
      [[1 2]
       [4 5]]
        
      print(array2d[1:3,:],'\n')
      --------------
      [[4 5 6]
       [7 8 9]]
        
      print(array2d[1:3,:2],'\n')
      -------------------
      [[4 5]
       [7 8]]
    
  • fancy indexing
    • 리스트나 ndarray로 인덱스 집합을 지정 → 해당 위치의 인덱스에 해당하는 ndarray를 반환하는 인덱싱 방식
      array1 = np.arange(1,10)
      array2d = array1.reshape(3,3)
        
      array3 = array2d[[0,2], 0:2]
      print(array3)
      ------------------
      [[1 2]
       [7 8]]
        
      array4 = array2d[[0,1]]
      print(array4)
      -------------------
      [[1 2 3]
       [4 5 6]]
    
  • boolean indexing
    • 조건 필터링과 검색을 동시에 할 수 있기 때문에 자주 사용되는 인덱싱 방식
      array1 = np.arange(1,10)
      array_filtered = array1[array1 > 5]
      print(array_filtered)       # [6 7 8 9]
      print(array1 > 5)     # [False False False False False  True  True  True  True]
        
      boolean_index = np.array([False False False False False  True  True  True  True])
      array_filtered2 = array1[boolean_index ];
      print(array_filtered2)       # [6 7 8 9]
    

8) 행렬의 정렬 - sort()와 argsort()

  • 행렬 정렬

      org_array = np.array([ 3, 1, 9, 5]) 
      print('원본 행렬:', org_array)
        
      # np.sort( )로 정렬 
      sort_array1 = np.sort(org_array)    
      print (sort_array1)     # np.sort 함수가 반환한 값 : [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] -> 원본 행렬이 정렬됨
    
    • 내림차순 정렬
      sort_array1_desc = np.sort(org_array)[::-1]
      print ('내림차순으로 정렬:', sort_array1_desc)     # [9 5 3 1]
    
    • 2차원 행렬의 정렬
      • axis=0 : 로우 방향으로 정렬
        array2d = np.array([[8, 12], 
                           [7, 1 ]])
              
        sort_array2d_axis0 = np.sort(array2d, axis=0)
        print('로우 방향으로 정렬:\n', sort_array2d_axis0)
        [[ 7  1]
         [ 8 12]]
      
      • axis=1 : 컬럼 방향으로 정렬
        sort_array2d_axis1 = np.sort(array2d, axis=1)
        print('컬럼 방향으로 정렬:\n', sort_array2d_axis1)
        [[ 8 12]
         [ 1  7]]
      
  • 정렬된 행렬의 인덱스 반환

      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]
    
      org_array = np.array([ 3, 1, 9, 5]) 
      sort_indices_desc = np.argsort(org_array)[::-1]    # 9,5,3,1
      print('행렬 내림차순 정렬 시 원본 행렬의 인덱스:', sort_indices_desc) 
      # [2 3 0 1]
    
      name_array = np.array(['John', 'Mike', 'Sarah', 'Kate', 'Samuel'])
      score_array= np.array([78, 95, 84, 98, 88])
        
    

9) 선형 대수 연산 - 행렬 내적과 전치 행렬 구하기

  • 행렬 내적
    • 행렬 곱을 의미
    • 두 행렬 A, B의 내적은 np.dot()을 이용해 계산한다.
    • 아래 그림에서 np.dot()의 1행 1열 값은 A 행렬의 1행과 B 행렬의 1열 값을 순차적으로 곱하여 더한 값이다. 58 = 17 + 29 + 3*11

image

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('행렬 내적 결과:\n', dot_product)
------------------------------------------
[[ 58  64]
 [139 154]]
  • 전치 행렬
    • 원 행렬에서 행과 열 위치를 교환한 원소로 구성한 행렬을 그 행렬의 전치 행렬이라 한다.
    • 2x2 행렬 A가 있을 경우 A 행렬의 1행 2열의 원소를 2행 1열의 원소로, 2행 1열의 원소를 1행 2열의 원소로 교환한다.
      A = np.array([[1, 2],
                    [3, 4]])
      transpose_mat = np.transpose(A)
      print('A의 전치 행렬:\n', transpose_mat)
      ------------------------------------------------------------------
      [[1 3]
       [2 4]]
    

    image