본문 바로가기

STUDY

파이썬 스터디 2주차(머신러닝)

많이 늦었습니다.

 

https://book.naver.com/bookdb/book_detail.nhn?bid=16238302

 

파이썬 머신러닝 완벽 가이드

자세한 이론 설명과 파이썬 실습을 통해 머신러닝을 완벽하게 배울 수 있습니다!《파이썬 머신러닝 완벽 가이드》는 이론 위주의 머신러닝 책에서 탈피해 다양한 실전 예제를 직접 구현해 보면

book.naver.com

 

2. 사이킷런으로 시작하는 머신러닝

1. 사이킷런 소개와 특징

 

사이킷런 : 파이썬 머신러닝 라이브러리 중 가장 많이 사용되는 라이브러리. 

 

 

2. 첫번째 머신러닝 만들어보기 - 붓꽃 품종 예측하기

 

분류(classification) : 대표적인 지도학습(Supervised Learning)방법의 하나. 

- 지도학습 : 명확한 정답이 주어진 데이터를 먼저 학습한 뒤 미지의 정답을 예측하는 방식. 이 때 학습을 위한 데이터 세트를 학습 데이터 세트, 머신러닝 모델의 예측 성능을 평가하기 위한 데이터 세트를 테스트 데이터 세트라 함.

 

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier #트리기반 ML 알고리즘(의사결정트리)
from sklearn.model_selection import train_test_split #train(학습)/test로 데이터 분리

 

* 미리 간단히 정리 * 데이터 세트 분류 예측 프로세스

1. 데이터 세트 분리 : 학습 데이터와 테스트 데이터로 분리

2. 모델 학습 : 학습 데이터를 기반으로 ML 알고리즘을 적용해 모델 학습

3. 예측 수행 : 학습된 ML 모델을 이용해 테스트 데이터 분류 예측

4. 평가 : 결괏값과 테스트 데이터 사이의 실제 값을 비교해 ML 모델 성능 평가

 

import pandas as pd
iris = load_iris()
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
iris_df['label'] = iris.target
iris_df.head()

 

- 학습용 데이터와 테스트용 데이터는 반드시 분리해야 함. 이를 위해 주로 train_test_split() 사용

- train_test_split()은 호출 시 무작위로 데이터를 분리해 수행할 때마다 다른 결과가 나올 수 있음

 

X_train, X_test, y_train, y_test = train_test_split(iris_data, iris.target, test_size=0.2)

 

- 첫 번째 파라미터는 피처 데이터 세트, 두 번째 파라미터는 레이블 데이터 세트, 세 번째 파라미터는 전체 데이터 중 테스트 데이터 세트의 비율을 뜻함. 

- 위 예제코드는 학습용/테스트용(train/test), 피처/레이블(X/y)데이터 세트를 나눠 반환함

 

dt_clf = DecisionTreeClassifier() #의사결정트리 객체 생성
dt_clf.fit(X_train, y_train) #학습용 피처/레이블 데이터 세트를 학습시킴
pred = dt_clf.predict(X_test) #학습된 객체에 테스트용 데이터로 예측 수행

 

from sklearn.metrics import accuracy_score
print(f'예측 정확도 : {accuracy_score(y_test, pred)}') #0.9 전후의 값 도출

 

- 정확도 측정을 위해 accuracy_score() 함수 사용. 첫 파라미터는 실제 레이블 데이터 세트, 두 번째 파라미터는 예측 레이블 데이터 세트

 

 

3. 사이킷런의 기반 프레임워크 익히기

 

  • Estimator 이해 및 fit(), predict() 메서드

- fit()은 ML 모델 학습, predict()는 학습된 모델의 예측을 위해 사용

- 분류 알고리즘 클래스는 Classifier, 회귀 알고리즘 클래스는 Regressor로 지칭하며 이 둘을 합쳐 Estimator 클래스라 함

- 비지도학습을 구현한 클래스도 대부분 fit()과 transform() 적용. 이 때 fit()은 입력 데이터의 형태에 맞춰 데이터를 변환하기 위한 구조를 맞추는 작업이며, 실제 작업은 transform()으로 수행함. 이에 fit()과 transform()을 하나로 결합한 fit_transform()도 있음.

- 일반적인 머신러닝 모델 구축 주요 프로세스는 피처 처리, ML 알고리즘 학습/예측, 모델 평가를 반복해 수행하는 것

 

  • 내장된 예제 데이터셋

- 분류나 회귀를 연습하기 위한 데이터 세트와 분류나 클러스터링을 위한 (표본)데이터 생성기로 나뉨

- 데이터세트는 일반적으로 딕셔너리 형태

