2021년도에 대학교 과목으로 들었던 '기계학습' 강의를 복습 및 정리 + 추가적인 공부를 위해 이 글을 작성한다. (세종대학교 최유경 교수님 '2021 기계학습'수업)
이제 본격적인 기계학습에 대해 알아보자. part1에서 언급했듯이 기계학습에는 지도학습, 비지도학습, 강화학습 3가지로 분류할 수 있다고 했다. 이번 part에서는 지도학습이 무엇인지, 지도학습의 대표적인 학습모델에 대해 알아보자.
지도학습
지도학습은 말 그대로 학습을 지도하는 가이드 라인(결과값)이 있다고 생각하면 된다. 즉, 입력과 결과값(목표값)을 이용하여 학습을 진행한다. 이는 크게 분류(classification)와 회귀(regression)로 나누어진다.
1. 분류(classification)
분류는 미리 정의된, 가능성 있는 여러 클래스 레이블(목표값) 중 하나를 예측하는 것을 말한다. 대표적으로 두개로만 나누는 이진 분류(Binary Classification), 셋 이상의 클래스로 분류하는 다중 분류(Multiclass Classification)으로 나뉜다. 숫자 판별, 긍부정 분류 등이 대표적인 분류 예시라고 할 수 있다.
2. 회귀(regression)
회귀는 연속적인 숫자 또는 실수를 예측하는 것을 말한다. 대표적으로 주식 가격 예측, 따릉이 이용자 수 예측 등이 회귀 예시라고 할 수 있다.
이런 지도학습의 분류 및 회귀에 이용되는 대표적인 학습 모델로는 KNN(K-Nearest Neighbor), Linear/Logistic regression, DA(Discriminant Analysis), Decision Tree, SVM(support vector machine) 등이 있다. 이들 중 이번 파트에서는 KNN(K-Nearest Neighbor)에 대해 알아본다.
KNN(K-Nearest Neighbor)
이론
1. 분류(classification)
분류로써의 KNN은 이름에서 알다시피 주변 k개의 자료의 클래스 중 가장 많은 클래스로 해당 자료를 분류하는 방식이다. 예시를 통해 살펴보면,

이렇게 새로운 특정 자료(?)의 클래스를 분류한다고 할 때, k를 5로 설정했다고 가정하면 가장 가까운 5개의 자료가 가지고 있는 클래수 중 가장 많은 클래스로 할당한다. (? 주위에는 ▲ 3개, ○ 1개, + 1개로 ?는 ▲로 클래스 할당) 이때 가까운 자료의 기준이 되는 거리는 Minkowski 거리를 이용한다.

KNN의 특징은 어떠한 추정 방법과 모형을 통해 분류하는 것이 아닌 학습 데이터 자체를 통해 분류를 진행한다는 것이다. 즉, 다른 학습모델과는 다르게 파라미터를 추정하지 않는다. 이렇게 간단한 방식으로 학습이 진행되지만 성능은 떨어지지 않는다. 이걸 바로 게으른 학습(lazy learner) 혹은 사례중심학습(instance-based learning)이라고 한다. (게으른 학습: 훈련 데이터를 토대로 판별 함수(판별 모델)를 학습하는 대신 훈련 데이터 자체를 메모리에 저장하여 학습하는 방법)
하지만 KNN은 데이터의 차원(특성, feature)이 증가하면 성능 저하가 심해지는 큰 단점이 존재한다. 이는 바로 차원의 저주 때문이다.
차원의 저주(curse of dimension)란, 데이터의 차원이 증가할수록 해당 공간의 크기(부피)가 기하급수적으로 증가하여 같은 개수의 데이터의 밀도는 차원이 증가할수록 급속도로 희박해진다는 것이다. 즉, 차원이 증가할수록 데이터의 분포 분석에 필요한 데이터의 개수는 기하급수적으로 증가하는데, 그에 비해 기존 데이터의 개수는 변하지 않기에 성능이 급속도로 저하한다.
그렇다면 여기서 K는 어떤 의미를 가질까? 단순하게 생각해보자. k가 가지고 있는 데이터의 개수에 비해 극단적으로 작다고 가정해보자. 이런 경우에는 당연히 다양한 경우의 수를 무시하게 되어 데이터의 지역적 특성을 지나치게 반영하게 되는 과대적합(overfitting)이 발생하게 된다. 하지만 반대로 극단적으로 크게되면 세부적인 경우의 수를 무시하게 되며 과소적합(underfitting)이 발생하여 일반화가 되지 않는다. 그러므로 적절한 k의 선정이 필요하다. 그렇다면 이 k를 적절하게만 설정한다면 분류가 잘 일어날까? 아니다. 일반적인 k는 사실 거리를 고려하지 않고 다수결 방식으로 범주를 예측한다. 이렇게 되면 k의 개수에 따라 예측되는 범주는 너무나 다양할 것이다. 예를 통해 살펴보자.

