반응형

적당량의 데이터로 머신러닝, 딥러닝을 돌려 성능을 내는것이 중요

비지도학습에서 군집화에 관심이 있다면 K-Means Clustering과 Hierarchical Clustering에 관해 공부
차원 축소에 관심이 있다면 주성분 분석(PCA) 혹은 t-SNE에 관해 공부
기본적인 강화 학습 알고리즘에는 Q-Learning, DQN 등에 관해 공부

🔥총 정리

모델링
성능 향상
클래스 불균형
지도학습
- 분류 회귀
알고리즘 DecisionTreeClassifier
KNeighborsClassifier
LogisticRegression
나이브 베이즈(Naive Bayes)
서포트 벡터 머신(SVM)
신경망(ANN)

👇 앙상블
RandomForestClassifier
XGBClassifier
LinearRegression
KNeighborsRegressor
DecisionTreeRegressor
RandomForestRegressor
XGBRegressor
Ridge
Lasso
평가 방법 accuracy_score
recall_score
precision_score
classification_report
confusion_matrix
mean_absolute_error
mean_squared_error
root mean_squared_error
mean_absolute_percentage_error
☝️ 작을수록 좋은 지표들
👇 클수록 좋은 지표
r2_score
  • 평가방법
    • model.predict_proba(x_test)
      • 이 데이터셋이 y의 컬럼값일 확률
    • model.score(feature, test)
      • 모델의 적합도를 확인
      • model.score(x_train, y_train)과 model.score(x_test, y_test)를 비교해서 과대적합, 과소적합을 확인가능
        • 과대 적합 : train의 score는 높은데 test의 score는 떨어지는 경우
        • 과소 적합 : train과 test 둘다 낮거나 train보다 test의 score가 훨씬 높은경우
    • 분류
      • accuracy, classification_report를 자주 사용(score 함수 시 accuracy_score)
    • 회귀
      • R2와 MAE를 자주 사용(score함수 시 r2 score)

비지도 학습



결측치_채우기

1. 필요없는 컬럼 제거

  • 기준
    • 결측치가 너무 많은데 이 결측치를 채울 방법이 없는 경우
    • Unique한 값이고 그저 데이터를 구분하기 위한 값인 경우
      • 사람 이름, 고객 번호
drop_cols = ['Cabin', 'PassengerId', 'Name', 'Ticket']  

# 1. inplace, 이때 inplace를 쓰면 반환값은 None이라서 None을 대입하는 식의 선언은 사용하지 말것
# titanic = titanic.drop(drop_cols, axis=1, inplace=True) => 불가
titanic.drop(drop_cols, axis=1, inplace=True)

# 2. 앞에서 받기
titanic = titanic.drop(drop_cols, axis=1)

결측치

  • 모든 결측치 제거
    • titanic.dropna(axis=0, inplace=True)
  • 결측치 중 특정 컬럼의 결측치만 제거
    • subset 매개변수 활용
    • titanic.dropna(subset=['Age'], axis=0, inplace=True)
  • 특정 값으로 채우기
    • 평균, 최빈값인 경우가 많음
      • 단순한 평균이 좋을 수도 있지만 특정 카테고리별 평균을 채우는 것이 더 성능이 좋을 수 있음
      • 모집단의 크기가 작아지고, 그 집단의 특성이 반영
      • 다만 확실히 이게 좋다 라고 말하긴 힘듦
    • titanic['Age'].fillna(titanic['Age'].mean(), inplace=True)
  • 바로 앞의 값, 뒤의 값으로 대체
    • air['Ozone'].fillna(method='ffill', inplace=True)
    • air['Solar.R'].fillna(method='bfill', inplace=True)
  • 선형값으로 채우기
    • air['Ozone'].interpolate(method='linear', inplace=True)

# 모든 결측치 제거
titanic.dropna(axis=0, inplace=True)

# Age 변수에 NaN이 포함된 행 제거  
titanic.dropna(subset=['Age'], axis=0, inplace=True)  

# NaN을 평균값으로 채우기  
titanic['Age'].fillna(titanic['Age'].mean(), inplace=True)

# Embarked 변수 값 확인  
titanic['Embarked'].value_counts(dropna=True)

# NaN 값을 가장 빈도가 높은 값으로 채우기  
titanic['Embarked'].fillna('S', inplace=True)

# Ozone 변수 NaN 값을 바로 앞의 값으로 채우기  
air['Ozone'].fillna(method='ffill', inplace=True)  

# Solar.R 변수 NaN 값을 바로 뒤의 값으로 채우기  
air['Solar.R'].fillna(method='bfill', inplace=True)

# 선형 보간법으로 채우기  
air['Ozone'].interpolate(method='linear', inplace=True)

# 가장 가까운 이웃값으로 채우기
air['Ozone'].interpolate(method='nearest', inplace=True)

결측치 채우기 블로그 글


train_test_split

  • stratify = y
    • y를 기준으로 데이터를 분할
    • y에서 특정 값이 적을 때 사용하면 좋음

# 모듈 불러오기  
from sklearn.model_selection import train_test_split  

# 7:3으로 분리  
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1, stratify=y)




가변수화

범주형 값을 갖는 변수에 대한 가변수화를 진행

One-Hot Encoding

  • 다중 공선성을 위해 drop_firtst =True
    • 최소한의 컬럼만 가지고 가변수화 작업을 수행하는 것이 효과적
    • 나중에 원핫 인코딩을 하게 되면 importance를 볼때 첫번째 컬럼은 볼 수 없음
  • 가변수화를 통해 서로 독립적으로 만듦(독립변수를 만듦)

# 가변수 대상 변수 식별  
dumm_cols = ['Pclass', 'Sex', 'Embarked']  

# 가변수화  
titanic = pd.get_dummies(titanic, columns=dumm_cols, drop_first=True)

Lable Encoding

  • 문자열 카테고리 값을 숫자형 카테고리 값으로 변환
  • 예) 상품 데이터
    • 상품 구분 : TV, 냉장고, 전자레인지, 컴퓨터, 선풍기, 믹서
    • 숫자로 변환 : TV->1, 냉장고->2, 전자레인지->3 등
    • 주의! 01, 02는 문자열이므로 1, 2로 적어야 함

from sklearn.preprocessing import LabelEncoder

items = ['TV', '냉장고', '전자레인지', '컴퓨터', '선풍기', '선풍기', '믹서', '믹서']

# LabelEncoder 객체 생성한 후 fit()과 transfrom()메서드로 label 인코딩 수행
encoder = LabelEncoder()
encoder.fit(items)
labels = encoder.transform(items)

print('인코딩 변환값 :', labels)

인코딩 변환값 : [0 1 4 5 3 3 2 2]

# 인코딩 전 원래 값 확인 : classes_ 속성
print('인코딩 클래스 :', encoder.classes_)

인코딩 클래스 : ['TV' '냉장고' '믹서' '선풍기' '전자레인지' '컴퓨터']

# 인코딩 된 값 디코딩 하기 : inverse_transform()
# 어떤 순서로 디코딩 하냐에 따라 원본 값 순서가 달라짐
print('디코딩 원본 값 : ', encoder.inverse_transform([0, 1, 4, 5, 3, 3, 2, 2]))
print('디코딩 원본 값 : ', encoder.inverse_transform([4, 5, 2, 0, 3, 3, 1, 2]))

디코딩 원본 값 :  ['TV' '냉장고' '전자레인지' '컴퓨터' '선풍기' '선풍기' '믹서' '믹서']
디코딩 원본 값 :  ['전자레인지' '컴퓨터' '믹서' 'TV' '선풍기' '선풍기' '냉장고' '믹서']