(data : 피처의 데이터 세트. ndarray 타입

target : (분류)레이블 값, (회귀)숫자 결괏값 데이터 세트. ndarray 타입

target_names : 개별 레이블의 이름. 넘파이 배열 또는 파이썬 리스트

feature_names : 피처의 이름. 넘파이 배열 또는 파이썬 리스트

DESCR : 데이터 세트에 대한 설명, 각 피처의 설명. 스트링 타입)

- 피처 데이터 값 추출을 위해서는 데이터 세트.data 또는 데이터세트['data']

 

 

4. Model Selection 모듈 소개

 

- 학습/테스트 데이터 세트 분리나 교차검증 분할/평가, Estimator의 하이퍼 파라미터 튜닝을 위한 함수와 클래스 제공

 

  • train_test_split()

- 원본 데이터 세트에서 학습 및 테스트 데이터 세트 분리. 첫 번째 파라미터로 피처 데이터 세트, 두 번째 파라미터로 레이블 데이터 세트를 입력받음

- 반환값은 튜플형태로 학습용 피처 데이터, 테스트용 피처 데이터, 학습용 레이블 데이터, 테스트용 레이블 데이터임

 

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

iris = load_iris()
dt_clf = DecisionTreeClassifier()
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.3)
dt_clf.fit(X_train, y_train)

pred = dt_clf.predict(X_test)
print(f'예측 정확도 : {accuracy_score(y_test, pred)}')

 

  • 교차검증

- 과적합(Overfitting) : 모델이 학습 데이터에만 과도하게 최적화되어 다른 데이터로 예측을 할 경우 성능이 떨어지는 것. 이를 해결하기 위해 교차 검증으로 다양한 학습과 평가를 수행함

 

- 전체 데이터 세트에서 학습 데이터 세트와 테스트 데이터 세트로 나눈 뒤 학습 데이터 세트를 다시 학습/검증 데이터세트로 나눔. 검증 데이터 세트는 학습된 모델을 다양하게 평가하는 데 사용.

- K폴드 교차검증 : 가장 보편적임. K개의 데이터 폴드 세트를 만들어 K번 만큼 각 폴드 세트에 학습/검증 평가를 반복 수행

 

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import KFold
import numpy as np

iris = load_iris()
features = iris.data
label = iris.target
dt_clf = DecisionTreeClassifier()

Kfold = KFold(n_splits=5) #5개의 폴드 세트로 분리
cv_accuracy = [] #폴드 세트별 정확도를 담을 리스트

n_iter = 0
for train_index, test_index in Kfold.split(features): #폴드 별 인덱스를 array로 반환
  #반환된 인덱스로 학습용, 검증용 테스트 데이터 추출
  X_train, X_test = features[train_index], features[test_index]
  y_train, y_test = label[train_index], label[test_index]
  #학습 및 예측
  dt_clf.fit(X_train, y_train)
  pred = dt_clf.predict(X_test)
  n_iter += 1
  #반복할 때마다 정확도 측정
  accuracy = np.round(accuracy_score(y_test, pred), 2) #소수점 둘째자리 반올림
  train_size = X_train.shape[0]
  test_size = X_test.shape[0]
  print(f"{n_iter}번째 교차검증 정확도: {accuracy}, 학습 데이터 크기: {train_size}, 검증 데이터 크기: {test_size}")
  print(f"{n_iter}번째 검증 세트 인덱스: {test_index}")
  cv_accuracy.append(accuracy)

print("평균 검증 정확도:", np.mean(cv_accuracy))

 

- 위 코드로 K폴드 교차검증을 한 결과는 왼쪽과 같다. 이처럼 5개의 폴드 세트로 분리한 경우 4개의 데이터를 학습 데이터, 1개의 데이터를 검증 데이터로 놓고 구성을 바꾸어가며 교차 검증을 해 준 뒤 평균을 구한 것.

 

 

- StratifiedKFold : 불균형(특정 값이 너무 많거나 적은)한 분포도를 가진 레이블 데이터 집합을 위한 것. 원본 데이터의 레이블 분포를 먼저 고려한 뒤 이와 동일하게 학습/검증 데이터 분배.

 

dt_clf = DecisionTreeClassifier()

skfold = StratifiedKFold(n_splits=3)
n_iter = 0
cv_accuracy = []

#StratifiedKFold는 split()에 레이블 데이터 세트도 넣어주어야 함
for train_index, test_index in skfold.split(features, label):
  #split()으로 반환된 인덱스를 활용해 학습용/검증용 데이터 추출
  X_train, X_test = features[train_index], features[test_index]
  y_train, y_test = label[train_index], label[test_index]
  #학습 및 예측
  dt_clf.fit(X_train, y_train)
  pred = dt_clf.predict(X_test)
  n_iter += 1
  accuracy = np.round(accuracy_score(y_test, pred), 2)
  train_size = X_train.shape[0]
  test_size = X_test.shape[0]
  print(f"#{n_iter} 교차 검증 정확도: {accuracy}, 학습 데이터 크기:{train_size}, 검증 데이터 크기:{test_size}")
  print(f"#{n_iter} 검증 세트 인덱스: {test_index}")
  cv_accuracy.append(accuracy)