위의 예시와 같이 k가 5일 때와 k가 9일때의 예측 범주는 달라진다. k가 9일 때를 살펴보면 사실 예측 범주는 우리가 어림잡아 눈으로 판단하면 해당 특정 범주와 가까우며 많은 범주는 사실 파란색이라고 할 수 있다. 하지만 KNN은 오직 다수결 법칙을 따르기에 거리를 생각하지 않고 파란색보다 많이 검출된 흰색이 해당 특정 범주에 적합하다고 판단한다. 이를 해결하기 위해 우린 가중 합 방식(Weighted voting)을 고려해야 된다. (가중합 방식: 가까운 이웃의 정보에 좀 더 가중치를 부여. 즉, 거리를 고려하며 판단) 가중 합 방식을 통해 예측을 진행하면 범위 내의 개수는 적지만 거리가 더 가까운 파란색으로 분류가 가능해 질 것이다.
2. 회귀
회귀에서의 KNN은 분류와 y(목표값)의 예측 치 계산만 다르고 나머지는 동일하다고 볼 수 있다.
KNN 회귀에서는 단순 회귀 기법이 기본적으로 사용된다. 다시 말해, k개의 관측치(x, y)에서 y의 평균을 계산하여 적합 치로 사용한다. 즉, 가장 가까운 K개 각각의 y의 평균을 예측 치로 사용한다는 말이다. 하지만 분류에서도 보았듯이 거리를 고려하지 않고 개수만을 고려하면 생기는 문제 때문에 분류와 마찬가지로 각각의 이웃의 개수만 고려하는 것이 아닌 거리까지 고려하는 가중 회귀(Weighted regression)기법을 사용한다.

지금까지 배운 이론을 바탕으로 간단한 실습을 통해 KNN을 어떻게 사용하는지 살펴보자. 학습모델을 통해 기계학습을 진행하고자 한다면 항상 가장 먼저 해야될 것은 내가 사용하고자 하는 학습모델의 장단점을 확실히 알고 가야한다. KNN은 데이터 속 노이즈에 견고하며 학습데이터 수가 많으면 꽤 효과적인 장점이 있다. 하지만 최적의 k 즉, 최적의 이웃의 수와 어떤 거리 척도가 분석에 적합한지 불분명하기에 도메인 및 데이터 각각의 특성에 맞게 임의로 선정해야 하고 이를 실험적으로 접근해야 된다. 또한, 새로운 관측치와 각각의 학습 데이터 사이의 거리를 전부 측정해야 하기에 계산 시간이 오래 걸리는 한계가 존재한다. (이에 따라 KNN의 계산복잡성을 줄이려는 다양한 시도들 또한 존재) 이런 KNN의 장단점을 상기시키며 실습에 들어가보자.
여기서 잠깐!
실습에 들어가기 전 마지막으로 우린 '데이터 분할'에 대해서 알아볼 필요가 있다. 데이터 분할이란, 학습데이터와 검증데이터를 분리하는 것을 말한다. 즉, 내가 학습에 이용할 데이터와 학습 결과를 확인하기 위한 검증 데이터를 나눈다는 것이다. 그렇다면 이런 과정은 왜 필요할까? 이는 학습데이터로 학습시키고 학습에 전혀 사용하지 않은 검증데이터에 적용하여 일반화가 가능한지 알아보기 위해서이다. 쉽게 예를 들어 보자면, 학생에게 답이 달려 있는 100문제를 30분동안 학습하라고 한다고 가정해보자. 그리고 이미 제공했던 그 100문제 중에서 20문제를 맞추어 보라고 하면 학생은 이미 그 20문제에 답을 안 상태에서 그 문제를 풀게될 것이다. 이렇게 되면 이 학생이 사실 문제를 공부한 것인지 답을 외운것인지 알 방법이 없다. 하지만, 20문제가 제공되었던 100문제가 아닌 비슷한 유형의 문제라면 학생이 얼마나 공부를 열심히했는지 객관적으로 판단할 수 있을 것이다. 이게 바로 일반화이다. 우린 학습 모델이 답을 외웠는지가 중요한 것이 아닌 그 문제를 통해 학습을 진행하고 새로운 문제에 대해서 풀 수 있는지에 대한 일반화 능력을 알고 싶은 것이다. 그러므로 학습 데이터와 검증 데이터 분리는 기계학습의 학습 과정에 있어서 필수이다.
실습
1. 분류
분류 실습은 앞에서 iris 데이터를 통해 진행하였다.
iris 데이터는 직접 다운받아 이용할 수도 있지만, seaborn이라는 라이브러리에서 제공하기도 한다.
또한 seaborn은 다양한 시각화 툴을 제공하여 시각화에 사용하기에도 좋은 라이브러리이다.
#iris 데이터 로드
import pandas as pd
import numpy as np
import seaborn as sns
iris = sns.load_dataset('iris') #seaborn을 통한 iris 데이터 로드
iris.head(3) #iris 데이터 확인