주의점
  • 간단하게 문자열 값을 숫자형 값으로 변환하지만 이는 단순 코드일 뿐 크기와는 상관 없음
  • 일부 ML 알고리즘에서 이를 적용할 경우 예측 성능이 떨어지는 경우 발생
  • 숫자 값의 크기 특성이 작용하기 때문
    • 즉, 냉장고가 1 믹서가 2로 변환되면 1보다 2가 더 큰 값이므로 가중치가 부여되거나 더 중요하게 인식될 가능성이 발생함
  • 이런 특성 때문에 레이블 인코딩은 선형 회귀와 같은 ML 알고리즘에서는 적용하지 않음
  • 트리 류의 ML알고리즘은 숫자의 이런 특성을 반영하지 않기 때문에 레이블 인코딩 적용할 때 문제 없음


스케일링

크기를 조절하는 작업

  • 거리를 따지는 경우 스케일링이 효과적일 확률이 높음
  • 평가용 데이터도 학습용 데이터를 기준으로 스케일링을 수행함
  • knn, support vector 머신의 경우 정규화 혹은 표준화가 사용됨

1. 정규화(Normalization)

  • 각 변수의 값이 0과 1 사이의 값이 됨
    $$\large X_{norm} = \frac{x-x_{min}}{x_{max}-x_{min}}$$

# 함수 불러오기

from sklearn.preprocessing import MinMaxScaler

# 정규화
scaler = MinMaxScaler() 
scaler.fit(x_train)  
x_train = scaler.transform(x_train) 
x_test = scaler.transform(x_test)

2. 표준화(Standardization)

  • 각 변수의 평균이 0, 표준편차가 1
    $$\large X_Z = \frac{x-x_{mean}}{x_{std}}$$
from sklearn.preprocessing import StandardScaler
col_names = df.iloc[:, 1:-1].columns
scaler = StandardScaler()
df_standard = scaler.fit_transform(df.iloc[:, 1:-1])

standard = pd.DataFrame(df_standard, columns = col_names)
standard

3. Robust Scaler

  • 각 feature의 median(Q2)에 해당하는 데이터를 0으로 잡고 Q1, Q3 사분위수와의 IQR 차이 만큼을 기준으로 정규화를 진행
    • 평균 대신 Median을 사용하고 표준편차 대신 사분위값을 사용한다는 차이점
    • 이상치에 매우 강함

$$\large x' = \frac{x-median(x)}{Q3-Q1}$$

  • $x'$ : Robust Standardised Value
  • x : Origin Value
  • medina(x) : Sample Median
  • Q3 - Q1 : IQR차이

from sklearn.preprocessing import RobustScaler
col_names = df.iloc[:,1:-1].columns
scaler = RobustScaler()
df_robust = scaler.fit_transform(df.iloc[:,1:-1])

robust = pd.DataFrame(df_robust, columns = col_names)
robust

4. MaxAbs Scaler

    • 각 특성의 절댓값이 0과 1사이가 되도록 스케일링
  • 모든 값은 -1과 1사이가 되며, 모든 데이터가 양수일 경우에는 MinMax Scaler와 같은 결과값
  • 이상치에 매우 민감

$$\large x_{scaled} = \frac{x}{max(|x|)}$$


from sklearn.preprocessing import MaxAbsScaler
col_names = df.iloc[:,1:-1].columns
scaler = MaxAbsScaler()
df_maxabs = scaler.fit_transform(df.iloc[:,1:-1])

maxabs = pd.DataFrame(df_maxabs, columns = col_names)
maxabs

5. 로그 변환(Log transformation)

  • 로그 변환을 통해 왜도와 첨도를 가진 변수를 정규분포에 가깝게 만들어 줌
  • 큰 수치를 같은 비율의 작은 수치로 변환
    • sns의 displot으로 왜도와 첨도 확인 필요
    • 분포가 뾰족하고 한쪽으로 쏠려있다면 로그 변환 필요
  • 로그변환과 스케일링 차이
    • 로그 변환
      • 개별 feature, target의 분포도가 skew가 심하면 log변환
    • 스케일링
      • 전체 데이터의 스케일링을 표준 정규 분포 형태로 맞추고 싶을 경우

sns.distplot(df['col'])

#로그변환
np.log1p(df['col])

🤔 평가용 데이터와 훈련용 데이터가 합쳐진 상태에서 스케일링하면 편하지 않을까?

  • 평가용 데이터는 미래의 데이터
    • 그렇기에 평가용 데이터와 훈련용 데이터가 합쳐진 상태에서는 스케일링을 하지 않고 분리 후 훈련용데이터를 기준으로 스케일링 후 평가용 데이터 또한 동일한 스케일러를 활용해야 함

🤔 그렇다면 평가용 데이터는 정규화를 할 경우 1을 넘을 수도 있지 않느냐?

  • 어쩔 수 없다. 미래의 데이터는 우리는 모르는 것인데 미래에 들어온 값이 정확히 우리의 훈련용 데이터 셋의 범위 내에서 올 거라고는 장담할 수 없음

🤔 언제 스케일링을 진행해야 하나요??


  1. 주성분 분석(PCA)

주성분 분석에서 높은 분산/ 넓은 범위를 가지는 변수는 낮은 분산을 가지는 변수보다 주성분에서 큰 회귀계수를 가지게 된다. 이는 즉, 중요하지 않은 변수도 범위가 넓으면 주성분에서 중요한 변수로 간주된다는 것이다. 이는 모델링을 수행할 때 가장 치명적이다.


  1. 군집(clustering)

군집분석은 거리-기반 알고리즘으로 거리 측도(ex. 유클리디안, 맨하튼.. )를 이용하여 관측값 사이에서 유사성을 찾아 군집을 형성한다. 따라서, 넓은 범위를 가지는 변수는 군집에서 더 큰 영향력을 가지게 된다.


  1. k-최근접 이웃(knn)

k-최근접 이웃은 거리-기반 알고리즘으로 새로운 관측값의 주변에 있는 k개의 이웃(데이터)를 이용하여 유사성 측도에 기반해 관측값을 분류한다. 따라서, 유사성 측도에 모든 변수가 동일하게 기여할 수 있도록 스케일링을 수행해야한다.


  1. 서포트벡터머신(SVM)

서포트벡터 머신은 서포트벡터와 분류기(hyperplane) 사이 거리인 마진(margin)을 최대로 만들어주는 분류기를 찾는 알고리즘이다. 따라서, 큰 값을 가지는 변수가 거리 계산을 할 때 영향력을 많이 미치게 된다.


  1. 회귀

예측을 위한 회귀 모델링이 목적이라면 표준화를 수행할 필요가 없지만, 변수의 중요도나 다른 회귀계수들과 비교를 하는 것이 목적이라면 표준화를 수행하여야 한다.


  1. 릿지-라쏘

릿지-라쏘 모형은 회귀계수에 벌점을 가하는 방법으로 다중공선성과 과적합을 해결하기 위해 사용된다. 회귀계수의 크기를 벌점으로 사용하기 때문에 상대적으로 큰 분산을 가지는 변수가 회귀계수가 클 것이고 그 회귀계수를 벌점으로 사용하게 되면 작은 분산을 가지는 변수들보다 회귀계수를 더 축소시켜 최종적인 회귀계수는 작아지게 될 것이다. (회귀 계수에 영향이 가기에 스케일링 필요)


🤔 스케일링이 필요하지 않은 경우?

로지스틱 회귀나 트리 기반 모델인 의사결정나무, 랜덤 포레스트 , 그래디언트 부스팅은 변수의 크기에 민감하지 않으므로 표준화를 수행해줄 필요가 없다.




Modeling_Sequence

  1. 사용할 데이터 준비과정
    • 충분한 탐색 및 전처리
  2. 사용할 알고리즘과 평가를 위한 함수 import
  3. 사용할 알고리즘용 함수로 모델 선언
  4. 모델.fit(x_train, y_train) 형태로 모델 학습시키기
  5. 모델.predict(x_test) 형태로 예측한 결과 변수로 저장
  6. 실제값과 예측값을 평가 함수에 전달해 성능 평가

# 0단계 : 데이터 준비하기
# 라이브러리 불러오기
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 데이터 읽어오기
data = pd.read_csv('airquality.csv')

# x, y 분리
target = 'Ozone'
x = data.drop(target, axis=1)
y = data.loc[:, target]

# 학습용, 평가용 데이터 분리
from sklearn.model_selection import train_test_split  
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, shuffle=True, stratify=y)
# shuffle : 섞기 , stratify : 어떤 컬럼을 기준으로 테스트, 훈련 세트를 동일한 분포로 둘거냐?

# 1단계: 불러오기
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error

# 2단계: 선언하기
model = LinearRegression()

# 3단계: 학습하기
model.fit(x_train, y_train)

# 4단계: 예측하기
y_pred = model.predict(x_test)

# 5단계: 평가하기
print(mean_absolute_error(y_test, y_pred))


분류 알고리즘

KNeighborsClassifier

의존성 주입


from sklearn.neighbors import KNeighborsClassifier

모델 선언 후 사용


# 선언하기
model = KNeighborsClassifier(n_neighbors=5) 

# 학습하기
model.fit(x_train, y_train)

# 예측하기
y_pred = model.predict(x_test)

# 평가하기
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))