print("## 교차 검증별 정확도 :", np.round(cv_accuracy, 2))
print("## 평균 검증 정확도 :", np.mean(cv_accuracy))

 

- K폴드는 인덱스값을 기준으로 나누나 Stratified K폴드는 레이블 데이터의 분포에 따라 나누기 때문에 split()에 피처 데이터 세트와 레이블 데이터 세트 둘 다 필요함

 

- iris 원본 데이터셋을 K폴드 방식으로 하는 경우 데이터가 특정 인덱스에 몰려 있는 경우가 많아 제대로 학습이 되지 않음. 위처럼 StratifiedKFold를 사용해야.

- 회귀(Regression)는 연속된 숫자값들이 결정값이기에 Stratified K폴드 사용x, K폴드 사용

 

cross_val_score(estimator, X, y=None, scoring=None, cv=None)

 

- cross_val_score()는 내부에서 Estimator를 학습, 예측, 평가시켜 교차검증을 좀 더 편리하게 해주는 API.

- estimator에 Classifier가 입력되면 StratifiedKFold방식으로 데이터를 분할

- X는 피처 데이터 세트, y는 데이터 레이블 세트, scoring은 예측 성능 평가 지표, cv는 교차 검증 폴드 수. 

- cv로 지정된 횟수만큼 scoring에 입력한 지표의 평과 결과값을 반환하며 이를 평균해 수치로 사용함.

- cross_val_score()는 단 하나의 평가지표만 가능하나 cross_validate()는 여러 평가지표 반환 가능

 

  • GridSearchCV(교차검증 + 최적 하이퍼 파라미터 튜닝)

- 하이퍼 파라미터 : 머신러닝 알고리즘을 구성하는 주요 요소.  값 조정으로 알고리즘 예측 성능 개선 가능.

- GridSearchCV는 교차검증으로 하이퍼 파라미터의 최적값을 찾아줌. 수행시간이 길다는 게 단점.

- 파라미터는 딕셔너리 형태, 하이퍼 파라미터 명칭은 문자열 Key값, 하이퍼 파라미터 값은 리스트형으로 주어야

- GridSearchCV 객체의 fit()은 최고 성능을 나타낸 하이퍼 파라미터 값과 그때의 평과 결과값이 각각 best_params_, best_score_ 속성에 기록됨.

- GridSearchCV 객체 파라미터 refit=True이면 최적의 하이퍼 파라미터로 Estimator를 학습해 best_estimator_로 저장

- 일반적으로 학습 데이터를 GridSearchCV로 최적 하이퍼 파라미터 튜닝을 수행한 뒤 별도의 테스트 세트에서 평가하는 것이 일반적인 머신러닝 모델 적용방법

 

 

5. 데이터 전처리

 

- ML알고리즘만큼 중요. Garbage In, Garbage Out.

- 결손값(Null, NaN)이 있어선 안 됨(다른 값으로 대체하거나 드롭해야 함), 문자열 값 또한 숫자형으로 변환해야 함.

 

  • 데이터 인코딩

- 레이블 인코딩(Label encoding)과 원-핫 인코딩(One Hot encoding)으로 나뉨.

 

- 레이블 인코딩 : 카테고리를 숫자로 변환하는 것. LabelEncoder 클래스로 구현. 

import sklearn
from sklearn.preprocessing import LabelEncoder

plays = ['Doran', 'Keria', 'Gumayusi', 'Keria', 'Deft']
encoder = LabelEncoder() #LabelEncoder 객체 생성
encoder.fit(plays)
labels = encoder.transform(plays) #fit과 transform으로 레이블 인코딩 수행
print("변환값 :",labels)

- Deft가 0, Doran이 1, Gumayusi가 2, Keria가 3이 된 것을 알 수 있음. 그러나 데이터가 많은 경우에는 LabelEncoder.classes_로 확인하거나, LabelEncoder.inverse_transform(변환값)으로 디코딩해 대응시킬 수도 있음

- 카테고리를 숫자로 옮긴 것이라(숫자 크기가 가중치가 아님) 선형회귀같은 것에는 적용하면 안 됨

 

- 원-핫 인코딩 : 피처 값 유형에 따라 새 피처를 추가해 고유 값인 칼럼에만 1, 나머지에는 0 표시. OneHotEncoder 클래스로 구현.

- OneHotEncoder로 변환하기 전에 1. 모든 문자열 값이 숫자형 값으로 변환되어야(레이블인코딩 먼저)하고 2. 입력값이

