Post

[혼공머신] 2주차 03-1 k-최근접 이웃 회귀

[혼공머신] 2주차 03-1 k-최근접 이웃 회귀

본 게시글은 한빛미디어의 혼자 공부하는 머신러닝+딥러닝을 바탕으로 작성되었습니다.

혼공학습단

이제 2주 차 혼공학습단이 되었다. 피드백을 기다리다가 혼공학습단을 몇 명이 하고 있는지 확인해 보았다. 250명… 혼공족장님은 250명을 다 혼자 피드백하시고 계신 건가 하는 궁금증이 생겼다. 작성하시는 것을 보면 혼자 하시는 것 같긴 한데, 만약 내가 이렇게 한다면 250명의 글을 모두 읽고 피드백을 하지는 못할 것 같다는 생각이 들었다. 만약 250명의 글에 다 들어가서 피드백으로 남길 디테일들을 기록하고 적는다면 난 일주일은커녕 하루 만에 포기하고 말 것 같다. 아, 그리고 간식을 받는 것에 성공해 매우 기뻤다. 이번에 받은 것은 매머드익스프레스 꿀커피였다. 비록 커피를 좋아하지는 않으나 다른 것으로 바꿔서 먹을 수 있을 것이기에 나중에 들러봐야겠다.

image

그리고 패들랫에 가입하지 않아도 글은 올릴 수 있다고 피드백을 주셨던데… 사실 그것은 알고 있었으나 프로필 사진이 마음에 들지 않아 바꾸려고 했었다. 그런데 프로필 사진이 이미 만들어진 목록 중에서 고르는 것이 아니라 직접 올리거나, 생성형 AI로 만들거나 그리는 등 그냥 고르기만 하면 되는 것이 아니었다. 그래서 예전에 지웠던 패들랫 계정을 다시 만들어서 사용했지만 결국 게시글 올릴 때 이름이 나오는 것으로 만족하기로 하였다.

KNN Classification

이제 지금까지 살펴본 KNN 알고리즘을 조금 더 살펴볼 것이다. 지난번에 했던 것은 KNN 알고리즘을 이용하여 도미와 빙어의 classification였다. 그런데 그냥 classification 말고 예측도 가능할까?

아마 통계학을 공부했다면 질리도록 배울 것인 회귀분석(Regression Analysis)에 대해서 알 것이다. 몰라도 상관은 없다. 회귀를 간단하게 말한다면 도미와 빙어 중 하나로 data point를 classify 하는 것이 아니라, 일부 도미의 무게 또는 길이가 없을 때 그 없는 data를 predict 하는 것이다. KNN 알고리즘은 이 두 가지를 모두 할 수 있다. 이 두 가지를 설명하기에 앞서, 간략하게 설명한 적이 있지만, 이번엔 KNN 알고리즘 자체에 대해서 다루기 때문에 KNN 알고리즘에 대해서 처음부터 설명을 해보겠다.

우선, 쉽게 이해하기 위해 classification 문제를 해결하는 방법을 예로 들어 설명하겠다. 아래와 같이 점들이 있다고 할 때, 파란색 점이랑 붉은색 점, 두 가지 class가 있다고 가정하겠다. 이때 우리는 주황색 점이 둘 중 어느 것에 속할 확률이 더 큰지, 어느 것에 더 가까운지 확인하고 싶다.

image

이러한 경우, 우리의 KNN 알고리즘은 매우 분명한 답을 내어준다. 가장 가까운 $K$개의 점을 찾고, 그 $K$개의 점들 중에서 제일 많은 개수를 가진 class를 찾아 그 class에 주황색 점을 배정하는 것이다.

이걸 시각적으로 간단하게 표현해 보자. 주황색 점을 중심으로 하는 원이 있을 때, $K=1$일 때 원 안에는 붉은색 점 하나뿐이므로 주황색 점은 붉은색 점의 class에 속할 확률이 높다고 할 수 있다.

image