KNN(k-Nearest Neighbor) 기본 원리

  • k 최근접 이웃(가장 가까운 이웃 k개)

    • k(탐색하는 이웃 개수)에 따라 데이터를 다르게 예측할 수도 있음
    • 적절한 k 값을 찾는 것이 중요
      • k를 1로 설정 안함→이웃 하나로 현재 데이터를 판단하기에는 너무 편향된 정보
      • k를 홀수로 설정 → 짝수인 경우 과반수 이상의 이웃이 나오지 않을 수 있음
      • k값의 크기가 클 수록 모델이 단순해짐
  • 학습용 데이터에서 k개의 최근접 이웃의 값을 찾아 그 값들로 새로운 값을 예측하는 알고리즘

  • 이해하기 쉽지만, 연산속도가 느림

  • KNN은 회귀와 분류에 둘 다 사용 가능

    • 회귀면 이웃들의 평균을 구함
    • 분류면 이웃들의 최빈값을 구함

스크린샷 2023-08-30 오후 12 19 49

거리 구하기
  • 유클리드 거리
    • 대각선 이동이 가능
    • 최단 거리
      $$\large d = \sqrt{\sum_{i=1}^n (q_i - p_i)^2}$$
  • 맨하튼 거리
    • 수직선을 따라서 이동

$$\large d = \sum_{i=1}^n |q_i - p_i|$$



DecisionTreeClassifier


의존성 주입

from sklearn.tree import DecisionTreeClassifier

모델 선언 후 사용


model = DecisionTreeClassifier()

model.fit(x_train, y_train)
y_pred = model.predict(x_test)

# 평가하기  
accuracy_score(y_test, y_pred)

유효 컬럼 확인하기

  • model.feature_importances_

perf_dic = {'feature':list(x), 'importance': model.feature_importances_}  
df = pd.DataFrame(perf_dic)  
df.sort_values(by='importance', ascending=True, inplace=True)

시각화


# 트리를 직접 보기
# 시각화 모듈 불러오기
from sklearn.tree import export_graphviz

# 이미지 파일 만들기

export_graphviz(model,
                filled=True,
                feature_names=x.columns,
                class_names=y.unique(),
                rounded=True,
                precision=3,
                out_file='tree.dot')

!dot tree.dot -Tpng -otree.png -Gdpi=300
# 이미지 파일 로딩
from IPython.display import Image
Image(filename='tree.png', width=600)

# 변수 중요도 시각화
plt.figure(figsize=(6, 8))
plt.barh(list(x), model.feature_importances_)
plt.ylabel('Features')
plt.xlabel('Importances')
plt.show()

DecisionTree 기본원리

  • 특정 변수에 대한 의사 결정 규칙을 나무가지가 뻗는 형태로 분류해 나감
  • 스케일링 등의 전처리 영향도가 크지 않음
    • 과적합으로 모델 성능이 떨어지기 쉬움
    • 트리 깊이를 제한하는(=가지치기) 튜닝이 필요
  • 분석 과정을 실제로 눈으로 확인할 수 있음 → 화이트 박스 모델
  • 스무고개처럼 의미있는 질문을 먼저 하는것이 중요

용어
  • Root Node(뿌리마디) : 전체자료를 갖는 시작하는 마디
  • Child Node(자식마디) : 마디 하나로부터 분리된 2개 이상의 마디
  • Parent Node(부모마디) : 주어진 마디의 상위 마디
  • Terminal Node(끝마디) : 자식마디가 없는 마디(=LeafNode)
  • Internal Node(중간마디) : 부모 마디와 자식 마디가 모두 있는 마디
  • Branch(가지) : 연결되어 있는 2개 이상의 마디 집합
  • Depth(깊이) : 뿌리 마디로부터 끝 마디까지 연결된 마디 개수

tree 보는법

  • 분류
    • sample : 해당 노드일 경우의 데이터의 수
    • value : 각 샘플 별 값들의 개수
    • class : 최빈값
    • gini : 지니 불순도(낮을수록 순도가 높음)
    • 특정 조건식 : 가지를 나눌 기준

불순도
  • 순도의 반대말 = 불순도
  • 순도가 높을 수록 분류가 잘 된것
  • 불순도의 수치화 지표
    • 지니 불순도
      • 1 - ($양성 클래스비율^2 + 음성 클래스 비율^2$)
      • $\large Gini = 1-\sum^c_{i=1}(p_i)^2$
      • 지니 불순도가 낮을수록 순도가 높음
      • 지니 불순도는 0~0.5 사이의 값(이진 분류의 경우)
    • 엔트로피
  • 정보 이득
    • 부모의 불순도에서 자식의 불순도를 뺀 값
    • 클 수록 좋음
    • $\large Gain(T,X) = Entropy(T) - Entropy(T, X)$

가지치기
  • 여러 하이퍼 파라미터 값을 조정해 가지치기 할 수 있음
    • max_depth, min_samples_leaf, min_samples_split
  • 학습 데이터에 대한 성능은 낮아지나, 평가 데이터에 대한 성능을 높일 수 있음

주요 하이퍼파라미터
파라미터 설명
max_depth 트리의 최대 깊이(기본값 : None)
계속 분할되면 트리 깊이가 너무 깊어져 과적합이 발생 👉 적절한 값 설정 필요
min_samples_split 노드를 분할하기 위한 최소한의 샘플 개수(기본값 : 2)
값을 작게 설정할 수록 계속 분할되어 트리 깊이가 깊어져 과적합 발생
min_samples_leaf 리프노드가 되기위한 최소한의 샘플 수(기본값 : 1)
불균형 클래스인 경우 이를 고려해 작은겂을 설정할 필요가 있음
max_feature 최선의 분할을 위해 고려할 feature 수(기본값 : None)
'sqrt' : feature수의 루트값
'log' : $log_2(전체 feature수)$
정수형 : feature 수
실수형 : feature 비율
max_leaf_node 리프 노드 최대 개수



LogisticRegression

의존성 주입


# 불러오기
from sklearn.linear_model import LogisticRegression  
from sklearn.metrics import confusion_matrix, classification_report

모델선언 후 사용


# 선언하기
model = LogisticRegression()

# 학습하기
model.fit(x_train, y_train)

# 예측하기
y_pred = model.predict(x_test)

# 평가하기
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))

LogisticRegression 원리

