□ K 최근접 이웃 회귀(K-NN Regression)
○ K-최근접 이웃 회귀모델은 분류와 동일하게 가장먼저가까운 k개의 이웃을 찾음.
○ 그다음 이웃샘플의 타깃값을 평균하여 샘플의 예측값으로 사용.
○ 사이킷런은 회귀모델의 점수로 R^2 즉 결정계수 값을 반환.
○ 이 값은 1에 가까울수록 좋으며 정량적인 평가르 하고싶다면 사이킷런에서 제공하는 다른 평가 도구를 사용할 수 있음.
□ 선형 회귀(LinearRegression)
○ 기본개념 : 평균(기대값)으로 돌아간다.
○ 즉, 평균값에 가까워지려는 경향을 의미하는게 회귀임.
○ 널리 사용되는 대표적인 회귀 알고리즘.
○ 선형이란 말에서 짐작할 수 있듯이 특성이 하나인 경우 어떤 직선을 학습하는 알고리즘.
○ 특성을 가장 잘 나타낼 수 있는 직선을 찾아야함.
○ 특성과 타깃사이의 관계를 잘 나타내는 선형방정식을 찾음.
→ *특성이 하나면 직선방정식
○ 선형 회귀가 찾은 특성과 타깃사이의 관계는 선형방정식의 계수 또는 가중치에 저장됨.
□ 상황 : 농어 물고기의 길이와 무게 데이터를 학습 후 신규 농어 길이에 따른 무게를 예측해보자
○ 라이브러리 및 데이터 저장
#라이브러리 호출
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]
)
○ 시각화 : 산점도
#시각화 : 산점도
import matplotlib.pyplot as plt
plt.scatter(perch_length,perch_weight)
plt.xlabel("length")
plt.ylabel("weight")
plt.show()
○ 트레이닝/테스트 셋 나누기
#트레이닝/테스트 셋 나누기
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(perch_length, perch_weight, random_state=42)
print(f"train_input:\n{train_input.ndim}")
print(f"train_input:\n{train_input.shape}")
print(f"train_input:\n{train_input[:5]}")
print(f"train_input:\n{test_input.ndim}")
print(f"test_input:\n{test_input.shape}")
print(f"test_input:\n{test_input[:5]}")
print("\n1차원 배열인 것을 2차원배열로 전환해야함")
○ 사이킷런의 train_test_split() 함수사용 후 학습을 위해 각 세트는 2차원 배열형태를 가져야함
train_input = train_input.reshape(-1,1) #-1을 지정하면 나머지 원소개수로 모두채우라는 의미임
test_input = test_input.reshape(-1,1)
print(f"train_input:\n{train_input.ndim}")
print(f"train_input:\n{train_input.shape}")
print(f"train_input:\n{train_input[:5]}")
print(f"train_input:\n{test_input.ndim}")
print(f"test_input:\n{test_input.shape}")
print(f"test_input:\n{test_input[:5]}")
※ 분류에서는 정확도에 초점을 맞췄다면, 회귀는 정확한 숫자를 맞추는 것이 불가능.
※ 왜냐하면 회귀에서 예측하는 값이나 타깃 모두 임의의 수치이기 때문.
※ 회귀에서는 정확도보다는 결정계수 R^2 로 모델을 평가함.
→ R^2= 1-((타깃-예측)^2 합 / (타깃-평균)^2 합)<br>
※ 0~1 범위로 1에 가까울수록 예측 타깃에 가까워진다는 의미
※ 분류에서는 standard scaling 작업에 집중했고, 그이유는 분류에서의 초점은 정확하게 분류하는 것이 목적이기 때문 For (표준점수 : Z)
※ 반면 회귀는 실제데이터와 예측값에 대한 차이를 최대한 줄이는것이 목적이기때문에 평가지수가 R^2 임
○ K최근점 이웃 회귀 모델 생성 및 학습
#모델 생성 및 훈련 : 결정계수(R^2)
from sklearn.neighbors import KNeighborsRegressor
#모델생성
knr = KNeighborsRegressor()
#모델훈련
knr.fit(train_input,train_target)
#점수 확인
print(f"점수\t:\n{knr.score(test_input,test_target)}")
○ 학습된 모델에 테스트 세트를 입력 후 예측 진행
- 예측 진행 후 mean_absolute_error를 활용해 실제값과 예측값으로 오차를 확인
from sklearn.metrics import mean_absolute_error
#테스트세트 예측
test_predict = knr.predict(test_input)
print(test_predict)
#결정계수 오차 확인
mae = mean_absolute_error(test_target, test_predict) #실제값과 예측값으로 오차확인
print(f"오차\t:\t{round(mae,2)}") #약 19g 정도의 오차가 발생함
○ 과대적합/과소적합
* 보통 훈련 세트의 점수가 조금더 높게나오는데, 그 이유는 훈련세트에서 모델을 훈련했으므로 훈련 세트에서 더 좋은 점수가 나옴
(1) 과대적합 : 훈련 점수는 좋으나 테스트 점수가 굉장히 낮을경우
(2) 과소적합 : 테스트 점수가 훈련 점수보다 다소 높거나 두점수가 모두 낮을 경우. 이는 훈련/테스트 데이터 양이 매우 적기때문임.
print(f"트레이닝 점수\t:\t{knr.score(train_input,train_target)}")
print(f"테스트 점수\t:\t{knr.score(test_input,test_target)}")
print("테스트 점수가 높은것으로 과소적합으로 보임")
○ 과대/과소 적합 해결을 위해 우리는 K-neighbor 이웃 값을 조정하여 해결할 수 있음
- 과소적합을 해결하려면 모델을 조금 더 복잡하게 만들면 됨.
- k-최근접 이웃 알고리즘으로 모델을 더 복잡하게 만드는 방법은 이웃의 개수 K를 줄이는 것임.
- k-최근접 이웃 알고리즘의 기본 k 값은 5임.
#이웃의 개수를 3으로 설정
knr.n_neighbors = 3 #지정을 안하면 기본값 5
#모델 재훈련
knr.fit(train_input,train_target)
#점수 확인
print(f"트레이닝 점수\t:\t{knr.score(train_input,train_target)}")
print(f"테스트 점수\t:\t{knr.score(test_input,test_target)}")
○ 과대/과소 적합을 해결하였으나 우리는 K최근접 이웃 회귀분석의 한계를 경험함
- 50cm 농어임에도 불구하고 1033g으로 예측됨.
- 실제중량은 더 무거움.
- 즉, 기존 학습데이터에서 벗어난 신규데이터가 입력될 경우 유의미한 예측이 불가하다는 한계에 다달음.
from sklearn.neighbors import KNeighborsRegressor
#k-최근접 이웃 회귀 모델 생성. 이웃은 기본값 5 에서 3으로 수정
knr = KNeighborsRegressor(n_neighbors=3)
#k-최근접 이웃 회귀 모델 훈련
knr.fit(train_input,train_target)
#예측 진행(길이 50cm농어)
nong_fish = np.array([[50]])
print(knr.predict(nong_fish))
○ 원인파악을 위한 산점도 시각화
import matplotlib.pyplot as plt
#50cm 농어의 이웃을 구함
distances, indexes = knr.kneighbors(nong_fish)
#산점도 그리기
plt.scatter(train_input, train_target) #훈련세트
plt.scatter(50,1033, marker="*") #신규농어 50cm로 예측했을때 1033g으로 나왔기때문에
plt.scatter(train_input[indexes], train_target[indexes], marker="D") #이웃샘플 표시
plt.xlabel("length")
plt.ylabel("weight")
plt.show()
print(f"신규농어의 이웃 평균 무게 : {np.mean(train_target[indexes])}")
※ 시각화 그래프만으로 봤을때 길이가 커질수록 농어의 무게 또한 증가되는 것을 확인할 수 있음.
※ but 50cm 농어에서 가장 가까운것은 45cm 근방이기 때문에 k-최근접 이웃 알고리즘은 샘플들의 무게를 평균하기에 50cm에 대한 길이를 1033으로 예측했던것임.
※ K-최근접 이웃을 통한 예측 한계를 해결하려면 다른 알고리즘을 사용해야함.
○ 예측 모델인 Linear Regression 모델 생성 및 학습
#LinearRegression
from sklearn.linear_model import LinearRegression
lr = LinearRegression() #객체생성
lr.fit(train_input, train_target) #훈련학습
lr_nong = lr.predict([[50]]) #예측 : 길이 50인 농어
print(lr_nong)
※ 예측과정
- 하나의 예측을 위한 선형회귀를 위해 직선이 필요하며 하나의 직선을 그리려면 기울기와 절편이 필요함.
- y=(a * x) +b
- a=기울기, b=절편
→ 절편 : y축에 처음으로 지나는 지점
- 선형회귀를 시행할때 기울기와 y절편이 중요함. 왜냐하면 기울기와 y절편을 바탕으로 회귀직선(추세선)을 그을 수 가 있는데 이때, 회귀직선(기존데이터 바탕으로 만들어진선)을 바탕으로 신규데이터에 대한 예측값을 산정할 수 있기 떄문임.
- coef_(기울기)와 intercept_(절편)를 머신러닝 알고리즘이 찾은 값이라는 의미로 모델 파라미터라고 부름.
print(f"기울기(회계계수 또는 가중치) :\t{lr.coef_}")
print(f"절편 :\t{lr.intercept_}")
○ 1차 다항식 + 산점도 시각화
#농어 길이 15~50까지 직선으로 그리기.
plt.scatter(train_input,train_target)
#15~50까지 1차 방정식 그래프 그리기 : 기울기 & 절편
plt.plot([15,50], [15*lr.coef_ + lr.intercept_, 50*lr.coef_ + lr.intercept_])
#50cm 농어 데이터
plt.scatter(50,1241.8, marker="^")
plt.xlabel("length")
plt.ylabel("weight")
plt.show()
print(lr.score(train_input, train_target)) #훈련 세트
print(lr.score(test_input, test_target)) #테스트 세트
※ 1차 직선을 적용해보니 위와 같이 20이하의 데이터가 들어오면 - 값을 예측하게됨. 이는 무게가 -인데 옳지않음. 따라서 1차 직선이 아닌 2차 다항식을 적용하는 것곽 같은 회귀차수를 높이는 절차가 필요함.
○ 2차 다항식을 위한 전처리 : y = (a*x^2) + (b*x) + c
- a, b 는 기울기를 의미하고, c는 y 절편을 의미
- 위 3개는 선행작업에서 진행함
train_poly = np.column_stack((train_input ** 2, train_input))
test_poly = np.column_stack((test_input ** 2, test_input))
print(train_poly.shape)
print(test_poly.shape)
○ 2차 다항식으로 전처리한 데이터 학습 및 회귀계수(기울기), y절편 구하기
#객체생성
lr = LinearRegression()
#학습
lr.fit(train_poly, train_target)
#예측
print(lr.predict([[50**2,50]]))
print(f"기울기(회귀계수 또는 가중치) :\t{lr.coef_}")
print(f"절편 :\t{lr.intercept_}")
○ 무게 = 1.01 * 길이^2 - 21.6 * 길이 + 116.05 를 의미하며 이를 2차 다항식 + 산점도 시각화
point = np.arange(15,50)
plt.scatter(train_input,train_target)
plt.plot(point, (1.01*point**2 - 21.6*point) + 116.05) #2차다항식을 바탕으로
plt.scatter(50,1574,marker="^")
plt.xlabel("length")
plt.ylabel("weight")
plt.show()
'Python > 머신러닝+딥러닝 Ⅰ' 카테고리의 다른 글
확률적경사하강법 (1) | 2024.03.22 |
---|---|
Logistic_KNN (0) | 2024.03.22 |
규제(L1, L2)와 Ridge, Lasso (0) | 2024.03.15 |
Multiple Regression(다중회귀) (0) | 2024.03.15 |
K-Nearest Neighbor : K-NN 알고리즘 (3) | 2024.03.12 |