선형 회귀

Jaeseok Han·2024년 4월 16일

머신러닝&딥러닝

목록 보기
6/22

k최근접 이웃 한계

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

# 훈련 세트와 테스트 세트 분류
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)

# 2차원 배열
train_input = train_input.reshape(-1, 1)
test_input = test_input.reshape(-1, 1)

# 최근접 이웃 3으로설정
from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor()
knr.neighbors = 3
knr.fit(train_input, train_target)

# 길이 50 예측
print(knr.predict([[50]]))
# 출력 [1033.33333333]

import matplotlib.pyplot as plt

# 길이 50 이웃 계산
distances, indexes = knr.kneighbors([[50]])

# 훈련세트 산점도 표시
plt.scatter(train_input, train_target)

# 50의 이웃 산점도 표시
plt.scatter(train_input[indexes], train_target[indexes], marker='D')

# 50과 예측된 타깃값을 산점도 표시
plt.scatter([[50]], knr.predict([[50]]), marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

k-최근접 이웃을 사용하면 가장 가까운 샘플을 찾아 타깃을 평균값으로 하기때문에 훈련세트 밖의 범위에서 길이가 아무리 커지더라도 무게가 커지지 않게된다.

print(knr.predict([[1000]]))
# 출력 [1033.33333333]

길이는 10배가 늘었지만 예측된 무게는 1033.33으로 동일

훈련 세트의 범위 밖에서도 길이에 따른 무게가 증가된 값으로 예측이 필요하다. 이 부분을 선형회귀로 해결이 가능하다.

선형 회귀

LinearRegression

사이킷런은 sklearn.linear_model패키지 아래에 LinearRegression클래스로 선형 회귀 알고리즘이 구현되어있다.

from sklearn.linear_model import LinearRegression
lr = LinearRegression()

# 선형 회귀 모델을 훈련
lr.fit(train_input, train_target)

# 길이 50 예측
print(lr.predict([[50]]))
# 출력 [1241.83860323]

# 선형 회귀로 학습된 직선의 기울기와 절편
print(lr.coef_, lr.intercept_)
# 출력 [39.01714496] -709.0186449535477

# 1차 방정식 그래프
plt.scatter(train_input, train_target)
plt.plot([15, 50], [15 * lr.coef_ + lr.intercept_, 50 * lr.coef_ + lr.intercept_])
# 길이 50 산점도 표시
plt.scatter([[50]], lr.predict([[50]]), marker='^')
plt.xlabel('length')
plt.ylabel('length')
plt.show()

# 훈련 세트와 테스트 세트 절대계수비교
print(lr.score(train_input, train_target))
# 출력 0.939846333997604
print(lr.score(test_input, test_target))
# 출력 0.8247503123313558

문제점

  • 훈련 세트와 테스트 세트의 점수가 차이가 나며 점수자체가 높지않다.
  • 그래프를 보면 음수의 무게도 가능한 형태를 띄고 있다.

따라서 직선 선형 그래프는 적합하지 않음

다항 회귀

산점도를 확인해보면 진석보다는 구부러진 곡선에 가까운 형태로 분포되어있다. 최적의 곡선이 해당 데이터에 맞는 알고리즘으로 생각해 볼 수 있다.

2차 방정식

## 2차 방정식
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)

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.0502107827827

[참고]일차방정식과 이차방정식

해당 모델은 2차방정식 그래프를 학습하였다.

무게=1.01×221.6×길이+116.05무게 = 1.01 \times 길이^2 - 21.6 \times 길이 + 116.05

이러 방정식을 다항식이라고 하며, 다항식을 사용한 선형회귀를 다항 회귀라고 한다.


# 구간별 직선을 그리기 위해 15~49 정수 배열 생성
point = np.arange(15, 50)

# 훈련 세트 산점도
plt.scatter(train_input, train_target)

# 15~49까지 2차 방정식 그래프
plt.plot(point, lr.coef_[0] * point ** 2 + lr.coef_[1] * point + lr.intercept_)

# 길이 50의 데이터
plt.scatter(50, lr.predict([[50 ** 2, 50]]), marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

# 훈련 세트와 테스트 세트 결정계수 점수 평가
print(lr.score(train_poly, train_target))
# 출력 0.9706807451768623
print(lr.score(test_poly, test_target))
# 출력 0.9775935108325122

점수는 높아졌으나 아직 테스트 세트의 점수가 조금 더 높다.(과소적합)

0개의 댓글