2차원 데이터여야 함

 

from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
import numpy as np

plays = ['Doran', 'Keria', 'Gumayusi', 'Keria', 'Deft']
l_encoder = LabelEncoder()
l_encoder.fit(plays)
labels = l_encoder.transform(plays) #여기까진 앞의(레이블 인코딩) 과정과 같음
labels = labels.reshape(-1, 1) #2차원으로 변환

#원-핫 인코딩
oh_encoder = OneHotEncoder()
oh_encoder.fit(labels)
oh_labels = oh_encoder.transform(labels)
print("원-핫 데이터:\n", oh_labels.toarray())
print("원-핫 차원:", oh_labels.shape)

 

- get_dummies()를 사용하면 위같이 LabelEncoding을 거치지 않고도 원-핫 인코딩이 가능. 코드는 아래와 같음.

import pandas as pd
pd.get_dummies(pd.DataFrame({'plays':
['Doran', 'Keria', 'Gumayusi', 'Keria', 'Deft']}))

 

- 기존의 원-핫 인코딩 결과와 같은 결과가 나옴

 

 

  • 피처 스케일링과 정규화

- 피처 스케일링 : 서로 다른 변수 값 범위를 일정 수준으로 맞추는 작업. 표준화와 정규화가 있음

- 표준화(Standardization) : 데이터 피처 각각을 평균이 0이고 분산이 1인 가우시안 정규분포 값으로 변환하는 것. '(기존값-평균)/표준편차'

- 정규화(Normalizaiton) : 서로 다른 피처의 크기 단위를 통일해주는 것. '(기존값-최솟값)/(최댓값-최솟값)'. 사이킷런의 Normalizer는 선형대수 정규화 개념을 사용해 벡터 크기를 맞추는 것을 의미함. '기존값/루트(x^2+y^2+z^2)'

 

  • StandardScaler : 데이터가 가우시안 정규분포를 가질 수 있도록 표준화를 지원하는 클래스
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
import pandas as pd

iris = load_iris()
iris_data = iris.data
iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)

scaler = StandardScaler()
scaler.fit(iris_df) #데이터세트 변환
iris_scaled = scaler.transform(iris_df)
#스케일 변환된 데이터셋은 Numpy Ndarray형태

iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print('feature 평균값:\n', iris_df_scaled.mean())
print('feature 분산값:\n', iris_df_scaled.var())

 

  • MinMaxScaler : 데이터가 가우시안 정규분포가 아닌 경우 데이터값을 0과 1사이의 범위값으로 변환하는 클래스. 사용법은 StandardScaler와 동일.
from sklearn.preprocessing import MinMaxScaler

iris = load_iris()
iris_data = iris.data
iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)

scaler = MinMaxScaler()
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df) #데이터세트 변환
#스케일 변환된 데이터셋은 Numpy Ndarray형태

iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print('feature 최솟값:\n', iris_df_scaled.min())
print('feature 최댓값:\n', iris_df_scaled.max())

 

  • 스케일링 변환 시 유의점

- 학습 데이터로 fit()을 적용한 스케일링 기준 정보를 그대로 테스트 데이터에 적용(transform)해야 함

- fit_transform()은 테스트 데이터에서 절대 사용하면 안 됨

- 전체 데이터에 스케일링 변환을 적용한 뒤 학습/테스트 데이터세트를 분리하는 것이 가장 좋음

 

 

6. 사이킷런으로 수행하는 타이타닉 생존자 예측(생략)

 

 

7. 정리

 

- 머신러닝 API : 데이터 전처리(가공, 변환) -> (학습/테스트)데이터세트 분리 -> 모델 학습 -> (테스트)데이터 예측 -> 모델 평가

- 오류데이터 보정, Null처리, LabelEncoding, OneHotEncoding, 데이터 스케일링/정규화, KFold, StratifiedKFold, cross_val_score(), GridSearchCV

 


 

책을 1독하며 형광펜을 긋고, 후에 블로그 글을 쓰며 코드를 짜보는데 전자보다 후자가 1.5배~2배 이상 시간이 걸리네요.

1독 > 코딩 > 블로그 리뷰 순으로 바꿔볼까 고민중입니다. 밀린 게 많지만 멈추면 더 쌓이니 차근차근 해나가야죠!!

'STUDY' 카테고리의 다른 글

파이썬 스터디 3주차(캐글)  (0) 2022.01.26
파이썬 스터디 3주차(백준)  (0) 2022.01.25
파이썬 스터디 2주차(캐글)  (0) 2022.01.13
파이썬 스터디 2주차(백준)  (0) 2022.01.11
파이썬 스터디 1주차(머신러닝)  (3) 2022.01.11