스크린샷 2023-08-31 오전 11 56 03

$$\large p=\frac{1}{1+e^{-f(x)}}$$

  • 로지스틱 함수(시그모이드 함수)
    • 𝑝는 선형판별식값이 커지면 1 , 작아지면 0에 가까운 값이 됨
  • f(x)는 선형 판별식
    • (-∞,∞)범위를 갖는 선형판별식 결과로 (0,1) 범위의 확률값을 얻게 됨
  • 기본적으로 확률값 0.5를 임계값(Threshold)로 하여 이보다 크면 1 , 아니면 0으로 분류

  • 시그모이드 함수
    • 해당 확률보다 낮으면 1 아니면 0(확률값을 받아서 그걸 기준으로 분류)
      스크린샷 2023-08-31 오전 11 56 13



RandomForestClassifier

개념


import


# 불러오기
from sklearn.ensemble import RandomForestClassifier  
from sklearn.metrics import confusion_matrix, classification_report

모델 선언 후 사용


# 선언하기
model = RandomForestClassifier(max_depth=5, n_estimators=100, random_state=1) 

# 학습하기
model.fit(x_train, y_train)

# 예측하기
y_pred = model.predict(x_test)

# 평가하기
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))


XGBClassifier

  • light GMB 을 사용할 수도 있음(경량화된)
  • from lightgbm import LGBMClassifier

개념


import


# 불러오기
from xgboost import XGBClassifier  
from sklearn.metrics import confusion_matrix, classification_report

모델 선언 후 사용


# 선언하기
model = XGBClassifier(max_depth=5, n_estimators=100, random_state=1)

# 학습하기
model.fit(x_train, y_train)

# 예측하기
y_pred = model.predict(x_test)

# 평가하기
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))









회귀 알고리즘

LinearRegression

의존성 주입


from sklearn.linear_model import LinearRegression  

모델 선언 후 사용


model = LinearRegression()

model.fit(x_train, y_train)
y_pred = model.predict(x_test)

# 평가
model.score(x_test, y_test)
# 혹은 MAE, R2 score를 직접 확인

# 회귀계수 확인  
display(list(x_train))  
display(model.coef_)  
display(model.intercept_)

선형 계수 확인


display(list(x_train))  
display(model.coef_)  
display(model.intercept_)

plt.scatter(x_test, y_test.values)  
plt.plot(speed, dist, color='r')  
plt.show()

선형 회귀의 이해

IMG_19FEE20B7C6B-1

  • 데이터는 다양한 형태를 가질것이며 최선의 직선을 긋기가 쉽지 않음

  • 과연 위 직선이 가장 최선의 직선일 것인가?

  • 선형회귀 : 함수 𝑦 = 𝑎𝑥 + 𝑏에서 최선의 기울기 𝑎와 𝑦절편 𝑏를 결정하는 방법

    • 최선의 회귀모델은 전체데이터의 오차 합이 최소가 되는 모델을 의미
    • 이때의 최선의 직선을 회귀선이라고 부름
  • 독립변수의 개수로 회귀분석을 분류

    • 단순 회귀
      • 독립변수 하나가 종속변수에 영향을 미치는 선형 회귀
      • 𝑥값 하나만으로 𝑦값을 설명할 수 있는 경우
      • $\large \hat{y} = w_0 + w_1x_1$
    • 다중 회귀
      • 여러 독립변수가 종속변수에 영향을 미치는 선형 회귀
      • 𝑦값을 설명하기 위해서는 여러 개의 𝑥값이 필요한 경우
      • $\large \hat{y} = w_0 + w_1x_1 + w_2x_2 ... + w_nx_n$
  • $w_1$ : 기울기(또는 가중치) : coef_

  • $w_0$ : y절편(또는 편향) : intercept_



KNeighborsRegressor

의존성 주입


# 불러오기
from sklearn.neighbors import KNeighborsRegressor  

모델 선언 후 사용

# 선언하기
model = KNeighborsRegressor(n_neighbors=5) 

# 학습하기
model.fit(x_train, y_train)

# 예측하기
y_pred = model.predict(x_test)

# 평가하기
print(mean_absolute_error(y_test, y_pred))
print(r2_score(y_test, y_pred))

KNN(k-Nearest Neighbor) 기본 원리

  • k 최근접 이웃(가장 가까운 이웃 k개)

    • k(탐색하는 이웃 개수)에 따라 데이터를 다르게 예측할 수도 있음
    • 적절한 k 값을 찾는 것이 중요
      • k를 1로 설정 안함→이웃 하나로 현재 데이터를 판단하기에는 너무 편향된 정보
      • k를 홀수로 설정 → 짝수인 경우 과반수 이상의 이웃이 나오지 않을 수 있음
      • k값의 크기가 클 수록 모델이 단순해짐
  • 학습용 데이터에서 k개의 최근접 이웃의 값을 찾아 그 값들로 새로운 값을 예측하는 알고리즘

  • 이해하기 쉽지만, 연산속도가 느림

  • KNN은 회귀와 분류에 둘 다 사용 가능

    • 회귀면 이웃들의 평균을 구함
    • 분류면 이웃들의 최빈값을 구함

스크린샷 2023-08-30 오후 12 19 49

거리 구하기
  • 유클리드 거리
    • 대각선 이동이 가능
    • 최단 거리
      $$\large d = \sqrt{\sum_{i=1}^n (q_i - p_i)^2}$$
  • 맨하튼 거리
    • 수직선을 따라서 이동

$$\large d = \sum_{i=1}^n |q_i - p_i|$$



DecisionTreeRegressor

의존성 주입


# 불러오기
from sklearn.tree import DecisionTreeRegressor  
from sklearn.metrics import mean_absolute_error, r2_score

모델 선언 후 사용


# 선언하기

model = DecisionTreeRegressor(max_depth=5) 

# 학습하기
model.fit(x_train, y_train)

# 예측하기
y_pred = model.predict(x_test)

# 평가하기
print(mean_absolute_error(y_test, y_pred))
print(r2_score(y_test, y_pred))

유효 컬럼 확인하기

  • model.feature_importances_

perf_dic = {'feature':list(x), 'importance': model.feature_importances_}  
df = pd.DataFrame(perf_dic)  
df.sort_values(by='importance', ascending=True, inplace=True)

시각화

  • 트리의 각각의 샘플 수를 적는 기준은 알파벳이 빠른 순으로 작성하게 되므로 class_name을 작성할 때 알파벳 순으로 작성해줘야 함
  • 원래 데이터에서 알파벳 순 정렬이고, 라벨은 본인이 보고 싶은 이름을 넣어주는 것

# 트리를 직접 보기
# 시각화 모듈 불러오기
from sklearn.tree import export_graphviz

# 이미지 파일 만들기

export_graphviz(model,
                filled=True,
                feature_names=x.columns,
                class_names=y.unique(), # 무조건 문자열로
                rounded=True,
                precision=3,
                out_file='tree.dot')

!dot tree.dot -Tpng -otree.png -Gdpi=300
# 이미지 파일 로딩
from IPython.display import Image
Image(filename='tree.png', width=600)

# 변수 중요도 시각화
plt.figure(figsize=(6, 8))
plt.barh(list(x), model.feature_importances_)
plt.ylabel('Features')
plt.xlabel('Importances')
plt.show()

DecisionTree 기본원리

  • 특정 변수에 대한 의사 결정 규칙을 나무가지가 뻗는 형태로 분류해 나감
  • 스케일링 등의 전처리 영향도가 크지 않음
    • 과적합으로 모델 성능이 떨어지기 쉬움
    • 트리 깊이를 제한하는(=가지치기) 튜닝이 필요
  • 분석 과정을 실제로 눈으로 확인할 수 있음 → 화이트 박스 모델
  • 스무고개처럼 의미있는 질문을 먼저 하는것이 중요

