예전부터 Data에 대한 연구는 꾸준히 진행되어왔다.
Data분석이 어려운 이유
1. 데이터가 많이 필요!
2. Computing Resource가 많이 필요
시대가 변하면서 데이터의 수요와 양이 증가 됨
상대적으로 적은 비용으로 컴퓨터 리소스를 사용할 수 있게 됨 (클라우드[AWS])
일반인들도 데이터 분석, 머신러닝 작업이 가능해짐
우선 데이터를 수집하고 가공하는 작업이 선행되어야 한다.
우리가 얻는 데이터는 대부분 raw data이다.
이것을 우리가 분석이나 머신러닝 학습에 사용하기 위해 가공해야한다!
하지만 이런 데이터 가공은 생각보다 어렵다
python의 모듈로 이런 데이터를 가공하기 위한 것이 제공된다.
==> pandas module
pandas의 데이터 타입을 구성하고 있는 또다른 모듈
==> numpy module
numpy는 하나의 자료구조(list, dict)를 제공
==> ndarray라는 자료구조를 제공해줌
결국 pandas가 numpy의 ndarray를 가져다 씀
Numpy란? 수치계산을 용이하게 하기 위한 python module (외장 모듈임)
대용량의 다차원 배열과 matrix(행렬)연산을 쉽게 하기 위해 사용
Numpy는 단 하나의 자료구조를 제공
- ndarray = 차원의 개념이 있음
- ndarray는 python의 list와 상당히 유사
- ndarray는 차원의 개념이 있음
list는 여러 다른 타입(숫자,문자,등)의 데이터가 저장될 수 있다.
하지만 ndarray는 무조건 같은 데이터 타입만 저장됨!
Numpy는 외장 module이기 때문에 당연히 설치해서 사용해야 함!
conda install numpy
예제를 통해 Numpy를 사용해보자
# 모듈 설치를 확인하기위해 import numpy를 써보자 # 전세계적으로 numpy는 np라는 as을 사용함 import numpy as np #python list a = [1, 2, 3, 4] print(a) #[1,2,3,4] print(type(a))# class 'list'> # Numpy의 ndarray를 만들어보자! # Nump를 만들때는 np.array를 이용 arr = np.array([1,2,3,4]) print(arr) #[1 2 3 4] => 1차원 # np.array는 콤마가 없다! 공백을 가지고 부름 print(type(arr)) # ndarray.를 가지고있는 <class 'numpy.ndarray'> print(arr.dtype) # int32 # dtype : d 는 데이터의 약자 (자료형) arrr = np.array([1,2.3,4]) # 자동으로 같은 값 실수로 바꿔줌 print(arrr) # [1. 2.3 4. ] print(type(arrr)) # <class 'numpy.ndarray'> print(arrr.dtype) # float64
- Numpy의 다차원 배열
# 다차원 배열 import numpy as np # 중첩리스트 my_list = [[1,2,3],[4,5,6 ]] print(my_list) # [[1, 2, 3], [4, 5, 6]] # 다시한번 얘기하지만 파이썬의 리스트는 차원 개념이 없음 # 하지만 np로 땡겨지면 # ndarray arr = np.array([[1,2,3],[4,5,6 ]]) print(arr) #[[1 2 3] # [4 5 6]] # my_list 의 5라는 값을 어떻게 추출하지? print(my_list[1][1]) # 5 # ndarray에서는 어떻게 가져오는가 print(arr[1,1]) #다음과 같이 표현 방법이 다르다 # 5 print(arr[1]) # 행자체가 출력됨 [4 5 6] print(arr[1][1]) # 5 print(arr.dtype) # int32 ( Numpy가 알아서 설정!) # 먼저 행을들고와 열을찾는 방식이 잘못된게아님 그러나 방식은 [x,x]이방식을 사용하는게 좋다 # 기본적으로 ndarray는 요소의 데이터타입을 이용해서 dtype을 설정 # 즉 내용을 보고 자기가 알아서 데이터 타입을 잡음 # 데이터 타입을 지정해서 ndarray를 생성할 수 있음! arr = np.array([[1,2,3],[4,5,6,]], dtype=np.float64) print(arr) #[[1. 2. 3.] # [4. 5. 6.]] print(arr.dtype) # float64
- ndarray의 차원 관련 속성
# ndarray의 차원 관련 속성 my_list = [1,2,3,4] arr = np.array(my_list) print(arr) # [1 2 3 4] print(arr.dtype) # ndarray의 datatype = > int 32 print(arr.ndim) # ndim은 차원수를 숫자로 알려줘요! => 1 # 얘는 꼭 기억하자 print(arr.shape) # shape은 차원과 요소수를 tuple(파이썬 튜플)로 알려줘요! =>(4,) # 1차원이니까 tuple안에 요소가 1개, 그리고 그 값이 요소의 개수 # (4,) # 2 차원을 진행해보자 my_list = [[1,2,3],[4,5,6]] arr = np.array(my_list) print(arr.ndim) # 2 print(arr.shape) # (2, 3) # (2,2,3) 형태의 ndarray를 만들어 보자 # my_list = [1,2,3] # (2,2,3)에서 1차원 3개를 의미 my_list =[[[1,2,3], [1,2,3]], [[1,2,3], [1,2,3]]] arr = np.array(my_list) print(arr.shape) # (2,2,3) 면 행 열로 출력
- ndarray의 type 변환
# ndarray의 type을 변환시켜보자! => astype() # ndarray는 내가 dtype을 잡아주지 않으면 안에 있는값을 기준으로 타입을 잡음 import numpy as np arr = np.array([1.2, 2.3, 3, 4, 5.7]) print(arr.dtype) # float64 new_arr = arr.astype(np.int32) # 실수를 정수로 바꿈 이렇게 작성하면 새로운 np.array가 만들어지고 정수형태로 출력됨 print(new_arr) # [1 2 3 4 5] new_arr = arr.astype(np.str_) # 안에있는 값을 문자열로 바꿈 print(new_arr) # ['1.2' '2.3' '3.0' '4.0' '5.7']
- ndarray를 만드는 함수들
# ndarray를 만드는 다양한 함수들 my_list = [1,2,3] arr = np.array(my_list) # list를 이용해서 ndarray를 생성 arr = np.zeros((3,4)) # () 안에 튜플을 넣어준다 즉 shape을 넣어준다 생각하면 됨 # shape은 tuple로 표현! print(arr) # zeros : 주어진 shape에 대한 ndarrray를 생성하고 0으로 채움! (3행 4열) # [[0. 0. 0. 0.] # [0. 0. 0. 0.] # [0. 0. 0. 0.]] arr = np.ones((2,3)) print(arr) # [[1. 1. 1.] # [1. 1. 1.]] arr = np.zeros((2,3,3)) # shape은 tuple로 표현! 3행3열 2면임 print(arr) # 주어진 shape에 대한 ndarrray를 생성하고 값을 채우지 않고 형태만 만듬 # 안에 쓰레기값이 들어갈 수 있음 # 상대적으로 ndarray를 빠르게 생성할 수 있음 #[[[0. 0. 0.] # [0. 0. 0.] # [0. 0. 0.]] # [[0. 0. 0.] # [0. 0. 0.] # [0. 0. 0.]]] arr = np.full((2,3), 7, dtype=np.float64) # 2행3열 만들고 7로채워 타입은 float print(arr) # [[7. 7. 7.] # [7. 7. 7.]] ##################################### # shape을 직접 지정하지 않고 다른 ndarray의 shape을 이용해서 ndarray를 생성할 수 있음! arr = np.array ([[1,2,3], [4,5,6]], dtype=np.int32) print(arr) #[[1 2 3] #[4 5 6]] new_arr = np.zeros_like(arr) # shape을 지정하지 않고 ()안에 있는 변수의 shape과 같은 형태로 만들어서 안을 싹다 0으로 채워! print(new_arr) #[[0 0 0] #[0 0 0]]
# ndarray를 만드는 방법! # np.array(), np.ones(), np.zeros(), np.full(), np.empty() # np.ones_like(), np.zeros_like(), np.full_like(), np.empty_like() # np.arange() import numpy as np # python의 range a = range(1,10) print(a) # range(1, 10) => 의미이고 실제 값을 하나씩 가지고 있지 않음 # numpy의 arange arr = np.arange(1,10) # 1부터 10까지 (10은 포함 x)1씩 증가하는 값으로 구성된 ndarray print(arr) # [1 2 3 4 5 6 7 8 9] => 의미는 똑같지만 실제 값을 가지고 있음! arr = np.arange(1.3, 10.1, 2) print(arr) # [1.3 3.3 5.3 7.3 9.3]
# ndarray를 만드는 방법! # np.array(), np.ones(), np.zeros(), np.full(), np.empty() # np.ones_like(), np.zeros_like(), np.full_like(), np.empty_like() # np.arange(), np.linspace() import numpy as np # np.linspace(start, stop, num) # start : 시작숫자와, stop : 끝 숫자 ==> 둘 다 포함 # num : 그안에 균일한 간격으로 몇개의 숫자가 들어갈지를 나타내는 숫자 # 균일한 간격의 데이터를 생성해서 ndarray를 만들어 내는 함수 # 원소간의 간격은 어떻게 생각하면 되나? =? (stop-start) / (num - 1) arr = np.linspace(0,120,31) print(arr)
결과 [ 0. 4. 8. 12. 16. 20. 24. 28. 32. 36. 40. 44. 48. 52. 56. 60. 64. 68. 72. 76. 80. 84. 88. 92. 96. 100. 104. 108. 112. 116. 120.]
# ndarray를 만드는 방법! # np.array(), np.ones(), np.zeros(), np.full(), np.empty() # np.ones_like(), np.zeros_like(), np.full_like(), np.empty_like() # np.arange(), np.linspace() # 랜덤값을 이용해서 ndarray를 만들어 내는 방법 - 5개의 함수가 있어요!! # np.random.normal(), np.random.rand(), np.random.randn(), np.random.randint(), np.random.random() # np.random이라는 패키지안에 normal()이란 함수가 있다! # np.random.normal() : ndarray를 만듦, 그런데 그안에 데이터는 난수로 채움! # 정규분포 실수 표본을 추출 # 평균, 표준편차값이 필요! # 일단 난수를 추출하고 그 난수가 정규분포를 따르는지 확인! import numpy as np import matplotlib.pyplot as plt # 차트 그리는 녀석임 # matplotlib 요 녀석을 설치해주도록 하자 # anaconda 가상환경에 conda install matplotlib 통해 설치를 해주자! # mean = 50 # 평균 # std = 2 # 표준편차 # 1번째 # arr = np.random.normal(mean, # std, # (100000,)) # 3번째 인자는 shape # print(arr) # 그래프로 나타내보자 bins이라는 간격안에 최솟값과 최대값을 가지고 100개의 영역을 나눠 그래프로 그림 # plt.hist(arr,bins=100) # plt.show() # 2번째 # np.random.rand() : ndarray를 만듬 그런데 그안에 데이터는 난수로 채움! # [0,1) 0부터 1사이 (0은 포함, 1은 불포함)의 실수형 난수를 # 균등분포에서 추출한 후 ndarray를 생성 # 데이터의 편향을 없애기 위해 위 방식처럼 난수를 추출함 # 무조건 0~1사이의 데이터를 뽑음 # arr = np.random.rand(1000000) # print(arr) # plt.hist(arr,bins=100) # plt.show() # 3번째 # np.random.randn() : ndarray를 만듬 그런데 그안에 데이터는 난수로 채움! # 표준정규분포에서 난수를 추출 # (정규분포에서 평균이0이고 표준편차가 1인 정규분포를 표준정규분포라 함) # arr = np.random.randn(100000) # print(arr) # plt.hist(arr,bins=100) # plt.show() # 특정분포를 따르는 난수들을 함수를 통해서 뽑을 때 원하는 형태로 만들어 낼 수 있다 라고 심플하게 생각해보도록 하자! # 4번째 # np.random.randint() : ndarray를 만듬 그런데 그안에 데이터는 난수로 채움! # 균등분포에서 정수형 난수를 추출 low와 high값을 줘야함 # 정수형 난수 추출하는구나! 라고 이해하도록하자 # arr = np.random.randint(1, 100, (100000,)) # print(arr) # plt.hist(arr,bins=100) # plt.show() # np.random.random() : ndarray를 만들어요, 그런데 그안에 데이터는 난수로채움 # 균등분포에서 실수형 난수를 추출 # 범위는 [0, 1) 사이에서 난수를 추출 # np.random.random(shape) arr = np.random.random((100000,)) print(arr) plt.hist(arr,bins=100) plt.show()
결과 [0.83878294 0.58468521 0.42893134 ... 0.83156919 0.29580214 0.31745492]
# 기억해야 하는 random관련 함수들 # 1. seed() # 랜덤값도 사실은 프로그램 알고리즘에 의해서 추출되는 값 # 랜덤값을 도출하는 초기값을 고정하면 항상 같은 랜덤값을 얻을 수 있어요! # np.random.seed(1) # np.random.seed(None) None이면 값이 랜덤하게 뽑힘 # arr = np.random.randint(1, 10, (5,)) # print(arr) # [6 9 6 1 1] 수치가 고정되서 뽑히는 것을 볼 수 있다. # 2. 데이터의 순서를 바꿀때 shuffle() # 셔플은 인자로 들어온 것을 섞음 즉 섞은거를 토대로 복사본이 만들어 지는게 아닌 원본이 섞임 그래서 즉 new_arr이 필요 없음 # 따라서 작성은 np.random.shuffle만 사용해 작성한다. # new_arr = np.random.shuffle(arr) # arr = np.arange(1,10) # print(arr) # np.random.shuffle(arr) # 원본이 변경됨!, 복사본 만들지 않음 # print(arr) # [1 2 3 4 5 6 7 8 9] # [2 8 1 4 9 3 6 7 5] # 3. sampling에서 사용할 수 있는 choice() # np.random.choice(a, size, replace, p) # 인자를 기억하도록 하자 # a : 배열(ndarray) # size : 숫자 (몇개를 뽑을건지) # replace : True이면 한번뽑을것을 다시 뽑을 수 있음 # p : 확률(각 데이터가 선택될 수 있는 확률) # arr = np.random.choice(np.array([1,2,3,4,5]),3) # == arr = np.random.choice(np.array([1,2,3,4,5]), 3, replace = True) # arr = np.random.choice(np.array([1,2,3,4,5]), 3, replace = False) arr = np.random.choice(np.array([1,2,3,4,5]), 3, p=[0.1, 0.2, 0.2, 0.5, 0]) print(arr) # [4 3 4]
- ndarray의 특징, 속성(shape)
# ndarray의 특징, 속성(shape) # ndarray 생성 # - np.array([1,2,3]) # list를 이용한 ndarray 생성 # - np.ones(), np.zeros(), ... # 다양한 생성 함수 # - np.arrange(), np.linspace() # 다양한 생성 함수 # - np.random.noraml(), 총5가지 # random값을 이용한 ndarray 생성 함수 # 기억해야할 random 관련 함수 # - np.random.seed(), np.random.shuffle(), np.random.choice() # ndarray의 shape과 관련된 중요한 함수들(reshape(), ravel(), resize()) arr = np.array([[1,2,3,4,5,6],[7,8,9,10,11,12]]) print(arr) # 2차원의 ndarray print(arr.shape) # (2,6) # new_arr = arr.reshape(3,4) # [[ 1 2 3 4 5 6] # [ 7 8 9 10 11 12]] # print(new_arr) # 1 2 3 4 # 5 6 7 8 # 9 10 11 12 # 이렇게 바껴서 출력될 거임 # new_arr[0,0]= 100 # print(new_arr) # print(arr) # reshape() : shape을 바꿔서 새로운 ndarray를 만들어 내는게 아님! # shape을 바꿔서 원래 ndarray에 데이터를 다르게 보여주는 view를 생성 # 즉 모양만 다르게 해서 보여주고 데이터는 하나임 그렇기 때문에 데이터를 바꿔버리면 원본데이터도 바뀌게 됨 # 만약 모양을바꾸고 새로운 ndarray를 생성하고 싶으면 copy()를 이용 new_arr = arr.reshape(3,4).copy() new_arr[0,0]= 100 print(new_arr) print(arr)
결과 [[ 1 2 3 4 5 6] [ 7 8 9 10 11 12]] (2, 6) [[100 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] [[ 1 2 3 4 5 6] [ 7 8 9 10 11 12]]
# reshape()은 내가 원하는 shape의 view를 만들 수 있어요! # ravael()은 무조건 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) new_arr = arr.ravel() # 1차원으로 view를 생성 #new_arr = arr.reshape(12) print(new_arr) # [ 1 2 3 4 5 6 7 8 9 10 11 12]
# resize()는 약간 달라요! arr = np.array([[1,2,3,4,5,6],[7,8,9,10,11,12]]) print(arr) # 2차원의 ndarray print(arr.shape) # (2,6) #new_arr = arr.reshape(3,5) # reshape은 요소수가 맞지 않으면 view가 생성되지 않아요! # new_arr = arr.resize(3,5) # print(new_arr) # None => resize는 복사본을 만들지 않아요. 원본을 변경! # arr.resize(3,5) 이런식으로 새로운 복사본을 만들어줄 필요 없음 arr.resize(3,2) # 3행2열로 출력 포함 안된 값은 버림 그렇기 때문에 데이터 유실이 있을 확률이 큼 # 따라서 잘 사용안함 print(arr) # resize()는 요소의 개수가 같지 않아도 수행이 가능 # 즉 resize()는 원본이 변형이 되면서 shape자체가 변경이 됨 또한 부족한 값은 0으로 채워서 view로 출력함
결과 [[ 1 2 3 4 5 6] [ 7 8 9 10 11 12]] (2, 6) [[1 2] [3 4] [5 6]]
######## 기본적인 사항들 ############# # ndarray의 특징, 속성(shape) # ndarray 생성 # - np.array([1,2,3]) # list를 이용한 ndarray 생성 # - np.ones(), np.zeros(), ... # 다양한 생성 함수 # - np.arrange(), np.linspace() # 다양한 생성 함수 # - np.random.noraml(), 총5가지 # random값을 이용한 ndarray 생성 함수 # 기억해야할 random 관련 함수 # - np.random.seed(), np.random.shuffle(), np.random.choice() # ndarray의 shape과 관련된 중요한 함수들(reshape(), ravel(), resize()) ######## indexing, sliceing ######### (ndarray 사용방법) # arr = np.arange(10,15,1) # [10 11 12 13 14] # print(arr) # print(arr[0]) #10 # 기본적인 index # print(arr[1:3]) # [11 12] # 기본적인 slicing은 python의 list와 동일 # print(arr[1:-1]) # [11 12 13] arr = np.arange(0,12).reshape(3,4) # print(arr) # print(arr[1,2]) # 6 # print(arr[1]) # [4 5 6 7] # print(arr[1,:]) # [4 5 6 7] # 6, 7, 10, 11을 가져와 보자 print(arr[1:,2:]) # [[ 6 7] # [10 11]] # 1행부터끝까지 다, 2열부터 끝까지 다 # 1차원에 대한 indexing과 slicing이 다차원으로 확장
- Boolean Indexing
# Boolean Indexing & Fancy Indexing # 오늘 공부의 하이라이트이다 잘해보도록하자 # Boolean Indexing # indexing 방법 중 하나로 .. boolean mask를 이용해서 indexing 하는 방법 import numpy as np np.random.seed(1) arr = np.random.randint(0, 10, (10,)) print(arr) # [5 8 9 5 0 0 1 7 6 9] # ndarray는 사칙연산이 가능하다 # ndarray의 사칙연산 => +, -, *, / # arr + 10 # ???? 어떻게 연산을 할거냐 # ndarray는 같은 shape에 대해서만 연산이 가능 # arr1 = np.array([1,2,3]) # shape이 (3,) # arr2 = np.array([4,5,6]) # shape이 (3,) # print(arr1 + arr2) # [5 7 9] # 연산의 의미가 python의 연산과 다름 # 같은 위치의 요소들 값끼리 계산이 됨 # 만약 shape이 다르면 오류가남 # arr1 = np.array([1,2,3,4]) # shape이 (4,) # arr2 = np.array([4,5,6]) # shape이 (3,) # 오류 발생 # 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] # print(arr %2 == 0) #[False True False False True True False False True False] # True, False로만 구성된 ndarray를 boolean mask라고 표현! my_mask = (arr % 2 == 0) # boolean indexing은 boolean mask를 가지고 indexing하는 것을 의미 print(arr[my_mask]) # [8, 0, 0, 6] # python의 list 연산 # list1 = [1, 2, 3] # list2 = [4, 5, 6] # print(list1 + list2) # list 연결 [1, 2, 3, 4, 5, 6]이 출력됨 # ndarray는 만약 shape을 맞출 수 있으면 broadcasting이 진행! (차원을 맞춰줘요!) # arr1 = np.array([1,2,3]) # arr1 + 4 # arr1 + [4 4 4] 이런식으로 브로드캐스팅이 진행되어 차원을 맞춰줌 # print(arr1 + 4) # [5 6 7]
- Fancy Indexing
# Fancy Indexing # ndarray에 index 배열을 전달해서 indexing하는 방법(??) # arr = np.array([1,2,3,4,5,6]) # print(arr) # [1 2 3 4 5 6] # 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) # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] # print(arr[0:2, 1:]) # [[1 2 3] # [5 6 7]] # print(arr[0:2, [1,3]]) # [[1 3] # [5 7]] # [[1 3] # [9 11]] 을 출력해보자 print(arr[[0,2], [1,3]]) # [1 11] ??? 왜 안되지???(numpy 내부구조) # 둘다 fancy indexing처리를 하면내부구조때문에 fancy indexing이 무조건 처리 되지 않음 # 그럼 어떻게 해야하는가? 이런경우를 위해 함수를 하나 제공해준다. # np.ix_ 함수를 이용하여 두개다 fancy_indexing처리를 해준다! print(arr[np.ix_([0,2], [1,3])]) #[[ 1 3] # [ 9 11]]