#seaborn style "데이터 시각화"
sns.pairplot(iris, hue='species') # pariplot을 통해 특성(feature)들 비교 가능, hue에 목표값 설정

이 부분이 part1에 언급했던 데이터를 의미있는 정보로 만들기 위한 '데이터 시각화' 부분이다. 위와 같은 seaborn의 pariplot은 각 특성들을 1대1로 매칭하여 목표값과의 관계를 보여준다. 사실 이 iris는 특성(feature)이 적어 시각화가 크게 필요로 하지는 않지만, 우리가 실제로 만나게 되는 데이터들은 특성이 수십에서 수백개가 될 수도 있다. 이 모든 특성들을 사실 학습에 사용하게 되면 그만큼 데이터가 상상 이상으로 많이 필요하기도 하고 좋은 예측을 이루어내기 힘들다. 그러므로 우린 위와 같은 시각화를 통해 목표값과 관련 있는 특성들을 추출하며 데이터를 정보로 표현해야 한다.
이제 학습 모델을 학습시키기 위해선 part1에서 배웠던 '데이터 전처리'가 필요하다. 먼저 필수적으로 데이터를 입력값과 목표값으로 나누어주고 학습이 잘 진행되었는지 확인하기 위해 해당 데이터를 학습 데이터와 검증데이터로 분리해준다.
#학습을 위해 데이터 input(입력값)과 output(목표값)을 분리
x = iris.drop('species', axis=1) # 목표값을 분리한 나머지 특성들
y = iris['species'] # 목표값
여기서 중요한 점은 위에서 데이터를 확인했다시피 iris 데이터의 목표값은 텍스트이자 범주형이다. 우린 이를 실수화할 필요가 있다. (One-Hot Encoding은 메모리를 비효율적으로 사용하므로 LabelEncdoer를 통해 변환)
#택스트 자료의 실수화 (species는 실수형 자료가 아닌 텍스트 자료이므로)
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
new_y = le.fit_transform(y) #실수화 진행
set(new_y) #실수화 결과 확인
# -> {0, 1, 2}
이제 학습 후 모델이 예측을 잘하는지 검증하기 위해 학습데이터와 검증데이터로 분리해준다.
#데이터 분류 (검증 데이터 마련. 학습데이터와 검증데이터로 분리)
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, new_y, test_size=0.2, random_state=22, stratify=new_y)
print(f'{x_train.shape} || {x_test.shape}')
# -> (120, 4) || (30, 4)
# 학습데이터 120개, 검증데이터 30개로 분리
이때 중요한 점은 train_test_split의 인자들 중 random_state와 stratify이다. random_state는 랜덤 시드를 고정하여 다시 분리할 때도 똑같은 데이터들이 분리될 수 있도록 설정해준다. stratify는 균형있게 검증데이터를 구성해주는 인자이다. iris 데이터의 목표값은 총 3가지인데, stratify는 이 각각의 카테고리를 적절하게 뽑아와 검증데이터를 구성하게 해준다. (0:10개, 1:10개, 2:10개) stratify를 설정해주지 않으면 편향된 데이터 구성이 이루어져 검증이 제대로 이루어지지 못하는 경우가 있으므로 유의해야된다.
다음으로 데이터 정규화 혹은 표준화를 통해 데이터가 가진 특성 간 스케일 차이를 줄여준다.
# 표준화 과정 진행
from sklearn.preprocessing import StandardScaler # STD, 표준화 기능 호출
std = StandardScaler() # 표준화 기능 선언
x_train_std = std.fit_transform(x_train) # 학습데이터에 맞게 변경 후 저장
x_test_std = std.transform(x_test) # 검증데이터를 학습데이터에 맞게 변경 후 저장
여기서 중요한 부분은 검증데이터를 학습데이터에 맞게 변경하는 부분이다. 예측 모델은 학습데이터를 통해 학습되기에 검증데이터를 검증데이터에 맞게 전처리(스케일링)를 진행하면 예측 모델은 학습데이터와 다르게 전처리(스케일링)된 데이터를 예측하는 것이기에 제대로된 예측이 이루어지지 않을 것이다. 그러므로 검증데이터 또한 학습데이터에 맞는 전처리(스케일링)가 필요한 것이다.
마지막으로 이제 전처리가 완료된 데이터를 통해 KNN 학습 모델을 학습시키자
# KNN 학습 모델을 통한 학습 진행
from sklearn.neighbors import KNeighborsClassifier
KNN = KNeighborsClassifier(n_neighbors=5, p=2, weights='uniform')
# uniform = 다수결 법칙, distance = 가중 합 방식(거리 고려)
KNN.fit(x_train, y_train) # 학습 진행
k (n_neighbors)는 5로 설정하고 가중 합 방식을 고려하지 않고 (다수결 법칙 -> uniform) 단순 다수결 법칙으로 학습이 이루어지게 설정하였다. 즉, 주변 5개의 이웃을 거리를 고려하지 않고 그저 개수로만 임의의 데이터의 목표값을 예측한다. (다수결일지 가중합일지 선택은 실험적으로 접근이 필요) p는 거리 측정 척도를 설정할 수 있는 인자이다. p=1 일때는 manhattan_distance, p=2 일 때는 euclidean_distance 측정 방식을 이용한다. 이는 데이터에 따라 실험적으로 설정해야 되는 부분이다.
이제 검증데이터를 이용하여 예측 정확도(일반화 능력)를 측정해보자
KNN.score(x_test,y_test)
# 0.9666666666666667
정확도 96%로 높은 정확도를 보였다. (accuracy score 성능 평가 기준 사용)
여기서 재밌는 점은 데이터 전처리 시에 정규화 및 표준화 과정을 거치지 않은 것이 더 좋은 성능을 보인다는 것이다. 이는 정규화 과정을 거치면 오히려 정확도가 더 떨어지기 때문이다. 이처럼 모든 데이터가 정규화 과정을 필요로 하는 것은 아니다. 정규화 과정도 앞서 하이퍼 파라미터를 조정하는 것처럼 실험적으로 접근하는 것이 옳다. 그 어떤 데이터든 정해진 분석방법은 없다는 것을 항상 유이해야 된다.
2. 회귀
실습에서의 회귀는 KNeighborsClassifier 대신 KNeighborsRegressor를 사용한다는 것 말고는 분류와 크게 다를 점이 없다. 이론에서 설명한 예시(영화 등급 예측)를 통해 실습을 진행해보자.
# 학습데이터
train_data=[[0.5, 0.2, 0.1, 5.0],
[0.9, 0.7, 0.3, 6.8],
[0.4, 0.5, 0.7, 9.0]]
# 입력값과 목표값 분리
x = [i[:-1] for i in train_data]
y= [i[-1] for i in train_data]
#학습 모델 설정
from sklearn.neighbors import KNeighborsRegressor # 회귀
KNN = KNeighborsRegressor(n_neighbors=3, weights='distance') # 가중 회귀 기법 사용 (거리 고려)
KNN.fit(x,y) # 학습
# 레이블이 없는 데이터
unknown_data=[[0.2,0.1,0.7],
[0.4,0.7,0.6],
[0.5,0.8,0.1]]
predict = KNN.predict(np.array(unknown_data)) # 예측 진행
predict # -> array([7.28143288, 7.76451922, 6.8457845 ])
이렇게 회귀도 분류와 마찬가지로 학습된 모델을 통해 데이터(입력값)만 주어진다면 해당 입력값에 대한 예측 결과를 얻을 수 있다.
'공부 > 기계학습 및 인공지능' 카테고리의 다른 글
Machine Learning (기계학습) - part 4 [판별분석(Discriminant Analysis)] (0) | 2022.01.09 |
---|---|
Machine Learning (기계학습) - part 3 [로지스틱 회귀(Logistic Regression)] (0) | 2022.01.06 |
Machine Learning (기계학습) - part 1 [기계학습, 데이터] (0) | 2022.01.04 |
U-Net 간단 리뷰 (0) | 2021.09.14 |
SegNet 간단 리뷰 (0) | 2021.09.13 |