용어
  • Root Node(뿌리마디) : 전체자료를 갖는 시작하는 마디
  • Child Node(자식마디) : 마디 하나로부터 분리된 2개 이상의 마디
  • Parent Node(부모마디) : 주어진 마디의 상위 마디
  • Terminal Node(끝마디) : 자식마디가 없는 마디(=LeafNode)
  • Internal Node(중간마디) : 부모 마디와 자식 마디가 모두 있는 마디
  • Branch(가지) : 연결되어 있는 2개 이상의 마디 집합
  • Depth(깊이) : 뿌리 마디로부터 끝 마디까지 연결된 마디 개수

tree 보는법

  • 회귀
    • sample : 해당 노드일 경우의 데이터의 수
    • mse : mean squared error
    • value : 반환할 값(예측값)
    • 조건 : 트리의 분할 조건

불순도
  • 순도의 반대말 = 불순도
  • 순도가 높을 수록 분류가 잘 된것
  • 불순도의 수치화 지표
    • 지니 불순도
      • 1 - ($양성 클래스비율^2 + 음성 클래스 비율^2$)
      • $\large Gini = 1-\sum^c_{i=1}(p_i)^2$
      • 지니 불순도가 낮을수록 순도가 높음
      • 지니 불순도는 0~0.5 사이의 값(이진 분류의 경우)
    • 엔트로피
  • 정보 이득
    • 부모의 불순도에서 자식의 불순도를 뺀 값
    • 클 수록 좋음
    • $\large Gain(T,X) = Entropy(T) - Entropy(T, X)$

가지치기
  • 여러 하이퍼 파라미터 값을 조정해 가지치기 할 수 있음
    • max_depth, min_samples_leaf, min_samples_split
  • 학습 데이터에 대한 성능은 낮아지나, 평가 데이터에 대한 성능을 높일 수 있음

주요 하이퍼파라미터

파라미터 설명
max_depth 트리의 최대 깊이(기본값 : None)
계속 분할되면 트리 깊이가 너무 깊어져 과적합이 발생 👉 적절한 값 설정 필요
min_samples_split 노드를 분할하기 위한 최소한의 샘플 개수(기본값 : 2)
값을 작게 설정할 수록 계속 분할되어 트리 깊이가 깊어져 과적합 발생
min_samples_leaf 리프노드가 되기위한 최소한의 샘플 수(기본값 : 1)
불균형 클래스인 경우 이를 고려해 작은겂을 설정할 필요가 있음
max_feature 최선의 분할을 위해 고려할 feature 수(기본값 : None)
'sqrt' : feature수의 루트값
'log' : $log_2(전체 feature수)$
정수형 : feature 수
실수형 : feature 비율
max_leaf_node 리프 노드 최대 개수




RandomForestRegressor

개념


import


# 불러오기
from sklearn.ensemble import RandomForestRegressor  
from sklearn.metrics import mean_absolute_error, r2_score

모델 선언 후 사용


# 선언하기
model = RandomForestRegressor(max_depth=5, n_estimators=100, random_state=1) 

# 학습하기
model.fit(x_train, y_train)

# 예측하기
y_pred = model.predict(x_test)

# 평가하기
print(mean_absolute_error(y_test, y_pred))
print(r2_score(y_test, y_pred))


XGBRegressor

개념


import


# 불러오기
from xgboost import XGBRegressor  
from sklearn.metrics import mean_absolute_error, r2_score

모델 선언 후 사용


# 선언하기
model = XGBRegressor(max_depth=5, n_estimators=100, random_state=1)

# 학습하기
model.fit(x_train, y_train)

# 예측하기
y_pred = model.predict(x_test)

# 평가하기
print(mean_absolute_error(y_test, y_pred))
print(r2_score(y_test, y_pred))



Ridge

import


from sklearn.linear_model import Ridge

모델 선언 후 사용


ridge = Ridge()  

ridge.fit(x_train, y_train)  

ridge.score(x_test, y_test)

train = []
test = []

alpha_list = [0.001., 0.01, 0.1, 1, 10 ,100]
for a in alpha_list:
    ridge = Ridge(alpha = a, max_iter=10000)
    ridge.fit(x_train, y_train)
    train.append(ridge.score(x_train, y_train))
    test.append(ridge.score(x_test, y_test))

plt.plot(np.log10(alpha_list), train)
plt.plot(np.log10(alpha_list), test)
plt.show()

Ridge 원리

  • 선형회귀 모델에 규제를 합쳐서 만든 모델
  • 규제 : 계수를 제곱한 값을 기준으로 규제 적용

Lasso

import


from sklearn.linear_model import Lasso

모델 선언 후 사용


lasso = Lasso()  

lasso.fit(x_train, y_train)  

lasso.score(x_test, y_test)

train = []
test = []

alpha_list = [0.001., 0.01, 0.1, 1, 10 ,100]
for a in alpha_list:
    lasso = Lasso(alpha = a, max_iter=10000)
    lasso.fit(x_train, y_train)
    train.append(lasso.score(x_train, y_train))
    test.append(lasso.score(x_test, y_test))

plt.plot(np.log10(alpha_list), train)
plt.plot(np.log10(alpha_list), test)
plt.show()

Lasso 원리

  • 선형회귀 모델에 규제를 합쳐서 만든 모델
  • 계수의 절댓값을 기준으로 규제 적용

하이퍼 파라미터

  • alpha : 규제의 양










성능 평가


회귀의 성능평가

  • 오차가 적은 것
  • 정확도의 개념이 아님

실제값

$$\huge y$$

  • 우리가 실제로 예측하고 싶은 값, Target, 목푯값
  • 이값과 비교해 우리 모델의 성능을 평가할 것임
  • 오차 : 실제값 - 예측값

예측값

$$\huge \hat{y}$$

  • 우리모델로 새롭게 예측한 값
  • 최소한, 아무리 못해도 평균값 보다는 좋아야 할 것

평균값

$$\huge \bar{y}$$

  • 이미 알고 있는, 이미 존재하고 있는 평균으로 예측한 값
  • 최소한 이 평균값 보다는 실젯값에 가까운 예측값을 원함

IMG_1BBFFC402AFC-1

  • SST = $\large\Sigma(y-\bar{y})^2$
    • Sum Squared Total
    • 전체 오차
    • 우리에게 허용된 최대 오차(이 이상의 오차가 발생시 해당 모델을 쓸 이유가 없음)
    • SST = SSR + SSE
  • SSR = $\large\Sigma(\hat{y}-y)^2$
    • Sum Squared Regression
    • 평균(전체오차)보다 우리의 회귀식이 잡아낸 오차
  • SSE = $\large \Sigma(\hat{y}-\bar{y})^2$
    • Sum Squared Error
    • 전체 오차 중 회귀식이 여전히 잡아내지 못한 오차

오차 제곱의 합


MSE

$$\large\frac{\Sigma(y-\hat{y})^2}{n}$$

  • Mean SSE
  • 오차 제곱의 합을 구한 후 평균을 구함

# 모듈 불러오기  
from sklearn.metrics import mean_squared_error  

# 성능 평가  
print("MSE : ", mean_squared_error(y_test, y_pred))


RMSE

$$\large \sqrt \frac{\Sigma(y-\hat{y})^2}{n}$$

  • Root MSE
  • 오차의 제곱이르몰 루트를 사용해 일반적인 값으로 표현

# 모듈 불러오기  
from sklearn.metrics import mean_squared_error  

# 성능 평가  
print("RMSE : ", mean_squared_error(y_test, y_pred)**(1/2))  
print("RMSE : ", mean_squared_error(y_test, y_pred, squared=False))


오차 절대값의 합


MAE

