본문 바로가기
CS/머신러닝

혼자 공부하는 머신러닝 + 딥러닝 - Ch3-1

by jaehoonChoi 2023. 1. 8.

Ch3-1에서는 KNN 회귀 알고리즘과 그 한계에 대해 공부합니다.

 

KNN 알고리즘은 분류 뿐만 아니라 회귀에서도 사용할 수 있습니다.

값들은 인접한 \(k\)개의 값들의 평균으로 계산됩니다.

KNN 회귀함수는 사이킷런의 KNeighborRegressor을 import하여 사용할 수 있습니다.

어떤 물고기의 데이터를 받아 그래프를 찍어봅시다.

fish_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])

fish_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])

# 분포 확인  
plt.scatter(fish_length, fish_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

 

이제 KNN 알고리즘을 수행해줍시다. 

 

# train, test data set 
train_X, test_X, train_Y, test_Y=train_test_split(
    fish_length, fish_weight, random_state=42
) 

# 2차원 배열로 전환 
train_X=train_X.reshape(-1,1)
test_X=test_X.reshape(-1,1)

# knn 회귀
knr=KNeighborsRegressor()
knr.fit(train_X, train_Y)

print(knr.score(test_X, test_Y))

그 결과는 

0.992809406101064

가 나오게 됩니다. 테스트 결과가 만족스럽네요. 하지만 이런 입력은 어떨까요?

지금까지 훈련한 범위를 벗어나는 값을 줘보는 것입니다. 그 값을 찍은 그래프를 보면, 

노란 점과 초록점은 훈련데이터와 동떨어진 점입니다. 

현재 두 점의 좌표는 각각 (47.4, 1342.2) , (49.2 , 1512.9) 입니다. .

이제 KNN 회귀로 예측해보겠습니다.

print(knr.predict([[47.4]]))
print(knr.predict([[49.2]]))

그 결과는 

[1010.]
[1010.]

아.. 문제가 생겼습니다. 그보다 두 값을 같다고 예측을 한다니 뭐가 잘못된걸까요?

KNN 알고리즘은 현재 데이터들중에서 \(k\) 개로 예측을 하는 모델입니다. 따라서 어느정도 범위를

넘어간다면 당연히 선택되는 영역도 같아지고 그 평균 또한 훈련데이터 안에서만 놀게 됩니다.

즉, 새로운 length에 비례하는 더 큰 weight를 예측해주지 못한다는 단점을 지니고 있습니다.

이를 해결하기 위한 한 방법으로 선형 회귀가 있습니다. 이 부분은 3-2에서 공부합니다.

오늘의 전체 코드입니다.

import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split 
from sklearn.neighbors import KNeighborsRegressor

fish_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])

fish_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])

# 분포 확인  
plt.scatter(fish_length, fish_weight)
plt.scatter(47.4, 1342.2, marker='^')
plt.scatter(49.2, 1512.9, marker='^')

plt.xlabel('length')
plt.ylabel('weight')
plt.show()

# train, test data set 
train_X, test_X, train_Y, test_Y=train_test_split(
    fish_length, fish_weight, random_state=42
) 

# 2차원 배열로 전환 
train_X=train_X.reshape(-1,1)
test_X=test_X.reshape(-1,1)

# knn 회귀
knr=KNeighborsRegressor()
knr.fit(train_X, train_Y)

print(knr.score(test_X, test_Y))

print(knr.score(train_X, train_Y)) 

print(knr.predict([[47.4]]))
print(knr.predict([[49.2]]))

 

 

 

댓글