데이터 분석을 하기 위해서는 데이터 정제를 먼저 해야함
pandas의 데이터타입을 구성하고 있는 numpy를 먼저 배워보자!
ndarray라는 자료구조를 제공
수치계산이 용이한 python module임
대용량의 다차원 배열과 matrix(행렬)연산을 쉽게 하기 위한 python module임
Numerical Python => Numpy // Numerical : 수치적인!
Numpy는 단 하나의 자료구조를 제공함
바로바로 ndarray라는 것인데!
- ndarray(n-dimensional array) : 다차원 배열
1) ndarray는 "차원"의 개념이 있다.
2) python의 list와 상당히 유사하다.
3) 무조건 같은 데이터 타입(한가지 종류)만 저장된다.
list는 다른 데이터 타입 저장이 가능함..!
이 부분이 가장 큰 차이임
anaconda prompt에 conda install numpy => numpy를 설치
이제 numpy를 import하고 본격적으로 공부 시작!
import numpy as np
# python list
a = [1, 2, 3, 4]
print(a) # [1, 2, 3, 4]
print(type(a)) # <class 'list'>
# Numpy의 ndarray
arr = np.array([1, 2, 3, 4])
print(arr) # [1 2 3 4] => 1차원임 // 오잉??? ,가 없음!! ndarray는 공백을 가지고 구분 한다!
print(type(arr)) # <class 'numpy.ndarray'> numpy의 ndarray로 부터 만들어진 클래스 객체
print(arr.dtype) # int32 // arr의 데이터 타입 확인
arr2 = np.array([1, 2.3, 3, 4]) # 정수, 실수, 실수, 실수
print(arr2) # [1. 2.3 3. 4. ] 정수 -> 실수 로 바뀜!
print(arr2.dtype) # float64
# 다차원 배열
# 중첩 list
my_list = [[1, 2, 3], [4, 5, 6]]
print(my_list) # [[1, 2, 3], [4, 5, 6]]
# ndarray
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr) # [[1 2 3]
#[4 5 6]]
# ndarray의 차원 관련 속성
my_list = [1, 2, 3, 4]
arr = np.array(my_list)
print(arr) # [1 2 3 4]
print(arr.dtype) # ndarray의 data type : int32
print(arr.ndim) # ndim : 차원수를 숫자로 알려줌 => 1
print(arr.shape) # shape은 차원과 요소수를 tupple로 알려줌 => (4,) => 1차원이고 4개의 요소가 있음
my_list2 = [[1, 2, 3], [4, 5, 6]]
arr2 = np.array(my_list2)
print(arr2)
print(arr2.ndim) # 2
print(arr2.shape) # (2, 3) => 2행 3열
# (2,2,3) 형태의 ndarray
my_list3 = [[[1,2,3],
[1,2,3]],
[[1,2,3],
[1,2,3]]]
arr3 = np.array(my_list3)
print(arr3.shape) # (2면, 2행, 3열)
# ndarray의 typ을 변환
arr = np.array([1.2, 2.3, 3, 4, 5.7])
print(arr.dtype) # float64
new_arr = arr.astype(np.int32) # 정수로
print(new_arr.dtype)
print(new_arr) # [1 2 3 4 5]
new_arr2 = arr.astype(np.str_) # 문자열로
print(new_arr2) # ['1.2' '2.3' '3.0' '4.0' '5.7']
# ndarray를 만드는 다양한 함수
# 1. array
# list를 이용해서 ndarray 생성
my_list = [1, 2, 3]
arr = np.array(my_list)
# 2. zeros
arr2 = np.zeros((3,4)) # shape은 tuple로 표현함
print(arr2) # 0으로 채워진 3행 4열의 행렬을 만듬
# 3. ones
arr3 = np.ones((2,3)) # shape은 tuple로 표현함
print(arr3) # 1로 채워진 2행 3열의 행렬을 만듬
# 4. empty
arr4 = np.empty((2,3,3)) # shape은 tuple로 표현함
print(arr4) # 주어진 shape에 대한 ndarray를 생성하고 값을 채우지 않는다.
# 쓸모없는 값이 들어차있음
# 상대적으로 ndarray를 빠르게 생성할 수 있음
# 5. full
arr5 = np.full((2,3), # 2행 3열의
7, # 7로 채워진
dtype=np.float64) # dtpy은 실수인 행렬 생성
print(arr5)
# shape을 직접 지정하지 않고
# 다른 ndarray의 shape을 이용해서 ndarray를 생성
arr = np.array([[1,2,3], [4,5,6]],
dtype=np.int32)
print(arr) # [[1 2 3]
# [4 5 6]]
# 6. _like() : ()와 똑같은 shape으로 생성
new_arr = np.zeros_like(arr)
print(new_arr)
# python의 range
a = range(1,10)
print(a) # range(1, 10) => 값을 안가지고 있음!
# 7. arange
# numpy의 arange
arr = np.arange(1,10) # 1부터 10까지 1씩 증가(10은 포함 안함!!)하는 "값"으로 구성된 ndarray
print(arr) # [1 2 3 4 5 6 7 8 9] # 값을 가지고 있음!
arr2 = np.arange(1.3, 10.1, 2)
print(arr2) # [1.3 3.3 5.3 7.3 9.3]
# 8. linspace
# np.linspace(start, stop, num)
# start : 시작숫자, stop : 끝 숫자 ==> 둘 다 포함
# num : 그 안에 균일한 간격으로 몇개의 숫자가 들어갈지 나타내는 숫자.
# 균일한 간격의 데이터를 생성해서 ndarray를 만들어내는 함수
# 원소의 간격 계산 : (stopp - start) / (num-1)
arr = np.linspace(0,10,11) # 0에서 10까지 동일한 간격으로 11개의 숫자가 들어감
print(arr)
arr2 = np.linspace(0,10,6) # # 0에서 10까지 동일한 간격으로 6개의 숫자가 들어감
print(arr2)
arr3 = np.linspace(0,10,3) # # 0에서 10까지 동일한 간격으로 3개의 숫자가 들어감
print(arr3)
arr4 = np.linspace(0, 120, 31)
print(arr4)
ndarray를 만드는 다양한 함수 이어서 9번
# 9. 랜덤값을 이용해서 ndarray를 만듬
# 9-1) np.random.normal() : ndarray를 만드는데, 데이터를 난수로 채움
# 정규분포에서 실수 표본을 추출
# 평균, 표준편차값이 필요함
# 일단 난수를 추출하고, 그 난수가 정규분포를 따르는지 확인
import numpy as np
# anaconda promptl => conda install matplotlib 모듈 설치해줘야함!
import matplotlib.pyplot as plt
mean = 50 # 평균 = 50
std = 2 # 표준편차 = 2
arr = np.random.normal(mean, std,
(100000,))
print(arr)
plt.hist(arr, bins=100)
plt.show
# 9-2) np.random.rand() : ndarray를 만드는데, 데이터를 난수로 채움
# [0,1) 0부터 1사이(0은 포함, 1은 불포함)의 실수형 난수를
# 균등분포에서 추출한 후 ndarray를 생성
arr = np.random.rand(100000)
print(arr)
plt.hist(arr, bins=100)
plt.show
# 9-3) np.random.randn() : ndarray를 만드는데, 데이터를 난수로 채움
# 표준정규분포에서 난수 추출
# * 표준정규분포 : 정규분포에서 평균이 0이고, 표준편차가 1인 정규분포
# np.random.rand(d1, d2, d3) 로 사용
arr = np.random.randn(100000)
print(arr)
plt.hist(arr, bins=100)
plt.show
# 9-4) np.random.randint() : ndarray를 만드는데, 데이터를 난수로 채움
# 균등분포에서 정수형 난수를 추출. low와 high값을 줘야함
arr = np.random.randint(1, 100, (100000, )) # (low, high, (1차원이고 10만개 요소를 가진 ndarray))
print(arr)
plt.hist(arr, bins=99)
plt.show
# 9-5) np.random.random() : ndarray를 만드는데, 데이터를 난수로 채움
# 균등분포에서 실수형 난수를 추출.
# [0, 1) 사이에서 난수를 추출
# np.random.random((10000,))
arr = np.random.random((100000,))
print(arr)
plt.hist(arr, bins=100)
plt.show
# 1. seed()
# seed => 초기값 // 랜덤값을 도출하는 초기값을 고정해줌
# ==> 난수의 재현성을 확보
np.random.seed(1)
arr = np.random.randint(1, 10, (5,))
#arr = np.random.randint(1, 10, (5,))
# => 균등 분포에서 정수형 난수를 추출. (low, hight, shape())
# => 여기서 shape은 (5,)로 줬음 => 1행이고 5개의 요소를 가지고 있다!
print(arr)
# 2. shuffle()
# shuffle => 데이터의 순서를 바꿈
# shuffle 은 원본이 바뀜. 복사본은 만들지 않음
arr = np.arange(1,10)
print(arr)
new_arr = np.random.shuffle(arr)
print(new_arr) # None // 그래서 None값을 뱉어냄!
np.random.shuffle(arr)
print(arr)
# 3. choice()
# np.random.choice(a, size, replace, p)
# a : 배열 (ndarray)
# size : 숫자 (몇개를 뽑을 거임)
# replace : True => 한번 뽑았던 것을 다시 뽑을 수 있음 // 기본적으로 True임
# False => 한번 뽑았던 것을 다시 뽑을 수 없음
# p : 확률 (각 데이터가 선택될 수 있는 확률)
arr = np.random.choice(np.array([1,2,3,4,5]), 3)
print(arr)
arr2 = np.random.choice(np.array([1,2,3,4,5]), 3, replace=False)
print(arr2)
arr3 = np.random.choice(np.array([1,2,3,4,5]), 3, p=[0.1, 0.2, 0.2, 0.3, 0.2])
print(arr3)
# ndarray의 shape과 관련된 중요한 함수들!
# reshape(), revel(), resize()
# 1) reshape() : 내가 원하는 shape의 view를 만들 수 있음 // 요소의 수가 동일해야함!
arr = np.array([[1,2,3,4,5,6], [7,8,9,10,11,12]])
print(arr) # 2차원의 ndarray
print(arr.shape) # (2,6) // 2행 6열!
# [[ 1 2 3 4 5 6]
# [ 7 8 9 10 11 12]]
new_arr = arr.reshape(3,4) # 3행 4열로 reshape!
print(new_arr)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
new_arr[0,0] = 100 # 0행 0열을 100으로!
print(new_arr)
print(arr) # ????? 뭐임?? 나는 new_arr을 바꿨는디, 왜 arr도 바뀌어있음?? 뭐임? 뭐함??
# => reshape() : shape을 바꿔서 새로운 ndarray를 만드는게 아님! 잘 들어보셈
# 요고슨 shape을 바꿔서 원래 ndarray에 데이터를 다르게 보여주는 view를 생성함
# 뭔 소리인지 암?
# reshape은 새로운 ndarray를 만드는게 아니고!! "모양"만 다르게 보여주는 거라는 거임!!
# 데이터는 단 1개라는 것이지! 그래서 new_arr에서 데이터를 바꿔버리면
# 원본 데이터를 바꾸는 것임
# 모양을 바꿔서 새로운 ndarray를 생성하고 싶으면 copy()를 이용해야함
new_arr2 = arr.reshape(3,4).copy()
new_arr2[0,0] = 50
print(new_arr2)
# [[50 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
print(arr)
# [[100 2 3 4 5 6]
# [ 7 8 9 10 11 12]]
# 음 이제야 편-안
# 2) revel() : 무조건 1차원의 view를 만듬
arr = np.array([[1,2,3,4,5,6], [7,8,9,10,11,12]])
print(arr) # 2차원의 ndarray
print(arr.shape) # (2,6) // 2행 6열!
new_arr = arr.ravel() # 1차원으로 view를 생성
print(new_arr)
# 3) resize() : 복사본을 만들지 않고, 원본을 변경.
# 요소의 수가 같지 않아도 수행 가능.
# => 부족한 것은 0으로 채움 : 불필요한 데이터가 생기는 위험이 있음
# => 넘는 것은 삭제됨 : 데이터의 유실 위험이 있음
arr = np.array([[1,2,3,4,5,6], [7,8,9,10,11,12]])
print(arr) # 2차원의 ndarray
print(arr.shape) # (2,6) // 2행 6열!
new_arr = arr.resize(3,5)
print(new_arr) # None => resize는 복사본을 만들지 않고, 원본을 변경해버림
print(arr)
# [[ 1 2 3 4 5]
# [ 6 7 8 9 10]
# [11 12 0 0 0]] => 부족한 부분은 0으로 채움
arr = np.array([[1,2,3,4,5,6], [7,8,9,10,11,12]])
arr.resize(3,2)
print(arr)
# [[1 2]
# [3 4]
# [5 6]] => 넘는 부분은 삭제
# 기본적인 index
# 기본적인 slicing은 python의 list와 동일
arr = np.arange(10,15,1)
print(arr) # [10 11 12 13 14]
print(arr[0]) # 10
print(arr[1:3]) # [11 12]
print(arr[1:-1]) # [11 12 13]
arr = np.arange(0,12).reshape(3,4)
print(arr)
print(arr[1,2]) # 6 // 1행 2번째열
print(arr[1,]) # [4 5 6 7] // 1행
print(arr[1,:]) # [4 5 6 7] // 1행, 모든열
print(arr[1:,2:]) # [[ 6 7] // 1행부터 끝까지, 2열부터 끝까지
# [10 11]]
# Boolean Indexing & Fancy Indexing
# Boolean Indexing
# => indexing 방법 중 하나로, boolean mask를 이용해서 indexing하는 방법
np.random.seed(1)
arr = np.random.randint(0, 10, (10,))
print(arr) # [5 8 9 5 0 0 1 7 6 9]
print(arr + 10) # [15 18 19 15 10 10 11 17 16 19]
# % : 나머지 값
print(arr % 2) # [1 0 1 1 0 0 1 1 0 1]
# True, False로만 구성된 ndarray를 boolean mask라고 표현함
print(arr % 2 == 0) # [0 0 0 0 0 0 0 0 0 0]
# [False True False False True True False False True False]
my_mask = (arr % 2 == 0)
# => boolean indexing은 boolean mask를 가지고 indexing하는 것을 의미한다.
print(arr[my_mask]) # [8 0 0 6] => boolean 값이 True인 것만 가져옴
# ndarray의 사칙연산 => +, -, *, /
# ndarray는 같은 shape에 대해서만 연산이 가능
arr1 = np.array([1,2,3])
arr2 = np.array([4,5,6])
print(arr1 + arr2) # [5 7 9]
# ndarray는 shape을 맞출 수 있으면 broadcasting이 진행된(차원을 맞춰줌)
arr1 = np.array([1,2,3])
print(arr1 + 4) # 4 => [4 4 4] broadcasting이 되어 차원이 맞춰짐! ㅇ0ㅇ
# Fancy Indexing
# ndarray에 index 배열을 전달해서 indexing하는 방법
arr = np.array([1,2,3,4,5,6])
print(arr)
print(arr[3]) # 4 => indexing
print(arr[3:]) # [4 5 6] => slicing
print(arr[[3, 5]]) # [4 6] => Fancy Indexing
arr = np.arange(0, 12, 1).reshape(3,4)
print(arr)
print(arr[0:2, 1:]) # [[1 2 3]
# [5 6 7]]
print(arr[0:2, [1,3]]) # [[1 3]
# [5 7]]
# np.ix_ 함수
print(arr[np.ix_([0,2], [1,3])])