데이터 분석 Study 02

데이터 분석 공부의 2차시 내용을 정리한 글입니다.

# Data Science
title

준비

Numpy 개념에 대해 알아보고 실습을 진행합니다.

필자는 Python 3.9.4, IDLE Shell 3.9.4 환경에서 실습을 진행하였습니다.

또한 실습에 앞서 numpy 라이브러리 설치가 필요합니다. 환경마다 조금씩 차이가 있기에 설치 과정은 생략합니다.

import numpy as np




Numpy 란?

"파이썬에서 산술 계산을 위한 가장 중요한 필수 패키지중 하나"

판다스와 주로 함께 사용됩니다.




Numpy 배열 vs Python 리스트

※ 환경에 따라 차이가 발생할 수 있습니다.

각각 백만개의 정수를 저장하여 연산 속도를 측정해봅니다.

import numpy as np

my_arr = np.arange(1000000) # Numpy 배열
my_list = list(range(1000000)) # Python 리스트
%time for _ in range(10):   my_arr2 = my_arr * 2

-> 14 ms

%time for _ in range(10):   my_list2 = [x * 2 for x in my_list]

-> 515 ms

Numpy 배열의 연산 속도가 훨~씬 빠른 것을 확인할 수 있습니다.




Numpy ndarray

  • numpy 가 지원하는 대규모 데이터들의 집합을 담을 수 있는 다차원 행렬 자료구조입니다.
  • C 의 array 보다 연산에 특화되어 있습니다.
  • 평균에 가까운 난수를 행렬 형태로 생성합니다.




Ndarray 조건

  • Ndarray 의 모든 원소는 동일 자료형이어야 합니다.
  • 모든 배열은 각 차원의 크기를 알려주는 shape 라는 튜플과 저장된 자료형을 알려주는 dtype 이라는 객체를 소유합니다.

Q. 여기서 차원이란 ?

직선은 1차원, 평면은 2차원, 공간은 3차원인 것처럼 특정 값 표현을 위해 다차원 배열을 이용할 수 있습니다.

ex) 2차원 배열의 값을 표로 표현.




Ndarray 생성

여기서는 아래의 배열 생성 함수들을 다뤄봅니다.

  • array
  • arange
  • ones
  • zeros
  • empty




1. array

가장 대표적이고 쉬운 배열 생성 함수로써 순차적 객체를 ndarray 로 변환합니다.

person = ['hyungjin', 'yubin', 'siu']
arr = np.array(person)
arr

array(['hyungjin', 'yubin', 'siu'], dtype='<U8')

또한 같은 길이를 가지는 순차적 데이터를 이용하여 다차원 배열을 생성할 수 있습니다.

fruit = [['포도', '복숭아', '멜론'], ['grape', 'peach', 'melon']] # 2차원 배열
arr2 = np.array(fruit)
arr2

array([['포도', '복숭아', '멜론'],
       ['grape', 'peach', 'melon']], dtype='<U5')

ndimshape 속성을 이용하여 각각 배열의 차원 수와 크기를 확인할 수 있습니다.

print(arr2.ndim)

-> 2

print(arr2.shape)

-> (2, 3)




2. arange

기존 range 함수와 유사하게 동작하며 ndarray 형태로 반환합니다.

_num = np.arange(2, 15, 3)
_num

array([ 2,  5,  8, 11, 14])




3. zeros

배열의 형태를 잡고 원소를 0 으로 초기화할 수 있습니다.

np.zeros((3, 2, 4))

array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.]],

       [[0., 0., 0., 0.],
        [0., 0., 0., 0.]],

       [[0., 0., 0., 0.],
        [0., 0., 0., 0.]]])




4. ones

zeros 함수와 동일하며 원소를 1 로 초기화합니다.

np.ones((2, 3, 2))

array([[[1., 1.],
        [1., 1.],
        [1., 1.]],

       [[1., 1.],
        [1., 1.],
        [1., 1.]]])




5. empty

zeros, ones 함수와 동일하지만 초기화를 하지 않기에 쓰레기 값이 할당될 수 있습니다.

np.empty(2)

array([-2.70673077e-011, -9.62446753e-265])




Numpy 자료형

dtype 객체를 확인할 수 있습니다.

arr = np.arange(10)
arr2 = np.array([3.26, 200.5, 40.15])
arr3 = np.array(['string', 'boolean', 'float', 'integer'])

print(arr.dtype)
print(arr2.dtype)
print(arr3.dtype)

int32
float64
<U7

뒤에 붙는 숫자는 자료형의 비트 크기를 나타냅니다.

'<U7' 의 숫자는 배열 원소의 가장 긴 문자열의 길이가 7 임을 알려줍니다.




자료형 설정

기본적으로 최적의 자료형을 탐색해서 디폴트 값을 설정하지만 아래처럼 직접 지정할 수도 있습니다.

arr1 = np.array([1, 2, 3,], dtype=np.float64)
arr2 = np.array([1, 2, 3,], dtype=np.int64)

print(arr1.dtype)
print(arr2.dtype)

float64
int64

astype 을 이용하는 방법도 있습니다.

arr = np.array([3, 2, 1])
print(arr.dtype)

f_arr = arr.astype(np.float64)
print(f_arr.dtype)




Numpy 산술연산

배열은 for 문을 사용하지 않고도 데이터를 일괄 처리할 수 있는데 이를 백터화 라고 합니다.

여기서는 아래 두 배열을 이용하여 연산을 해보겠습니다.