만약 $K=3$이라면 아래와 같이 표현할 수 있다. 아까 $K=1$이었을 때는 붉은색 점이 하나 있고, 파란색 점이 0개 있어서 붉은색 점의 class로 분류를 하였으나, 이번에는 아까와 동일하게 붉은색 점이 하나 있으나, 파란색 점이 2개로, 파란색 점이 더 많다. 따라서 이번에는 주황색 점이 파란색 점의 class로 배정이 될 확률이 높게 나타난다고 할 수 있다.

image

지금까지 본 것과 같이 KNN 알고리즘은 거리를 바탕으로 한다는 것을 알 수 있다. 방금 우리가 원으로 살펴본 것은 원의 반지름을 활용한 것으로, 이를 조금 더 직관적으로 선으로 그어서 표현하면 아래와 같이 표현할 수 있다.

image

이렇게 점과 점 사이의 거리를 바탕으로 우리는 KNN 알고리즘을 적용하게 된다. 이것을 통해서 classification 문제를 해결하는 방법은 알게 되었다. 그런데 regression 문제는 어떻게 해결할까?

KNN Regression

사실 이것도 간단하다. 약간 그래프가 달라진 것 같지만, 그래프를 이쁘게 그리기 위해 바꾸었다고 생각해 주고 아래 그래프를 보자. 아까와 같이 $K=3$이라고 하면 숫자를 예쁘게 적은 3개의 점만 선택이 될 것이다. 그럼, 이 점들의 평균을 구하면 된다. $\frac{3+4+6}{3}\approx4.3$으로 약 4.3이 됨을 알 수 있다.

image

그런데 우리는 그래프를 봤을 때 대충 점의 $y$값이 5 정도 일 것이라고 생각할 수 있다. 하지만 이건 설명을 하기 쉽도록 하기 위함이다. 사실 잘 생각해 보면 약간 이상하다. 분명 아까 KNN 알고리즘은 거리를 바탕으로 한다고 했는데 주황색 점의 $y$값을 추정하는 것이 아니었나? 그럼 주황색 점의 $y$값이 없으니, 점과 점 사이의 거리를 구할 수 없는 게 아닐까? 라고 생각할 수 있다.

물론 이러한 생각이 안 들어도 상관없다. 살면서 이걸 손으로 풀어볼 일은 대학 수업에서 말고는 거의 없을 것이다. 그래도 이걸 잘 생각보면 다른 방법으로 해결할 수 있다는 것을 알 수 있다. 우리는 $y$값은 없는 대신 $x$값은 가지고 있다. 따라서 우리는 $x$값만을 가지고 점과 점 사이의 거리를 구하면 되는 것이다. 즉, $x$만을 기준으로 가장 가까운 3개의 점을 찾고, 그 3개의 점의 $y$값의 mean을 구하면 되는 것이다.

농어 무게 예측

지금까지 도미와 빙어를 너무 많이 살펴보았다. 이 정도로 봤으면 비린내가 날 것이기에 한빛미디어는 이번엔 싱싱한 농어를 새로 가져왔다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np

perch_length = np.array([8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0, 21.0,
       21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5, 22.5, 22.7,
       23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5, 27.3, 27.5, 27.5,
       27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0, 36.5, 36.0, 37.0, 37.0,
       39.0, 39.0, 39.0, 40.0, 40.0, 40.0, 40.0, 42.0, 43.0, 43.0, 43.5,
       44.0])
perch_weight = np.array([5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0, 110.0,
       115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0, 130.0,
       150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0, 197.0,
       218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0, 514.0,
       556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0, 820.0,
       850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0, 1000.0,
       1000.0])

Data가 있으면 우리는 당연히 visualization을 해야 한다. 해보자.

1
2
3
4
5
6
import matplotlib.pyplot as plt

