본문 바로가기

인공지능/머신러닝

[머신러닝ML] 머신러닝 실습 - KNN모델(회귀모델)

~ 목차 ~

라이브러리 정의

 


import numpy as np
import matplotlib.pyplot as plt

# 폰트 환경설정 라이브러리
from matplotlib import font_manager, rc

plt.rc("font", family = "Malgun Gothic")
### 그래프 내에 마이너스( - ) 표시 기호 적용하기
plt.rcParams["axes.unicode_minus"] = False

from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsRegressor

### 회귀평가 라이브러리
from sklearn.metrics import mean_absolute_error

### 선형회귀모델
from sklearn.linear_model import LinearRegression


 


 

농어 데이터 회귀 분석 - KNN모델

 

    - Data

 


### 농어 길이 
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]
     )


    -  농어의 길이로, 무게 예측하기


### 농어의 길이로, 무게 예측하기
# - 독립변수 : 길이
# - 종속변수 : 무게(연속형)
perch_length.shape, perch_weight.shape

 ==> 출력 : ((56,), (56,))

    -  산점도 그리기


### 산점도 그리기
plt.scatter(perch_length, perch_weight, c="purple", label="perch")
plt.xlabel("length")
plt.ylabel("weight")
plt.legend()
plt.title("농어 데이터")
plt.show()

### 해석
# 초반에는 곡선을 띄는 듯 하다가, 증반부 부터는 직선의 형태를 나타내고 있음
# 종속변수가 연속형 데이터이며, 선형 분포를 나타내기에 회귀모델을 사용함

해석🪄
- 초반에는 곡선을 띄는 듯 하다가, 증반부 부터는 직선의 형태를 나타내고 있음
- 종속변수가 연속형 데이터이며, 선형 분포를 나타내기에 회귀모델을 사용함

 

농어 산점도 그래프

 

    -  훈련 및 테스트 데이터 분류하기


### 훈련 : 테스트 = 75 : 25로 구분
### 사용변수 : train_input, train_target, test_input, test_target
train_input, test_input, train_target, test_target = train_test_split(perch_length,
                                                                      perch_weight,
                                                                      test_size=0.25,
                                                                      random_state=42)
print(f"{train_input.shape} : {train_target.shape}")
print(f"{test_input.shape} : {test_target.shape}")

 ==> 출력 :(42,) : (42,)
                   (14,) : (14,)

 

    -  훈련 및 테스트의 독립변수를 2차원으로 만들기


### 훈련 독립변수 2차원 만들기
reshape() : 차원만들어주는 함수 (-1 : 전체 행, 1 : 1개의 열을 만들겠다.)
train_input = train_input.reshape(-1, 1)

### 테스트 독립변수 2차원 만들기
test_input = test_input.reshape(-1, 1)

print(f"{train_input.shape} / {test_input.shape}")

 ==> 출력 : (42, 1) / (14, 1)

    -  훈련 모델 생성하기


### 훈련 모델 생성하기
knr = KNeighborsRegressor()
knr

 ==> 출력 :

훈련 모델 생성

 

   -  모델 훈련 시키기


knr.fit(train_input, train_target)

 ==> 출력 :

훈련 모델 생성

 

정확도에 대한 용어 정의

 :  분류에서는 "정확도"라고 칭하며,  회귀에서는 "결정계수(R^2)"이라고 칭합니다.


### 훈련 정확도 확인하기
train_r2=knr.score(train_input, train_target)

### 테스트 정확도 확인하기
test_r2 = knr.score(test_input,test_target)

print(f"훈련={train_r2} / 테스트={test_r2}")

 ==> 출력 : 훈련=0.9698823289099254 / 테스트=0.992809406101064

해석🪄
-  훈련 및 테스트 정확도는 매우 높게 나타난 성능 좋은 모델로 판단되나, 과적합 여부를 확인한 결과,
   훈련 정확도가 테스트 정확도보다 낮게 나타난 것으로 보아 과소적합이 발생하고 있는것으로 판단됨
- 이는 데이터의 갯수가 작거나, 튜닝이 필요한 경우로 이후 진행을 하고자 함
  (이에 따라, 성능을 높이기 위한 하이퍼파라메터 튜닝이 필요해보임)

 


모델 평가하기 : 평균절대오차(MAE)

<평균절대오차(MAE; Mean Absolute Error)>
 - 회귀에서 사용하는 평가방법
 - 예측값과 실제값과의 거리 차이를 평균하여 계산한 값
 - 즉, 사용된 이웃들과의 거리차를 절대값으로 평균한 값 


### 회귀평가 라이브러리
from sklearn.metrics import mean_absolute_error

### 예측하기
test_pred = knr.predict(test_input)
test_pred

### 평가하기
mae = mean_absolute_error(test_target, test_pred)
mae

 ==> 출력 : array([  60. ,   79.6,  248. ,  122. ,  136. ,  847. ,  311.4,  183.4, 847. ,  113. , 1010. ,   60. ,  248. ,  248. ])

                    19.157142857142862

