https://book.naver.com/bookdb/book_detail.nhn?bid=16238302
1. 파이썬 기반의 머신러닝과 생태계 이해
01. 머신러닝의 개념
머신러닝 : 애플리케이션을 수정하지 않고도 데이터를 기반으로 패턴을 학습하고 결과를 예측하는 알고리즘 기법.
- 지도학습(Supervised Learning), 비지도학습(Un-supervised Learning), 강화학습(Reinforcement Learning)으로 나뉨.
- 데이터에 매우 의존적임(Garbage In, Garbage Out)
02. 파이썬 머신러닝 생태계를 구성하는 주요 패키지
머신러닝을 가장 빠르게 익히는 방법 중 하나는 다른 사람이 만든 소스코드를 이해하고 그것을 자기 것으로 흡수하기 위해 많은 코드를 스스로 만들어 보는 것.
03. 넘파이
넘파이NUMerical PYthon : 파이썬에서 선형대수 기반의 프로그램을 쉽게 만들 수 있도록 지원하는 대표적인 패키지. 많은 머신러닝 알고리즘이 넘파이 기반으로 작성되어 있기 때문에 이를 이해하는 것이 파이썬 기반의 머신러닝에서 매우 중요함.
- Ndarray : 넘파이의 기반 데이터 타입. 다차원(Multi-dimension)배열을 쉽게 생성하고 다양한 연산을 수행할 수 있다.
array1 = np.array([1, 2, 3]) #1차원
array2 = np.array([['a', 'b', 'c'], ['d', 'e', 'f']]) #2차원
array3 = np.array([[1, 2, 3]]) #2차원
- ndarray.shape는 ndarray의 차원과 크기를 튜플(tuple) 형태로 나타내줌. array1은 (3, ) array2는 (2, 3) array3은 (1, 3)
list1 = [1, 2.0, 3.0]
array1 = np.array(list1)
#[1. 2. 3.] 출력. dtype으로 확인하면 float64(실수)
array1_=array1.astype('int32')
#[1 2 3] 출력. dtype으로 확인하면 int32(정수)
- ndarray 내의 데이터 값은 숫자, 문자, 불 값 모두 가능하지만 연산 특성상 같은 데이터 타입만 가능. 만약 다른 데이터 유형이 섞여 있는 리스트를 ndarray로 변경하면 데이터 크기가 더 큰 타입으로 형 변환이 일괄 적용됨.
- ndarray 내의 데이터값 타입 변경은 astype() 매서드 사용. 메모리를 절약해야 할 때 주로 이용함.
array1 = np.arange(1, 8, 2) #[1 3 5 7] 출력(1부터 7(=8-1)까지 2씩 띄움)
array2 = np.zeros((2, 2)) #2x2의 shape를 가진, 0으로만 구성된 ndarray
array3 = np.ones((3, 2), dtype='float32') #3x2의 shape를 가진, 1.0으로만 구성된 ndarray
- arange()는 array를 range()로 표현하는 것. range와 유사하게 start값을 부여하는 것 또한 가능.
- zeros()는 인자로 튜플 형태의 shape를 입력하면 모든 값을 0으로 채운 shape의 ndarray를, ones()는 모든 값을 1로 채운 shape의 ndarray 반환(default dtype은 float).
array1 = np.arange(8)
array2 = array1.reshape(2, -1)
#[[0 1 2 3]
# [4 5 6 7]]출력. 4개의 1차원과 호환되는 로우 2개에 맞는 칼럼 개수는 4이므로 2x4
- reshape()는 ndarray를 특정 차원 및 크기로 변환하나 변경이 불가능한 경우에는 오류가 발생함. -1을 인자로 사용해 원래의 ndarray와 호환되는 shape로 변환 가능.
- reshape(-1, 1)은 원본 ndarray가 어떤 형태이더라도 2차원이면서 1개의 칼럼을 가진 ndarray로 변환시킴
- 인덱싱
array1 = np.arange(1, 10).reshape(3, 3) #1부터 9까지를 3x3으로 배열
array1[0, 0] = 9
array1[-1, -1] = 1
#(0, 0)위치의 1을 9로, (-1, -1)위치의 9를 1로 바꿈
1. 특정 데이터만 추출: 원하는 위치의 인덱스 값 지정
- 인덱스는 0부터 시작하며, 마이너스 기호를 사용하면 맨 뒤에서부터 데이터 추출
- ndarray 내의 데이터 값 수정 또한 가능
- 2차원 데이터의 경우 콤마로 분리된 로우와 칼럼 위치 인덱스로 접근해 추출
- axis 0은 로우 방향의 축, axis 1은 칼럼 방향의 축. 디폴트값은 axis 0.
array2 = np.arange(1,10).reshape(3,3)
array2[:2, :] #인덱스값 1인 2행까지([[1 2 3] [4 5 6]])
array2[2] #인덱스값 2인 3행([7, 8, 9])
2. 슬라이싱(Slicing): 연속된 인덱스상의 ndarray 추출
- ':' 기호 이용. `시작:종료`면 시작~종료-1 위치의 데이터 ndarray를 반환.
- 시작, 종료 인덱스 생략 가능(시작 생략은 처음부터, 종료 생략은 마지막까지, 둘다 생략은 처음~마지막까지)
- 2차원 ndarray에서 뒤 인덱스(칼럼)를 없애면 1차원 ndarray반환(로우 축(axis 0)의 로우만 반환). array2[2]를 array3라 저장하고 array3.shape로 확인해보면 (3, )!
array3 = np.arange(1,10).reshape(3,3)
array3[[0,1]] #((0,:), (1,:))인덱싱 적용. [0:2, :]과 동일.
array4 = np.arange(9) #0부터 8까지 9개의 숫자로 구성된 array
array4[[True,False,True,True,False,False,False,False,True]] #array([0, 2, 3, 8])
3. 팬시 인덱싱(Fnacy Indexing): 일정 인덱싱 집합을 리스트나 ndarray로 지정해 해당 위치의 데이터 ndarray 반환
4. 불린 인덱싱(Boolean Indexing) : True/False 값 인덱싱 집합 기반으로 True 인덱스 위치의 데이터 ndarray 반환
- []내에 조건문을 그대로 기재해 사용하거나 결과로 반환된 ndarray 객체 자체를 넣음.
- 행렬
array1 = np.array([3, 6, 1, 5, 9])
array2 = np.sort(array1)[::-1] #[9 6 5 3 1]
array3 = array1.sort() #array3은 None임. array1을 프린트 해 보면 [1, 3, 5, 6, 9]
- 넘파이 행렬 정렬은 np.sort()와 ndarray.sort() 크게 두 가지
- np.sort()는 원 행렬은 그대로 두고 정리된 행렬을 반환, ndarray.sort()는 원 행렬을 정렬하고 반환값 None
- 둘다 기본적으로는 오름차순 정렬. 내림차순으로 하기 위해서는 [::-1] 사용
array1 = np.array([[3, 2], [1, 6]])
array1_ = np.sort(array1, axis=0) #[[1 2], [3 6]]
array2 = np.array([3, 2, 9])
array2_ = np.argsort(array2) #[1 0 2], type은 numpy.ndarray
- 행렬이 2차원 이상일 경우 axis 축 값 설정을 통해 로우 방향(axis=0) 또는 칼럼 방향(axis=1)으로 정렬도 가능
- 원본 행렬이 정렬되었을 때 기존 원본 행렬의 원소에 대한 인덱스가 필요할 때 np.argsort()이용. 반환값은 ndarray형.
- 내림차순 정렬 시 원본 행렬의 인덱스를 구하는 것도 np.argsort()[::-1]
names = np.array(['Zeus', 'Oner', 'Faker', 'Gumayusi', 'Keria'])
awards = np.array([0, 0, 19, 0, 7])
sort_awards = np.argsort(awards)[::-1] #names[sort_awards]하면 ['Faker' 'Keria' 'Gumayusi' 'Oner' 'Zeus']
- 넘파이의 ndarray는 메타 데이터를 가질 수 없으므로 실제 값과 그 값이 뜻하는 메타 데이터를 별도의 ndarray로 각각 가져야만 함.
A = np.array([[2021, 2022], [2020, 2019]])
B = np.array([[1], [-2]])
dots = np.dot(A, B) #[[-2023], [-2018]] (=2021-4044, 2020-4038)
#np.transpose(A)하면 [[2021, 2020], [2022, 2019]]
- 행렬 내적 = 행렬 곱. np.dot()
- 두 행렬 A와 B의 내적은 A의 로우(행)와 B의 칼럼(열)의 원소들을 순차적으로 곱한 뒤 그 결과를 모두 더한 값.
- 전치행렬 : 원 행렬에서 행과 열 위치를 교환한 원소로 구성한 행렬. np.transpose()로 쉽게 구할 수 있음.
04. 데이터 핸들링 - 판다스
판다스 : 행과 열로 이루어진 2차원 데이터를 효율적으로 가공/처리할 수 있는 다양하고 훌륭한 기능 제공!
- DataFrame : 판다스의 핵심 객체. 여러 개의 행과 열로 이루어진 2차원 데이터를 담는 데이터 구조체.
- Index와 Series이해가 중요 :: Index는 개별 데이터를 고유하게 식별하는 Key값. Series는 칼럼이 하나뿐인 데이터 구조체로, Index를 key값으로 가짐
- DataFrame은 여러 개의 Series로 이루어졌다고 할 수 있음
- read_csv()는 csv뿐만 아니라 어떤 필드 구분 문자 기반 파일 포맷도 DataFrame으로 변환 가능. 인자인 sep에 해당 구분문자를 입력해주면 됨
- read_csv()엔 로드하려는 데이터 파일의 경로를 포함한 파일명을 입력해 주어야 함
- read_csv()는 별 다른 파라미터 지정이 없다면 파일의 맨 처음 로우를 칼럼 명으로 인지하고, 칼럼으로 변환함
- 모든 DataFrame 내의 데이터는 생성되는 순간 고유의 Index 값을 가지게 됨.
- DataFrame.head()는 DataFrame의 맨 앞에 있는 N개(파라미터)의 로우 반환, DataFrame.shape()는 DataFrame의 행과 열을 튜플 형태로 반환
- DataFrame.info()로 칼럼 타입, Null 데이터 개수, 데이터 분포도 등의 메타데이터 조회 가능
- describe()는 칼럼별 수치형 데이터의 정보만 알려줌(object 타입의 칼럼은 출력에서 제외)
-DataFrmae의 []연산자 내부에 칼럼 명을 입력하면 Series 형태로 특정 칼럼 데이터 세트 반환.
- value_counts는 반환된 Series에 호출했을 때 해당 칼럼 값의 유형과 건수 확인 가능. 반환값 역시 Series
- Series는 Index와 단 하나의 칼럼으로 구성된 데이터 세트. 모든 Series와 DataFrame은 인덱스를 가짐
- 인덱스는 고유성이 보장된다면 의미 있는 데이터값 할당도 가능!
- DataFrame-리스트-딕셔너리-넘파이ndarray 상호변환
- DataFrame은 파이썬 리스트, 딕셔너리, 넘파이 ndarray 등으로부터 생성될 수 있으며 반대로 DataFrame도 파이썬 리스트, 딕셔너리, 넘파이 ndarray 등으로 변환될 수 있음
- DataFrame은 기본적으로 행과 열을 가지는 2차원 데이터 : 2차원 이하의 데이터들만 DataFrame으로 변환될 수 있음
- 딕셔너리를 DataFrame으로 변환하는 경우 딕셔너리의 Key는 칼럼명, Value는 칼럼 데이터.
- DataFrame 객체의 values를 이용하면 DataFrame을 넘파이 ndarray로 변환. 이 ndarray에 tolist()를 호출하면 리스트로 변환
- DataFrame 객체에 to_dict('list')를 써주면 딕셔너리 값을 리스트형으로 반환
- DataFrame의 칼럼 데이터 세트 생성과 수정도 []연산자로 가능.
- 넘파이 ndarray에 상숫값을 할당할 때 모든 ndarray값에 일괄 적용되는 것처럼, Series에 상숫값을 할당할 때에도 Series의 모든 데이터셋에 일괄 적용됨.
- DataFrame의 데이터 삭제는 drop()메서드 활용. drop() 메서드 원형은
DataFrame.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors='raise')
- axis 0은 로우방향 축, axis 1은 칼럼 방향 축.
- axis 0이면 DataFrame은 자동으로 labels에 오는 값을 인덱스로 간주.
- 주로 axis 1으로 설정하고 칼럼을 드롭하는 경우가 많음. aixs 0으로 설정할 때에는 이상치를 삭제하는 경우.
- Inplace=False는 삭제된 결과 DF만 반환, inplace=True는 자기 자신의 DF 데이터를 삭제하고 None을 반환. 그러므로 inplace=True로 설정한 반환값을 다시 원 DF객체로 할당하면 안 됨! 객체변수가 None이 되기 때문.
- Index
- Index : DataFrame, Series의 레코드를 고유하게 식별하는 개체.
- 실제 값은 넘파이 1차원 ndarray. values 속성으로 ndarray 값을 알 수 있음.
- 한 번 만들어진 DataFrame, Series의 Index 객체는 함부로 변경 불가
- Index는 오직 식별용임. Series 객체에 연산 함수를 적용할 때 Index는 연산에서 제외됨.
- DataFrame 및 Series에 reset_index()를 수행하면 새로운 숫자 인덱스를 할당하며 기존 인덱스는 'index'라는 새 칼럼명으로 추가됨. 이는 인덱스를 연속된 int 숫자형 데이터로 만들기 위해 사용
- Series에 reset_index()를 적용하면 기존 인덱스가 칼럼으로 변환되어 Series가 아닌 DataFrame이 반환됨
- reset_index() 파라미터로 drop=True를 설정하면 기존 인덱스가 새 칼럼('index')으로 추가되지 않고 삭제되며, Series에 적용할 경우 Series로 유지됨
- 데이터 셀렉션
- 넘파이와 유사하면서도 달라 혼동하기 쉬움
- 넘파이의 []연산자 : 행 위치, 열 위치, 슬라이싱 범위 등을 지정해 데이터를 가져옴
- 판다스의 []연산자 : (DataFrame 뒤에서) 칼럼 명 문자(칼럼 명 리스트 객체), 인덱스로 변환 가능한 표현식만 사용해 데이터를 가져옴
(ix는 다루지 않겠습니다)
- DataFrame.loc[] : 칼럼 명칭 기반 인덱싱 연산자. 슬라이싱을 적용할 경우 종료 값 까지 포함(숫자형이 아닐 수 있기 때문). 불린 조건을 입력해주면 불린 인덱싱 가능
- DataFrame.iloc[] : 칼럼 위치 기반 인덱싱 연산자. 행과 열 값으로 int, int형 슬라이싱, 팬시 리스트 값을 주어야함. 불린
불가
- DataFrame 인덱스 값은 명칭 기반 인덱싱(=명칭 기반과 위치 기반 데이터 형이 서로 같을 경우 명칭 기반이 우선함)
- 복합조건도 사용 가능(and는 &, or는 |, Not은 ~). 개별 조건을 ()로 묶고 복합 조건 연산자 사용
- 정렬, Aggregation, Groupby
- sort_values() : DataFrame과 Series의 정렬을 위해 사용. SQL의 order by와 유사.
- 주요 입력 파라미터는 by(해당 칼럼으로 정렬 수행), ascending(=True는 오름차순, =False는 내림차순), inplace.
- 여러 개의 칼럼으로 정렬하려면 by에 리스트 형식으로 칼럼 입력
- DataFrame에서의 aggregation 함수 적용은 SQL의 aggregation 함수 적용과 유사하나 바로 aggregation을 호출할 경우 모든 칼럼에 적용해줌.
- 특정 칼럼에만 aggregation 함수를 적용하기 위해선 대상 칼럼만 추출해 aggregation( df[['승률', '픽률']].mean() )
- DataFrame의 groupby()는 SQL의 groupby 키워드와 유사
- 입력 파라미터 by에 칼럼을 입력하면 대상 칼럼으로 groupby하며 DataFrameGroupBy라는 다른 DataFrame 반환
- DataFrameGroupBy에 aggregation을 호출하면 groupby() 대상 칼럼을 제외한 모든 칼럼에 aggregation 적용
- 특정 칼럼만 aggregation을 적용하려면 DataFrameGroupBy 객체에 해당 칼럼들을 필터링 한 뒤 aggregation 적용
- 여러 aggregation 함수를 적용할 경우, 함수 명을 DataFrameGroupBy의 agg()내에 인자로 입력해 사용
( df.groupby('티어')['픽률'].agg([max,min]) )(티어에 따라 groupby된 객체의 픽률 max, min)
- 각각의 처리가 필요한 경우 agg()내 입력값으로 딕셔너리 형태의 aggregation 적용 칼럼과 함수 입력
- Missing Data 처리하기
- 결손 데이터(Missing Data) : 칼럼에 값이 없는 NULL인 경우. 넘파이의 NaN이 해당. 평균, 총합 등의 함수 연산에서 제외되어 머신러닝 알고리즘으로 처리되지 않아 때문에 다른 값으로 대체해야 함.
- NaN 여부를 확인하는 API는 isna(), NaN 값을 다른 값으로 대체하는 API는 fillna()
- DataFrame.isna()는 모든 칼럼 값이 NaN인지 아닌지 불린으로 알려줌. sum()으로 결손 데이터 개수를 구함
- DataFrame.fillna()는 결손 데이터를 ()안의 인자로 대체해 반환함. default는 inplace=False
- apply lambda
- 판다스에서는 apply 함수에 lambda 식을 결합해 DataFrame이나 Series 레코드별로 데이터 가공 가능
- lambda는 함수 선언과 함수 내 처리를 한 줄로 쉽게 변환한 식.
year = [-3, -2, -1]
years = list(map(lambda x : x+2022, year))
print("Keria", years, "수상 축하합니다") #Keria [2019, 2020, 2021] 수상 축하합니다
- 위 식에서 ':' 왼쪽인 x는 입력 인자, ':' 오른쪽인 x + 2022는 입력인자의 계산식(반환값).
- lambda 식에서 여러 값을 입력 인자로 받아야 할 때는 map()함수 사용
- lambda 식은 if else를 지원하나 if 절은 if 식보다 반환값이 먼저, else는 else가 먼저 옴
- if~else만 지원하고 if, else if, else는 지원x
05. 정리
- 넘파이와 판다스는 머신러닝 학습을 위해 정복해야 할 매우 중요한 요소
- 머신러닝 프로그램을 직접 만들면서 이해하고 모르는 부분을 찾아보는 게 학습을 위한 제일 빠른 방법
- 실제로 머신러닝 모델 생성/예측 수행에 있어 알고리즘보다 데이터 전처리, 가공/추출이 더 많은 비중을 차지함.
- 사이킷런에 대한 이해도 중요하나 다양한 패키지에 대한 이해 역시 매우 중요
1.24 기준 한번 정리해 보았는데, 그래도 여전히 필사의 느낌이 남아있네요. 추후에 또 간추릴 수 있으면 좋겠습니다.
'STUDY' 카테고리의 다른 글
파이썬 스터디 2주차(캐글) (0) | 2022.01.13 |
---|---|
파이썬 스터디 2주차(백준) (0) | 2022.01.11 |
파이썬 스터디 1주차(백준, 캐글) (4) | 2022.01.07 |
코드잇 대학생 코딩캠프 - 업무자동화 for Windows(1) (0) | 2021.09.07 |
코드잇 대학생 코딩캠프 - 데이터 사이언스 입문(2) (0) | 2021.08.12 |