# 데이터 준비하기
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])
# train 데이터와 test 데이터로 분리
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)
# input 데이터를 2차원으로 변환
train_input = train_input.reshape(-1,1)
test_input = test_input.reshape(-1,1)
# n_neighbors를 3으로 하는 KNeighborsRegressor모델을 훈련
from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor(n_neighbors=3)
knr.fit(train_input, train_target)
KNeighborsRegressor(n_neighbors=3)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
KNeighborsRegressor(n_neighbors=3)
여기까지는 기존과 동일하다. 해당 모델에 길이 50cm의 모델을 입력해보자.
참고로, 2차원 리스트 형태로 [[50]]을 전달하는 이유는 아래와 같다. 사이킷런 모델에서는 입력 데이터가 2차원 배열이어야 한다. 50은 물고기 길이를 나타내며, 이를 모델에 전달하려면 (1, 1) 형태로 변환해야 한다. [[50]]은 샘플 1개와 특성 1개의 2차원 배열로, 올바른 입력 형식이며 [50]처럼 1차원 배열을 사용하면 에러가 발생한다. 따라서 reshape() 함수를 사용하거나 직접 [[값]] 형태로 작성해 전달해야 한다.
print(knr.predict([[50]]))
[1033.33333333]
새로운 데이터의 무게가 너무 낮다.
scatter plot과 kneighbors() 메서드를 활용하여 새로운 데이터의 이웃하는 데이터의 배치를 확인해보자.
import matplotlib.pyplot as plt
distances, indexes = knr.kneighbors([[50]])
plt.scatter(train_input, train_target)
plt.scatter(train_input[indexes], train_target[indexes], marker='D')
plt.scatter(50, 1033, marker='^')
plt.xlabel('lenth')
plt.ylabel('weight')
plt.show()
산점도를 확인하니
KNN회귀모델은 훈련 데이터 범위 밖의 데이터를 측정하는데 적합하지 않은 듯 하다.
선형회귀모델을 만들어 훈련시킨 후 결과를 예측해보자.
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(train_input, train_target)
# 50cm 농어 데이터 예측
lr.predict([[50]])
print(lr.predict([[50]]))
[1241.83860323]
예측이 잘 이루어 지는 것 같다.
LinearRegression객체의 coef_와 intercept_속성을 확인하고, 그래프를 그려보자.
coef_는 기울기, 계수, 가중치이며
intercept_는 y절편 값이다.
이 속성을 사용하여 선형회귀식을 나타내보면 아래와 같다.
*y = coef_ * x + intercept_*
print(lr.coef_, lr.intercept_)
[39.01714496] -709.0186449535477
두 속성을 사용하여 선형회귀모델이 찾은 직선을 그려보자.
plot()을 사용하면 (x_1,y_1)와 (x_2,y_2) 두 점을 이을 수 있다.
*plt.plot([x_1, x_2], [y_1, y_2])*
산점도와 함께 나타내보자.
# train 데이터의 scatter plot을 그린다.
plt.scatter(train_input, train_target)
# 길이가 15, 50인 두 점(데이터)를 이어서 직선을 그린다.
plt.plot([15, 50], [15*lr.coef_+lr.intercept_, 50*lr.coef_+lr.intercept_])
# 50cm 농어 데이터를 그린다.
plt.scatter(50, lr.predict([[50]]), marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
선형회귀모델이 예측을 잘 수행했음을 알 수 있다.
과소적합, 과대적합 유무를 판단하기 위해
train 세트와 test 데이터의 R^2점수를 확인한다.
print(lr.score(train_input, train_target))
print(lr.score(test_input, test_target))
0.9398463339976041 0.8247503123313559
test 세트에서의 점수가 더 낮다. 과적합이 발생한 것일까?
그렇다기에는 train 세트의 점수도 만족스럽지 않다.
직선이 아닌 데이터를 일차함수모델로 예측했기 떄문이다.
이 문제를 해결하려면 최적의 직선이 아닌 최적의 곡선을 찾아야한다.
이 경우에는 2차 방정식이 적합하며
2차 방정식의 그래프를 그리려면 '길이'를 '제곱'한 항이 input데이터에 추가되어야 한다.
column_stack() 함수와 넘파이 브로드캐스팅를 사용하여
train_input을 제곱한 배열과 train_input 두 배열을 붙인다.
test_input에도 동일한 과정을 수행한다.
train_poly = np.column_stack((train_input**2, train_input))
test_poly = np.column_stack((test_input**2, test_input))
print(train_poly.shape, test_poly.shape)
(42, 2) (14, 2)
선형회귀모델을 다시 훈련시키고 50cm 농어의 무게를 예측해보자.
2차함수의 input 데이터를 만들었을 때 처럼 50**2과 50을 입력해준다.
lr = LinearRegression()
lr.fit(train_poly, train_target)
print(lr.predict([[50**2, 50]]))
[1573.98423528]
# 계수와 절편을 확인
print(lr.coef_, lr.intercept_)
[ 1.01433211 -21.55792498] 116.05021078278259
이 모델은 다음과 같은 그래프를 학습했다.
*무게 = 1.01 * 길이^2 - 21.56 * 길이 + 116.05*
2차 함수 방정식은 비선형이나, 이를 선형 회귀로 처리하려면 아래와 같이 변수를 바꿔서 생각하면 된다.
*무게 = 1.01 * 슈퍼길이 - 21.56 * 길이 + 116.05*
이제 무게를 슈퍼길이와 길이를 사용하여 선형 관계로 표현할 수 있다.
이렇게 다항식을 사용한 선형회귀를 다항회귀라고 한다.
# 산점도와 2차방정식 그래프 그리기
# 곡선을 표현하기 위해 15에서 49까지의 정수배열을 생성
point = np.arange(15, 50)
# 훈련세트의 산점도 그리기
plt.scatter(train_input, train_target)
# 15에서 49까지의 2차방정식 그래프 그리기
plt.plot(point, 1.01*point**2 - 21.56*point + 116.05)
# 50cm 농어 데이터 표시
plt.scatter(50, lr.predict([[50**2, 50]]), marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
# 다항회귀 모델의 train데이터, test데이터 점수 확인
print(lr.score(train_poly, train_target))
print(lr.score(test_poly, test_target))
0.9706807451768623 0.9775935108325121
우수한 점수가 나오지만 과소적합이 조금 발생하는 듯 하다.
모델을 조금 더 복잡하게하여 train데이터 점수를 올려보자.
'혼자 공부하는 머신러닝 딥러닝' 카테고리의 다른 글
KNN 회귀문제 다루기 + 과소적합문제 해결 (0) | 2024.12.11 |
---|---|
데이터 전처리 (2) | 2024.12.09 |
훈련 세트와 테스트 세트 추출하기 (0) | 2024.12.03 |
사이킷런 KNN모델로 데이터 분류하기 (0) | 2024.11.27 |