plt.scatter(perch_length, perch_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

image

이제 학습을 해야 하므로 우린 무의식적으로 train data와 test data로 나눠야 한다. 나는 친절하기 때문에 아래와 같이 코드를 다 적었다. 적어도 되지만, 기억이 안 나는 사람은 복사를 해도 된다.

1
2
3
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(perch_length, perch_weight, random_state=0)

지난번에 scikit-learn에 대해서 공부했을 때, 데이터는 2차원 배열이어야 해서 numpy를 통해 변환을 했던 기억이 있을 것이다. 이제 그걸 해보자.

1
2
X_train = X_train.reshape(-1, 1)
X_test = X_test.reshape(-1, 1)

결정계수

Scikit-learn에서 사용하기 적당하게 data를 변환했으므로 이제 학습을 해야 할 시간이다. 학습을 한 다음에 점수를 확인해 보자.

1
2
3
4
5
from sklearn.neighbors import KNeighborsRegressor

knn = KNeighborsRegressor()
knn.fit(X_train, y_train)
knn.score(X_test, y_test)

0.9162089041423581

어? 근데 점수? 무슨 점수지? 라고 생각을 해야 할 것이다. 지난번에 classification에서 살펴봤던 점수는 정확도(accuracy)이다. 그런데 여기서도 accuracy일까? 아쉽게도 여기서는 다른 점수를 사용한다. 바로 결정계수(Coefficient of Determination), $R^2$이다.

$R^2$에 대해서 할 수 있는 말이 엄청나게 많지만, 그것에 대한 내용은 나중에 Regression Analysis에 대해서 설명하는 글을 쓸 때 작성하고, 여기서는 그냥 어떻게 구하는지만 살펴보자.

$R^2=1-\frac{(y값-예측)^2의 합}{(y값-평균)^2의 합}$

우선, 교재에는 위와 같이 작성되어 있다. 이 식을 간단하게 보면 $y$값이 있는데, 예측한 $y$값이 mean에 가까워지면 $R^2$는 0에 가까워지고, 예측한 $y$값이 값이 실제 $y$값에 가까워지면, $R^2$은 1에 가까워지게 됨을 알 수 있다. 하지만 우린 조금 더 자세하게 살펴보자. 우린 머신러닝을 하려면 결국 통계를 건드리게 될 수밖에 없다. 따라서 식을 봤을 때 조금 속이 안 좋더라도 맛보기 정도로 생각하고 보자.

$R^2=1-\frac{\sum^n_ {i=1}(y_ i-\hat{y}_ i)^2} {\sum^n_ {i=1}(y_ i-\bar{y})^2}$

벌써 어지럽더라도 어쩔 수 없다. 벌써 이런 것으로 어지럽다면 나중에 회귀에 대해서 다룰 때는 기절을 하게 될 수도 있다. 그렇기에 억지로라도 이해하려고 해야 한다. 우선, 기본적인 용어, 표기부터 보자.

먼저, 합 기호이다. 물론 대부분 학교에서 배웠을 것으로 예상하지만 혹시라도 까먹은 사람이 있을 수도 있으니 친절하게 설명해 주도록 하겠다. 아래를 보면 $\Sigma$(시그마, Sigma) 아래의 $i=1$이 보이고, 위에 $n$가 있는 것을 볼 수 있다. 그리고 오른쪽에 $y_i$가 있음을 알 수 있다. 이것은 $i$가 1부터 $n$까지 변화할 때, $y_i$에 그 $i$를 대입하게 된다. 그럼 $y_1, y_2, y_3, \cdots, y_n$이 될 텐데, $\Sigma$의 의미는 이 $y_i$들을 다 더한다는 의미이다. 따라서 오른쪽의 수식과 동일한 의미가 된다.

$\sum^n_{i=1}y_i=y_1+y_2+y_3+\cdots+y_n$

그리고 평균(Mean) 기호를 보자. 대부분 알고 있겠지만, 추정된 값을 나타내는 $\hat{}$ 과 혼동할 우려가 있다고 생각되어 이것도 친절히 설명해 주겠다. 누구나 알고 있듯 평균은 모든 데이터를 더한 후, 데이터의 수로 나눠주는 것이다. 아래에 보니 방금 살펴본 합 기호가 있다. 즉 모든 데이터를 더해준 것이다. 이때, 우리는 $i=1$부터 $n$까지 $y_i$를 더한 것이므로, 모두 더하는 $y_i$의 개수는 $n$개가 됨은 당연함을 알 수 있다. 따라서 아래와 같이 평균을 구할 수 있게 된다. 이때, 평균의 기호는 $\bar{}$ (바, Bar)를 사용한다. 읽는 방법은 $\bar{y}$는 “$y$바”로 읽으면 된다.

$\frac{1}{n}\sum^n_{i=1}y_i=\bar{y}$

마지막으로, 추정값(Estimate)이다. 여기서는 굳이 추정(Estimation), 추정량(Estimator), 추정량(Estimate)와 같은 세부적인 것을 설명하지는 않겠다. 그냥 우리는 추정된 값인 추정값만 볼 것이다. 추정값은 말 그대로 추정한 값이다. 우리가 KNN regression을 통해 구한 값은 추정값이 되는 것이다. 표현은 아래와 같이 $\hat{}$ (햇, Hat) 를 써서 하게 되는데 $\hat{y}$는 “$y$햇”로 읽으면 된다.

$\hat{y}$

이전에 말하려고 했던 것 중 하나 까먹은 것이 있는데, 항상 교수님께서 말씀하시는 것이 있다. 통계학도들은 가설 중 어떤 것이 맞다, 틀리다고 말해서는 안 된다는 것이다. 어? 그런데 우리는 지금까지 KNN 알고리즘을 활용하니 샘플이 도미이다, 빙어이다 이런 식으로 말했던 것을 기억할 것이다. 하지만 우리는 그렇게 말하는 것을 지양해야 한다. 왜냐하면 우리는 그 샘플에 대한 것을 눈감고 그냥 찍는 것보다 더 나은 방법으로 추측하는 것이지 직접 본 것이 아니기 때문이다. 그렇기 때문에 표현을 하려면 ~일 확률이 유의미하게 높다, ~라고 판단할 유의미한 증거가 있다라는 식으로 단정적인 표현 대신 확률적으로 기술(記述)해야 한다는 것이다.

오차

조금 사족이 많이 길었던 것 같다. 그래도 언젠간 한번 언급하고 싶었던 내용이다. 이제 다시 $R^2$으로 돌아가자. 사실 아래의 식은 교재에 적혀있는 내용을 그냥 수식으로 그대로 옮긴 것이다. 이것에 대해서 조금 이제 통계적으로 설명을 해보자면, 아까 말했듯이 우리는 직접 보지 않는 이상 정확한 값을 절대 찾을 수 없다. 반드시 오차(Error)가 발생하게 된다. 그런데 이 error에는 우리가 줄일 수 있는 오류 $SSR$(Sum of Squares due to Regression)와 줄일 수 없는 오류 $SSE$(Sum of Squared Errors(Residuals))가 있고, 그 둘을 합친 것을 $SST$(Total Sum of Squares deviations)이라고 한다. 설명을 보다가 이해가 안 되면 아래의 힘들게 그린 그래프를 참고하길 바란다.

image

여담이지만 그래프를 예쁘게 그리는 것은 아직도 어렵다… 아무리 해도 만족스럽지가 않다.

조금 더 설명하자면, 나중에 선형 회귀에서 다룰 진 모르겠지만, $SSR$은 우리가 알고리즘, 모형을 조절하여 줄일 수 있게 되는 error이다. $SSE$는 측정 과정 또는 알 수 없는 이유로 발생하게 되는 오차이다. 아마 살면서 100%인 것은 없다는 말을 들어본 적이 있을 것이다. 그냥 그런 것이라고 생각하면 된다. 공장에서 물건을 만들 때도 오차가 발생하고, 생물들도 돌연변이가 생긴다. 이러한 것은 우리가 예측하기는 어렵다. 그렇기에 우리가 조절할 수 없는 error로 처리하는 것이다.

이제 $SST, SSR, SSE$를 수식으로 조금만 더 살펴보자. 지금까지 한 것도 힘들었으리라 생각된다만, 이제 거의 다 왔다. 이 부분을 위해 지금까지 설명을 한 것이다. 먼저, $SST$부터 설명하도록 하자. 간단히 말해서 전체 error이다. 이것은 그냥 각 data에 전체 data의 mean을 뺀 후 제곱해서 다 더한다.

$SST=\sum^n_{i=1}(y_i-\bar{y})^2$

여기서, 아… 지금까지 한 것도 힘든데 그냥 더하지 왜 굳이 제곱을 한 후에 더하는 거야?라고 불만을 가지는 사람도 있을 것이라고 생각한다. 그러나 이렇게 된 것은 다 이유가 있는 것이다. 예를 들어 $i=1, 2, 3$일 때 data가 $x_i=1, 2, 3$이 있다고 생각해 보자. 이때 $\bar{x}=2$이 될 것이다. 그럼 이 data에 mean을 그냥 빼면 $-1, 0, 1$d이 되고, 다 더하면 0이 되어버린다. 이렇게 되면 굳이 error를 구하는 의미가 없어진다. 분명 mean과 차이가 있는데 error는 0이 나와버리기 때문이다. 그렇기에 우리는 양수와 음수가 서로 상쇄되지 않게 하기 위해 제곱을 하는 것이다. 제곱을 하면 모두 양수가 되기에 음수인 경우도 반영을 할 수 있게 된다.

다음은 $SSR$이다. $SSR$은 예측 가능한 error라고 했는데 무슨 의미일까? 그건 식을 살펴보면 알 수 있다. 식을 보면 추정된 $y_i$값에 mean을 빼는 것이다. 즉, 우리가 추정을 잘해서 평균에 가깝게 된다면 error는 0에 가깝게 되는 것이다. 따라서 우리는 이 $SSR$을 최소화할 수 있도록 해야 하는 것이다.

$SSR=\sum^n_{i=1}(\hat{y}_i-\bar{y})^2$

마지막으로 우리가 추측할 수 없는 error인 $SSE$이다. 이것도 간단하게 생각하면 된다. 전체 error, 즉 $SST$에서 우리가 설명할 수 있는 error, $SSR$을 빼면 된다. 그런데 아래 식을 보니 조금 이상하게 생겼다. 어라, 뭐지? 라고 생각할 수 있다. 하지만 걱정하지 않아도 된다. 이것에 대해 의문을 품을 여러분을 위해 누구나 좋아하는 증명 과정을 아래에 작성해 두려고 했으나, 그걸 다 작성하면 이걸 보다가 기절하는 사람이 속출할 것 같아 다른 게시글에 적도록 하기로 하였다. 따라서 아래 식은 그냥 참고로 보면 된다. 만약 그래도 내용을 보고 싶다면 SST, SSR, SSE 관계 유도를 참고하면 된다.

$SSE=\sum^n_{i=1}(y_i-\hat{y}_i)^2$

이렇게 해서 우리는 $SST$는 전체 error, $SSE$은 설명 불가능한 error임을 알 수 있게 되었다. 그럼 이를 바탕으로 $R^2$를 한 번 살펴보자. 식을 보니 1에 설명 불가능한 error를 전체 error로 나눠준 것을 뺀다는 것을 확인할 수 있다. 즉 설명 가능한 error의 비율을 구하는 식임을 알 수 있다. 따라서 $R^2$은 전체 error 중 설명 가능한 error의 비율임을 알 수 있다. 모델이 있을 때, 설명 불가능한 error보다 설명 가능한 error의 비율이 높다면 좋을 것이다. 설명 가능한 error는 우리가 모델 변형을 통해서 줄일 수 있기 때문이다. 따라서 $R^2$은 높을수록 좋다는 것을 알 수 있다.

$R^2=1-\frac{SSE}{SST}=\frac{SSR}{SST}=1-\frac{\sum^n_ {i=1}(y_ i-\hat{y}_ i)^2}{\sum^n_ {i=1}(y_ i-\bar{y})^2}$

평균절대오차

글이 조금 많이 길어진 감이 있지만 아직 두 가지 주제가 남았기에 어쩔 수 없다. 하지만 나머지 주제들은 간단하게만 설명할 수 있는 것들이라 정말 간단하게만 설명하고 넘어갈 것이다. 우리의 교재에서는 $R^2$은 accuracy보다 직관적으로 알아보기 어렵다는 이유로 평균절대오차(MAE, Mean Absolute Error)를 제시해 준다. 이것은 통계에서 써본 거의 기억이 없기에 굳이 수식을 보진 않고, 바로 코딩으로 넘어가도록 하자.

1
2
3
4
5
from sklearn.metrics import mean_absolute_error

y_predict = knn.predict(X_test)
mae = mean_absolute_error(y_test, y_predict)
mae

42.27142857142858

결과를 보니, 평균적으로 19g 정도 실제 y값과 다르다는 것을 알 수 있다.

과대적합, 과소적합

우리는 지금까지 train data를 사용해서 학습을 하고, test data를 사용하여 평가를 했다. 그런데 train data를 사용해서 학습을 한 뒤에 train data에 대해서 평가를 해보면 어떻게 될까? 당연히 train data를 사용해서 학습을 했기에 높은 점수가 나올 것이다. 그런데, 이것이 조금 극단으로 치닫게 되는 경우가 있다.

예를 들어 매번 족보에서 시험을 내시던 교수님이 있다. 그래서 우리는 족보만을 보고 다른 건 아무것도 공부를 하지 않은 채로 시험을 보러 갔다. 그런데 갑자기 교수님께서 무슨 바람이 드셨는지 문제를 다 바꾸어 버린 것이다. 그러면 우리는 교수님께 편지를 쓰고 나올 수밖에 없다. 이러한 경우 train data에 대한 점수는 매우 높게 나오지만 test data에 대한 점수는 매우 형편없게 나올 것이다. 이와 같이 train data에 대해서 너무 많이 학습이 되어서 test data에 대해 지나치게 낮게 점수가 나오는 경우를 과대적합(Overfitting)이라고 한다.

그러면 만약 overfitting을 방지하기 위해서 train data를 매우 적게 한다고 해보자. 그러면 어떻게 될까? 우리가 족보만 너무 외우는 걸 막으려고 공부를 조금만 하게 되면 어떻게 될까? 그렇다. 폭망할 것이다. 여기서도 동일하다. 지나치게 train data를 적게 해서 trian data, test data 두 가지 모두의 점수가 낮게 나오는 경우를 과소적합(Underfitting)이라고 한다. 물론, train data에 대한 점수가 test data에 대한 점수보다 낮게 나오는 경우도 있기는 하다. 하지만, 그런 경우가 그렇게 많지는 않다.

우리가 머신러닝을 하면서 자주 보게 될 문제는 overfitting이다. 머신러닝, AI, 빅데이터는 data가 많이 없어서 sample data를 뽑아내는 통계와는 다르게 많은 data를 가지고 있는 것을 가정으로 하므로 underfitting이 될 정도의 데이터가 있는 경우가 흔치는 않을 것이다. 하지만 나중에 볼 파라미터 조절 과정에서 발생하게 될 우려가 있을 수도 있으므로 참고로 알아두도록 하자.

기본 숙제

글을 다 적고 생각해 보니까 숙제가 있었다. 그래서 뒤늦게 추가해 본다. 다른 분들의 게시글을 보니 그냥 문제를 다 적고 계신 것 같아서 나도 그냥 적기로 했다.

  1. k-최근접 이웃 회귀에서는 새로운 샘플에 대한 예측을 어떻게 만드나요?
    ① 이웃 샘플 클래스 중 다수인 클래스
    ② 이웃 샘플의 타깃값의 평균
    ③ 이웃 샘플 중 가장 높은 타깃값
    ④ 이웃 샘플 중 가장 낮은 타깃값

답: ②
우선, KNN regression은 주어진 값들 중 $K$개의 가장 가까운 값을 기준으로 평균을 구해 추정값을 구한다고 앞서 말한 적이 있다. ①번을 보면, 이웃 샘플 클래스 중 다수인 클래스라고 나와 있다. 이것은 KNN classification에 대한 설명으로, regression가 아닌 classification에 대한 설명이다. 그리고 ③, ④번은 모두 우리가 언급한 적도 없었던 것이다. 따라서 정답은 이웃한 샘플의 타깃값의 평균인 ②가 맞다. 사실 1번은 과제가 아니다. 그럼에도 하는 이유는 2번만 따로 나와 있으면 심기가 불편하기 때문이다. 이왕이면 1, 2 모두 있는 게 좋다.

  1. 과대적합과 과소적합에 대한 이래를 돕기 위해 복잡한 모델과 단순한 모델을 만들겠습니다. 앞서 만든 k-최근접 이웃 회귀 모델의 k 값을 1, 5, 10으로 바꿔가며 훈련해 보세요. 그다음 농어의 길이를 5부터 45까지 바꿔가며 예측을 만들어 그래프로 나타내 보세요. n이 커짐에 따라 모델이 단순해지는 것을 볼 수 있나요?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    knr = KNeighborsRegressor()
    x = np.arrange(5, 45).reshape(-1, 1)
    for n in [1, 5, 10]:
        knr.n_neighbors = # ① (       )
        knr.fit(train_input, train_target)
        prediction = # ② (       )
        plt.scatter(train_input, train_target)
        plt.plot(x, prediction)
        plt.title('n_neighbors = {}'.format(n))
        plt.xlabel('length')
        plt.ylabel('weight')
        plt.show()
    

답: ①: n, ②: knr.predict(x)

image image image

우선, ①부터 살펴보자. ①의 내용은 knr.n_neighbors에 대한 내용으로, 우리가 해야 하는 것은 KNN 모델의 $K$값을 1, 5, 10으로 바꾸어가며 훈련을 해야 한다. 이것은 knr.n_neighbors에 대한 내용으로, knr.n_neighbors의 값을 1, 5, 10으로 바꾸어가면서 훈련해야 함을 알 수 있다. 이때, 위 코드에서는 for 문을 활용하여 n의 값을 1, 5, 10으로 바꾸어가며 반복하게 되어 있으므로, 이 n을 knr.n_neighbors의 값으로 활용해 문제를 해결해야 할 것이다. 따라서 knr.n_neighbors에 n을 그대로 입력하게 된다면 knr.n_neighbors에 1, 5, 10이 차례대로 들어가며 학습과 visualization을 반복하게 될 것이다. 따라서 ①에는 n이 들어가는 것이 맞다.

다음으로, ② 부분을 살펴보자. ②의 부분은 prediction의 값을 정하는 것으로, KNN 알고리즘을 train data를 활용하여 학습한 다음 새로운 값으로 predict를 해야 한다. 그런데 우리는 이 범위에 대해서 이미 x에 저장하였다. 그렇기에 우리는 그 x를 사용하기만 하면 되는 것이다. 따라서 우리는 학습한 KNN 모델을 통해서 x의 값을 활용해 예측을 하면 된다. 따라서 knr.predict(x)를 사용하게 되는 것이다.

마지막으로, n이 커짐에 따라 모델이 단순해지는가에 대한 대답을 할 차례이다. 우리가 위 3가지 그래프를 보았을 때, 확실히 n이 커짐에 따라 모델이 단순해짐을 알 수 있다. 우리는 이렇게 모델이 단순한 것과 복잡한 것을 각각 단순성(Simplicity), 복잡성(Complexity)라고 한다. 둘 중에 어떤 것이 더 좋을까? 이것은 분석의 목적에 따라 달라질 수 있다. 그냥 simple 한 것이 더 좋거나 complex 한 것이 무조건 좋다는 식으로 말할 수는 없는 것이다.

Simplicity가 높아지면 우리는 그 결과를 설명하기가 쉽다. 즉 설명력이 높다. 하지만 모델의 complexity가 높아지면 그 결과를 해석하기는 어려워질 것이다. 즉 해석력(Interpretability)이 떨어지게 되는 것이다. 하지만 simple 한 모델보다는 accuracy가 높아질 가능성이 크다. 따라서 우리는 모델을 설명하고 싶은지, 아니면 단순히 성능만을 원하는지에 따라서 이 둘 사이의 정도를 조절해야 하는 것이다.

This post is licensed under CC BY 4.0 by the author.