arr1 = np.array([[1.2, 5.4, .3], [4., 5., 6.]])
arr2 = np.array([[4., 7., .3], [1., 2., 3.]])

배열간 덧셈

arr1 + arr2

array([[ 5.2, 12.4,  0.6],
       [ 5. ,  7. ,  9. ]])

배열간 뺄셈

arr1 - arr2

array([[-2.8, -1.6,  0. ],
       [ 3. ,  3. ,  3. ]])

배열간 곱셈

arr1 * arr2

array([[ 4.8 , 37.8 ,  0.09],
       [ 4.  , 10.  , 18.  ]])

배열간 나눗셈

arr1 / arr2

array([[0.3       , 0.77142857, 1.        ],
       [4.        , 2.5       , 2.        ]])

스칼라 / 비교 연산

스칼라 : Scalar 타입 (int, float, None, bool 4가지)

List 와 달리 배열의 각 원소들에 연산을 시도합니다.


arr1 * 100

array([[120., 540.,  30.],
       [400., 500., 600.]])

제곱

arr2 ** 2

array([[16.  , 49.  ,  0.09],
       [ 1.  ,  4.  ,  9.  ]])

비교 연산

boolean 타입 배열을 반환합니다.

_bool = arr2 > arr1
print(_bool.dtype)
print(_bool)

bool
[[ True  True False]
 [False False False]]




브로드캐스팅

브로드캐스팅 은 shape 가 다른 배열끼리도 연산이 가능하게 해주는 것입니다.

만약 이어지는 각 차원(시작부터 끝까지)에 대해 축의 길이가 일치하거나 둘 중 하나의 길이가 1이라면 두 배열은 브로드캐스팅 호환입니다. 브로드캐스팅은 누락된 혹은 길이가 1인 차원에 대해 수행됩니다.

저차원 브로드캐스팅 조건

· 두 배열의 차원(ndim)이 같지 않다면 차원이 더 낮은 배열이 차원이 더 높은 배열과 같은 차원의 배열로 인식합니다.

· 반환된 배열은 연산을 수행한 배열 중 차원의 수(ndim)가 가장 큰 배열이 됩니다.

· 연산에 사용된 배열과 반환된 배열의 차원의 크기(shape)가 같거나 1일 경우 브로드캐스팅이 가능합니다.

· 브로드캐스팅이 적용된 배열의 차원 크기(shape)는 연산에 사용된 배열들의 차원의 크기에 대한 최소 공배수 값으로 사용합니다.

예시 코드

스칼라를 백터로 확장시켜 연산합니다.

x = np.array([1, 2, 3])
y = np.ones(3, dtype=int)

x + y

array([2, 3, 4])

차원 증가

b_arr = np.array([[1, 2, 3], [4, 5, 6]])
b_arr2 = np.array([1, 2, 3])

b_arr + b_arr2

array([[2, 4, 6],
       [5, 7, 9]])




유니크

unique : 입력 배열을 평면화 시킨 뒤에 고유 값을 정렬하여 반환하는 함수

arr = np.array([[2, 3, 1], [3, 4, 2], [1, 2, 3]])
u_arr = np.unique(arr)

u_arr

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

return_index 옵션을 주면 원소들의 고유값과 각 고유값이 첫 번째로 등장하는 인덱스 번호를 반환합니다.

arr = np.array([[2, 7, 4], [3, 2, 6], [5, 1, 4]])
u_arr = np.unique(arr, return_index=True)

u_arr

(array([1, 2, 3, 4, 5, 6, 7]), array([7, 0, 3, 2, 6, 5, 1], dtype=int64))

return_counts 옵션을 주면 원소들의 고유값과 해당 배열에서의 각 고유값의 개수를 반환합니다.

arr = np.array([[2, 7, 4], [3, 2, 6], [5, 1, 4]])
u_arr = np.unique(arr, return_counts=True)

u_arr

(array([1, 2, 3, 4, 5, 6, 7]), array([1, 2, 1, 2, 1, 1, 1], dtype=int64))




덤프

pickle 은 텍스트 외 파이썬 객체 자체를 파일로 저장하기 위한 모듈입니다. 데이터 변경 없이 그대로 save & load 할 수 있다는 장점이 있고 복잡한 학습 모델도 pickling 으로 간단히 저장 가능합니다.

dumppickle 모듈에서 객체를 저장할 때 사용하는 함수입니다.

import pickle

company_list = ['amazon', 'facebook', 'google', 'microsoft', 'apple']

# save
with open('files.pkl', 'wb') as f:
    pickle.dump(company_list, f, protocol=pickle.HIGHEST_PROTOCOL)

# load
with open('files.pkl', 'rb') as f:
    data = pickle.load(f)

print(data)

['amazon', 'facebook', 'google', 'microsoft', 'apple']




Quiz

Q. Ndarray 의 필수 요소 두 가지는?

A. dtype, shape


Q. 자료형을 변경하는데 사용되는 메서드는?

A. astype


Q. Ndarray 와 list 의 차이점은?

A. ndarray 는 원소 값끼리의 연산이 가능하며 그 성능도 list 보다 뛰어납니다.


Q. Ndarray 의 생성 함수는?

A. array, arange, ones, zeros, empty




🙏 감사합니다

수업을 진행해주신 선린인터넷고등학교 이모션 동아리의 안유빈 선배님께 감사드립니다.



읽어주셔서 감사합니다.

😍  댓글