$$\large \frac{\Sigma|y-\hat{y}|}{n}$$

  • Mean Absolute Mean
  • 오차 절대값의 합을 구한 후 평균을 구함

# 모듈 불러오기  
from sklearn.metrics import mean_absolute_error  

# 성능 평가  
print("MAE : ", mean_absolute_error(y_test, y_pred))


MAPE

$$\large \frac{\Sigma|\frac{y-\hat{y}}{y}|}{n}$$

  • Mean Absolute Percentage Mean
  • 오차 비율을 표시하고 싶은 경우 MAPE를 사용함

# 모듈 불러오기  
from sklearn.metrics import mean_absolute_percentage_error  

# 성능 평가  
print("MAPE : ", mean_absolute_percentage_error(y_test, y_pred))


결정계수

$$R^2 = \frac{SSR}{SST} = 1-\frac{SSE}{SST}$$

  • model에서 score함수 사용 시 결정계수를 사용
  • $R^2$(R-Squared)
  • 모델성능을 잘 해석하기 위해서 만든 MSE의 표준화된 버전이 결정계수
  • 전체 오차 중에서 회귀식이 잡아낸 오차 비율(일반적으로 0 ~ 1 사이)
  • 오차의 비 또는 설명력 이라고도 부름
  • $𝑅^2$ =1이면 𝑀𝑆𝐸=0이고 모델이 데이터를 완벽하게 학습한 것
    • 클 수록 좋은 평가지표
  • 만약 $R^2$의 값이 음의 값이 나온다면(비정상) 알고리즘 자체가 적합하지 않다는 뜻임

# 모듈 불러오기  
from sklearn.metrics import r2_score  

# 성능 평가  
print("r2 : ", r2_score(y_test, y_pred))





분류 모델평가


혼돈행렬

  • ConfusionMatrix(오분류표)
    스크린샷 2023-08-29 오후 1 45 32

  • T, F : 결과

    • 예측이 맞음, 틀림
  • N, P :예측

    • 1로 예측, 0으로 예측
  • TN(True Negative, 진음성): 음성으로 잘 예측한 것(음성을 음성이라고 예측한 것)

  • FP(False Positive, 위양성): 양성으로 잘 못 예측한 것(음성을 양성이라고 예측한 것)

  • FN(False Negative, 위음성): 음성으로 잘 못 예측한 것(양성을 음성이라고 예측한 것)

  • TP(True Positive, 진양성): 양성으로 잘 예측한 것(양성을 양성이라고 예측한 것)


# 모듈 불러오기  
from sklearn.metrics import confusion_matrix  

# 성능 평가  
confusion_matrix(y_test, y_pred)

# 혼돈행렬 시각화  
plt.figure(figsize=(2, 2))  
sns.heatmap(confusion_matrix(y_test, y_pred),  
    annot=True,  
    cmap='Blues',  
    fmt='.2f',  
    annot_kws={'size':7},  
    square=True)


Accuracy

  • 정확도(정분류율)
    • 전체 중에서 예측이 맞은 확률
      $$\frac{TN + TP}{TN + FP + FN + TP}$$

# 모듈 불러오기  
from sklearn.metrics import accuracy_score  

# 성능 평가  
accuracy_score(y_test, y_pred)


Precision

  • 정밀도
    • 보통은 1의 정밀도
    • 예측값이 분모
    • 예측을 n으로 했는데 n이 실제로 n이었을 확률
    • Positive로 예측한 것(FP + TP) 중에서 실제 Positive(TP)인 비율
      • 비가 오지 않는데 비가 온다고 했으니 불필요한 우산을 챙기는 수고 발생
      • 암이 아닌데 암이라 했으니 불필요한 치료 발생
        $$\frac{TP}{FP + TP}$$

# 모듈 불러오기  
from sklearn.metrics import precision_score  

# 성능 평가  

# 1의 precision
precision_score(y_test, y_pred)  

# 각 값에 따른 precision 전체를 보여주기  
precision_score(y_test, y_pred, average=None)  
precision_score(y_test, y_pred, average='binary') # 이진 분류  
precision_score(y_test, y_pred, average='macro') # 평균  
precision_score(y_test, y_pred, average='weighted') # 개수를 반영한 평균


Recall

  • 재현율(민감도)
    • 실제 값이 n인데 예측값도 n인 확률
    • 실제값이 분모
    • 실제 Positive(FN + TP) 중에서 Positive로 예측한(TP)
      • 비가 내리는 날 내리지 않을 것이라 했으니 우산을 챙기지 않아 비를 맞음
      • 암인사람에게 암이 아니라했으니 심각한 결과 초래
        $$\frac{TP}{FN + TP}$$

# 모듈 불러오기  
from sklearn.metrics import recall_score  

# 성능 평가  
# 1의 recall
recall_score(y_test, y_pred)  

# 모든 값에 대한 recall
recall_score(y_test, y_pred, average=None)  
recall_score(y_test, y_pred, average='binary') # 이진 분류  
recall_score(y_test, y_pred, average='macro') # 평균  
recall_score(y_test, y_pred, average='weighted') # 개수를 반영한 평균


F1-Score

  • 정밀도와 재현율의 조화 평균
    • 정밀도, 재현율 둘 다 반영된 지표
  • 분자가 같지만 분모가 다를경우, 즉 관점이 다른경우 조화평균이 큰 의미를 가짐

$$\large (F1-Score) = 2\frac{1}{\frac{1}{Precesion} + \frac{1}{Recall}} = \frac{2Precesion*Recall}{Precesion + Recall}$$


# 모듈 불러오기  
from sklearn.metrics import f1_score  

# 성능 평가  
f1_score(y_test, y_pred)


classification_report

스크린샷 2023-08-29 오후 2 59 18

  • macro avg : 0일때와 1일때의 precision, recall, f1-score의 평균
  • weighted avg : 데이터의 개수를 고려해 가중치를 더해 평균을 구함

# 모듈 불러오기  
from sklearn.metrics import classification_report  

# 성능 평가  
print(classification_report(y_test, y_pred))


K-FoldCrossValidation


# 1단계: 불러오기
from sklearn.tree import DecisionTreeClassifier 
from sklearn.model_selection import cross_val_score

# 2단계: 선언하기
model = DecisionTreeClassifier(max_depth=3) 

# 3단계: 검증하기
cv_score = cross_val_score(model, x_train, y_train, cv=10, 
                           scoring='accuracy_score')

# 확인
print(cv_score) 
print(cv_score.mean())

$$\large 데이터 = 학습용 + 검증용 + 평가용$$

  • 지금까지 모델을 선언하고 학습한 후 바로 평가를 진행함

  • 일반화 성능, 즉 이후 새로운 데이터에 대한 모델의 성능을 예측하지 못한 상태에서 최종평가를 수행

  • 검증용 데이터가 모델의 일반화된 성능을 예측할 수 있게 도와줌

    • 하지만 이것 역시 단 하나의 데이터셋에 대한 추정일뿐
    • 단 하나의 데이터셋에서 얻은 성능으로 정확도에 확신을 가질 수 없음
  • K-FoldCrossValidation

    • 모든 데이터가 평가에 한번, 학습에 k-1번 사용
    • K개의 분할(Fold)에 대한 성능을 예측→평균과 표준편차 계산→일반화 성능
    • 단, k는 2이상이 되어야함(최소한 한개씩의 학습용, 검증용 데이터가 필요)
    • k-분할은 어느정도의 점수가 나오는지 확인하는 정도의 용도고 실제 모델 학습 시에는 k 분할을 알고리즘 및 하이퍼 파라미터 튜닝을 통해 가장 효율적인 방법으로 해서 x_train 전체를(즉, 학습용과 검증용 나눈거 없이) 학습

IMG_93DA92283B3A-1