해석🪄
 - 해당 모델을 이용해서 예측을 할 경우에는 평균적으로 약 19.157g 정도의 차이(오차)가 있는 결과를 얻을 수 있음
- 즉, 예측결과는 약 19.157g 정도의 차이가 있음


- 과소적합을 해소하기 위하여 [하이퍼파라메터 튜닝]을 진행해 보기


### KNN 모델의 이웃의 갯수(하이퍼파라메터)를 조정해보기

### 이웃의 갯수 -> 조정
knr.n_neighbors = 3

### 하이퍼파라메터 값 수정 후 재훈련 시켜서 검증해야 한다.
knr.fit(train_input, train_target)

### 훈련 정확도 확인
train_r2 = knr.score(train_input, train_target)

### 테스트(검증) 정확도 확인
test_r2 = knr.score(test_input, test_target)

print(f"훈련={train_r2} / 테스트 = {test_r2}")



 ==> 출력 : 훈련=0.9804899950518966 / 테스트 = 0.9746459963987609

해석🪄
 -  과소적합 해소를 위해 이웃의 갯수를 조정하여 하이퍼파라메터 튜닝을 진행한 결과 과소적합을 해소할 수 있었음
- 또한, 훈련 정확도와 테스트 정확도의 차이가 크지 않기에 과대적합도 일어나지 않았음
- 다만, 테스트 정확도는 다소 낮아진 반면, 훈련 정확도가 높아졌음
- 이 모델은 과적합이 발생하지 않은 일반화된 모델로 사용가능

 


### 1보다 작은 가장 좋은 정확도일 때의 이웃의 갯수 찾기
### 모델(클래스) 생성
knr = KNeighborsRegressor()

### 훈련시키기
knr.fit(train_input, train_target)

# 반복문 사용 : 범위는 3 ~ 전체 데이터 갯수 (짝수갯수로 찾으면 안되고 홀수갯수로 찾아야함)

### 정확도가 가장 높을 때의 이웃의 갯수를 담을 변수
nCnt = 0
### 정확도가 가장 높을 때의 값을 담을 변수
nScore = 0

for n in range(3, len(train_input), 2):
    knr.n_neighbors = n
    score = knr.score(train_input, train_target)
    print(f" {n} / {score}")

    ### 1보다 작은 정확도인 경우
    if score < 1:
        ### nScore의 값이 score보다 작은 경우 담기
        if nScore < score:
            nScore = score
            nCnt = n
print(f"nCnt = {nCnt} / nScore = {nScore}")

 ==> 출력 : nCnt = 3 / nScore = 0.9804899950518966

 

- 임의 값으로 예측하기


### 길이 50으로 무게 예측하기
pred=knr.predict([[50]])
pred

### 사용된 이웃의 인덱스 확인
dist, indexes=knr.kneighbors([pred])
dist, indexes

### 산점도로 그려보기
### 산점도 그리기
plt.scatter(train_input, train_target, c="purple", label="perch")
plt.scatter(50, pred[0], marker="^", c="green", label="pred")
plt.scatter(train_input[indexes], train_target[indexes], c = "red", label = "nei")
plt.xlabel("length")
plt.ylabel("weight")
plt.legend()
plt.title("농어 데이터")
plt.show()

 

 

- 길이 100으로 무게 예측하기


### 길이 100으로 무게 예측하기
pred2=knr.predict([[100]])
pred2

### 사용된 이웃의 인덱스 확인
dist2, indexes2=knr.kneighbors([pred2])
dist2, indexes2

### 산점도로 그려보기
### 산점도 그리기
plt.scatter(train_input, train_target, c="purple", label="perch")
plt.scatter(100, pred2[0], marker="D", c="gold", label="pred")
plt.scatter(train_input[indexes2], train_target[indexes2], c = "lightcoral", label = "nei")
plt.xlabel("length")
plt.ylabel("weight")
plt.legend()
plt.title("농어 데이터")
plt.show()

 

<KNN의 한계> 
- 가장 가까운 이웃을 이용해서 예측을 수행하는 모델이기에,
- 독립변수의 값이 기존 훈련데이터의 독립변수가 가지고 있는 범위를 벗어나는 경우에는 
- 값이 항상 동일하게 나옴(가까운 거리의 이웃이 항상 동일해짐)

따라서, 다른 회귀모델을 사용해야함

<회귀모델 종류>
- 선형회귀모델(직선 한개), 다향회귀모델(곡선), 다중회귀모델(직선 여러개), 릿지, 라쏘, 
  >>릿지,라쏘는 모델 성능이 향상된 것, 하이퍼파라메터 튜닝이 같이 들어감

  랜덤포레스트, 그레디언트부스트, 히스토그램그레디언트부스트, XGBoost, 기타 등등  >>> 회귀, 분류 둘 다 가능 / 성능 향상된 것들

- XGBoost만 별도 라이브러리고 나머지는 sklearn에 포함되어 있음
- 주로 많이 사용되는 회귀모델 : 릿지, 히스토그램그레디언트부스트, XGBoost

 

 

728x90