#### 장점 + 모든 데이터를 학습과 평가에 사용할 수 있음 + 반복 학습과 평가를 통해 정확도를 향상시킬 수 있음 + 데이터가 부족해서 발생하는 과소적합 문제를 방지할 수 있음 + 평가에 사용되는 데이터의 편향을 막을 수 있음 + 좀 더 일반화된 모델을 만들 수 있음

단점

  • 반복 횟수가 많아서 모델 학습과 평가에 많은시간이 소요됨


Hyperparameter

튜닝
과학이기보다는 예술(정해진 방법이 없음)

  • 알고리즘을 사용해 모델링 할때 모델 성능을 최적화하기 위해 조절할 수 있는 매개변수
    • KNN 알고리즘의 n_neighbors, Decision Tree 알고리즘의 max_depth 등
  • 모델의 성능 향상을 위해 최선의 하이퍼파라미터값을 찾는 다양한 시도를 해야함
  • Grid Search, Random Search

RandomSearch
GridSearch


KNN

  • n_neighbors에 따라 성능이 달라짐
  • k값이 가장 클 때(=전체데이터개수) 가장 단순 모델
    • →평균, 최빈값과 다를바 없음
  • k값이 작을수록 복잡한 모델이 됨

Decision Tree

  • max_depth
    • 이 값이 작을 수록 트리 깊이가 제한되어 모델이 단순해 짐
  • min_samples_leaf
    • leaf가 되기 위한 최소한의 샘플 데이터 수
    • 이 값이 클 수록 모델이 단순해 짐
  • min_samples_split
    • 노드를 분할하기 위한 최소한의 샘플 데이터 수
    • 이 값이 클 수록 모델이 단순해짐

RandomSearch

  • 성능을 테스트할 파라미터 값의 범위를 지정(딕셔너리 형태)
  • 위 파라미터 값 범위에서 몇개 선택할지 정하여 RandomSearch 모델 선언 후 학습
  • 학습 데이터에 대해 가장 좋은 성능을 보인 파라미터값으로 자동으로 학습함
  • 이후 예측 및 평가과정을 바로 진행하면됨
    • 지정한 개수의 임의의 값에 대해서만 성능 확인 가능

# 함수 불러오기
from sklearn.neighbors import KNeighborsClassifier 
from sklearn.model_selection import RandomizedSearchCV

# 파라미터 선언
param = {'n_neighbors': range(1, 500, 10),
         'metric': ['euclidean', 'manhattan']}

# 기본모델 선언
knn_model = KNeighborsClassifier()

# Random Search 선언
model = RandomizedSearchCV(knn_model, param,
                           cv=3,
                           n_iter=20)

# 학습하기
model.fit(x_train, y_train)

# 최적 파라미터
model.best_params_

# 최고 성능
model.best_score_

# 최고 성능의 모델
model.best_estimator_

GridSearch

  • 성능을 테스트할 파라미터 값의 범위를 지정(딕셔너리 형태)
  • 위 파라미터값 범위를 모두 사용하는 GridSearch모델 선언 후 학습
  • 학습 데이터에 대해 가장 좋은 성능을 보인 파라미터값으로 자동으로 학습함
  • 이후 예측 및 평가 과정을 바로 진행하면됨
    • 모든 경우의 성능 확인 가능
  • tip
    • 넓은 범위와 큰 Step으로 설정한 후 범위를 좁혀나가는 방식으로 시간을 단축

# 함수 불러오기
from sklearn.neighbors import KNeighborsClassifier 
from sklearn.model_selection import GridSearchCV

# 파라미터 선언
param = {'n_neighbors': range(1, 500, 10), 'metric': ['euclidean', 'manhattan']} 

# 기본모델 선언
knn_model = KNeighborsClassifier()

# Grid Search 선언
model = GridSearchCV(knn_model,
                    param, # 파라미터 범위
                    cv = 5, #K-Fold 개수 
                    n_iter=20, # 랜덤하게 선택할 파라미터(조합) 개수  
                    scoring='r2', # 평가 지표 
                    verbose = 2 # 모델 fit 과정 정보, 3은 실제 진행되는 과정까지 표현
)

# 학습하기
model.fit(x_train, y_train)

# 테스트로 얻은 성능
model.cv_results_['mean_test_score']

# 최적 파라미터
model.best_params_

# 최고 성능
model.best_score_

# 최고 성능의 모델
model.best_estimator_

# DecisionTree의 경우 시각화
plt.figure(figsize=(4, 4))  
plt.barh(y = list(x), width=model.best_estimator_.feature_importances_)  
plt.show()

IMG_56935BDB0985-1

  • Grid Search. Random Search를 사용할 때 내부적인 K-Fold Cross Validation을 위해 cv 값을 지정하므로 실제 수행되는 횟수는 $파라미터 조합 수*cv$ 값이 됨

🤔 데이터 범위가 엄청 넓을때 Hyperparameter 값 찾는법

  • Random Search와 Greed Search를 둘 다 사용
    • 우선 Random Search를 통해 좋은 값을 찾기
    • Grid Search로 Random Search로 찾은 좋은값의 주변값을 포함해서 검사
    • 주변중에서 제일 좋은 값이 Random Search에서 나온값과 같다면 그대로 하이퍼 파라미터찾기 종료
    • 바뀐다면 바뀐 값 기준으로 새롭게 Grid를 지정해서 좋은 값 찾기

🤔Hyperparameter 튜닝 시 주의사항

  • 운영환경에서 성능이 보장되지 않음
    • 과적합될 수 있음
    • 미래에 발생할 데이터는 과거와 다를 수 있음
  • 모델링 목표 : 완벽한 적절한 예측력을 위해 적절한 복잡도의 모델 완성


UnderSampling

  • recall값이 비정상적임을 해결하기 위한 목적
  • target값의 불균형 해결
  • 실전에서는 높아진 recall로 인한 이득과 낮아진 accuracy로 인한 비용을 고려해서 진행
    • confusion matrix의 각 부분을 돈으로 산정해서 얼마를 절감할 수 있는지 파악 후 절감이 가장 많이 되는 중요한 부분의 수치를 높이는데 집중해야함

# imblearn 설치  
!pip install imbalanced-learn

#%%  
# 불러오기  
from imblearn.under_sampling import RandomUnderSampler  

# Under Sampling  
under_sample = RandomUnderSampler()  
u_x_train, u_y_train = under_sample.fit_resample(x_train, y_train)  

# 확인  
print('전:', np.bincount(y_train))  
print('후:', np.bincount(u_y_train))

sns.scatterplot(x='Age', y='MonthlyIncome', hue=u_y_train, data=u_x_train)  
plt.show()

# 선언하기  
model = RandomForestClassifier(max_depth=5, random_state=1)  

# 학습하기  
model.fit(u_x_train, u_y_train)  

# 예측하기  
y_pred = model.predict(x_test)  

# 평가하기  
print(confusion_matrix(y_test, y_pred))  
print(classification_report(y_test, y_pred))


OverSampling

  1. target중 값이 적은 값을 똑같이 늘림

# 불러오기  
from imblearn.over_sampling import RandomOverSampler  

# Over Sampling  
over_sample = RandomOverSampler()  
o_x_train, o_y_train = over_sample.fit_resample(x_train, y_train)  

# 확인  
print('전:', np.bincount(y_train))  
print('후:', np.bincount(o_y_train))

# 학습 데이터 분포 확인  
sns.scatterplot(x='Age', y='MonthlyIncome', hue=o_y_train, data=o_x_train)  
plt.show()

# 선언하기  
model = RandomForestClassifier(max_depth=5, random_state=1)  

# 학습하기  
model.fit(o_x_train, o_y_train)  

# 예측하기  
y_pred = model.predict(x_test)  

# 평가하기  
print(confusion_matrix(y_test, y_pred))  
print(classification_report(y_test, y_pred))

  1. SMOTE를 사용해서 값과 값 사이사이에 케이스를 늘림

# 불러오기  
from imblearn.over_sampling import SMOTE  

# Over Sampling  
smote = SMOTE()  
s_x_train, s_y_train = smote.fit_resample(x_train, y_train)  

# 확인  
print('전:', np.bincount(y_train))  
print('후:', np.bincount(s_y_train))

# 학습 데이터 분포 확인  
sns.scatterplot(x='Age', y='MonthlyIncome', hue=s_y_train, data=s_x_train)  
plt.show()

# 선언하기  
model = RandomForestClassifier(max_depth=5, random_state=1)  

# 학습하기  
model.fit(s_x_train, s_y_train)  

# 예측하기  
y_pred = model.predict(x_test)  

# 평가하기  
print(confusion_matrix(y_test, y_pred))  
print(classification_report(y_test, y_pred))


ClassWeight

  • 적절한 가중치를 두어 class 불균형 해소

# 선언하기  
model = RandomForestClassifier(max_depth=5, random_state=1, class_weight='balanced')  

# 학습하기  
model.fit(x_train, y_train)  

# 예측하기  
y_pred = model.predict(x_test)  

# 평가하기  
print(confusion_matrix(y_test, y_pred))  
print(classification_report(y_test, y_pred))


앙상블(Ensembel)


앙상블 이해

  • 통합은 힘이다(Unity is strength)
  • 약한모델이 올바르게 결합하면 더 정확하고 견고한 모델을 얻을 수 있다!
    • →여러 개의 모델을 결합하여 훨씬 강력한 모델을 생성하는 기법
  • 캐글(Kaggle)과 같은 많은 기계학습경쟁에서 상위순위를 차지하고 있음

앙상블 방법



보팅(Voting)

  • 여러모델들(다른 유형의 알고리즘 기반)의 예측결과를 투표를 통해 최종 예측결과를 결정하는 방법
    • 하드 보팅 : 다수 모델이 예측한 값이 최종 결괏값
    • 소프트 보팅 : 모든 모델이 예측한 레이블 값의 결정 확률 평균을 구한 뒤 가장 확률이 높은값을 최종선택


배깅(Bagging)

  • Bootstrap Aggregating의 약자
  • 데이터로부터 부트스트랩(중복된 복원추출) 한 데이터로 모델들을 학습시킨 후, 모델들의 예측 결과를 집계해 최종 결과를 얻는 방법
  • 같은유형의알고리즘기반모델들을사용
  • 데이터 분할시 중복을 허용(복원 랜덤 샘플링 방식이라고 함)
    • 범주형 데이터(Categorical Data)는 투표방식(Voting)으로 결과를 집계
    • 연속형 데이터(Continuous Data)는 평균으로 결과를 집계
  • 대표적인 배깅 알고리즘 : RandomForest

랜덤 포레스트(Random Forest)

  • 배깅의 가장 대표적 알고리즘
  • 여러 Decision Tree 모델이 전체 데이터에서 배깅 방식으로 각자의 데이터 샘플링
  • 모델들이 개별적으로 학습을 수행한 뒤 모든 결과를 집계하여 최종결과 결정

111


2가지 Random
  • 랜덤하게 데이터를 샘플링

122

  • 개별 모델이 트리를 구성할 때 분할기준이 되는 Feature를 랜덤하게 선정

123


Forest

  • 나무가 모여 숲을 이루듯 Decision Tree가 여러 개 모여 Forest가 됨

123


주요 하이퍼파라미터

  • 대부분 Decision Tree에서와 같은 하이퍼 파라미터를 가짐
파라미터 설명
n_estimators 만들어질 Decision Tree 개수 지정(기본값 : 100)
많이 지정할 수록 성능이 좋아질 것으로 기대하지만 무조건 그런것은 아님
너무 늘리면 학습속도가 너무 느려질 수 있음
max_depth 트리의 최대 깊이(기본값 : None)
계속 분할되면 트리 깊이가 너무 깊어져 과적합이 발생 👉 적절한 값 설정 필요
min_samples_split 노드를 분할하기 위한 최소한의 샘플 개수(기본값 : 2)
값을 작게 설정할 수록 계속 분할되어 트리 깊이가 깊어져 과적합 발생
min_samples_leaf 리프노드가 되기위한 최소한의 샘플 수(기본값 : 1)
불균형 클래스인 경우 이를 고려해 작은겂을 설정할 필요가 있음
max_feature 최선의 분할을 위해 고려할 feature 수(기본값 : None)
'sqrt' : feature수의 루트값
'log' : $log_2(전체 feature수)$
정수형 : feature 수
실수형 : feature 비율


부스팅(Boosting)

  • 같은 유형의 알고리즘 기반 모델 여러개에 대해 순차적으로 학습을 수행
  • 이전 모델이 제대로 예측하지 못한 데이터에 대해서 가중치를 부여하여 다음모델이 학습과 예측을 진행하는 방법
  • 계속하여 모델에게 가중치를 부스팅하며 학습을 진행해 부스팅 방식이라함
  • 예측 성능이 뛰어나 앙상블 학습을 주도함
  • 배깅에 비해 성능이 좋지만, 속도가 느리고 과적합 발생 가능성이 있음
    • →상황에 맞게 적절히 사용해야 함
  • 대표적인 부스팅 알고리즘 : XGBoost, LightGBM(XGBoost가 너무 느려서 나오게된 모델)

124

125


XGBoost(eXtreme Gradient Boosting)

  • 부스팅을 구현한 대표적인 알고리즘중 하나가 GBM(GradientBoostMachine)
  • GBM 알고리즘을 병렬학습이 가능하도록 구현한것이 XGBoost
  • 회귀, 분류 문제를 모두 지원하며, 성능과 자원 효율이 좋아 많이 사용됨
  • XGBoost장점
    • 높은 예측 성능
    • 빠른 수행 시간
    • 과적합 규제 기능
    • 가지치기
    • 내장된 교차 검증
    • 결측치 자체 처리


스태킹(Stacking)

  • 여러 모델의 예측값을 최종 모델의 학습 데이터로 사용하여 예측 하는 방법
  • 예를들면
    • KNN, Logistic Regression, XGBoost 모델을 사용해 4종류 예측값을 구한 후
    • 이 예측 값을 최종 모델인 Randomforest 학습 데이터로 사용
  • 현실모델에서 많이 사용되지 않으며, 캐글(Kaggle)같은 미세한 성능 차이로 승부를 결정하는 대회에서 사용됨
  • 기본 모델로 4개 이상 선택해야 좋은결과를 기대할 수 있음

126



K-meanClustering

  • 정규화 필요
  • k의 개수만큼 군집화 시킴

import


from sklearn.cluster import KMeans

모델 생성 후 사용


k = 3  

model = KMeans(n_clusters=k, random_state=1)  

model.fit(x_train)  

data['cluster'] = model.fit(x_train)

군집된 값 시각화


plt.figure(figsize = (8, 8)) 
for i in range(k): 
    plt.scatter(df.loc[df['cluster'] == i, 'Annual Income (k$)'], df.loc[df['cluster'] == i, 'Spending Score (1-100)'], 
                label = 'cluster ' + str(i)) 

    plt.legend() 
    plt.title('K = %d results'%k , size = 15)
    plt.xlabel('Annual Income', size = 12)
    plt.ylabel('Spending Score', size = 12)
    plt.show()

k 결정 방법


from yellowbrick.cluster import KElbowVisualizer 

model = KMeans() 
visualizer = KElbowVisualizer(model, k=(1,10)) 
visualizer.fit(data_scale)

반응형

+ Recent posts