선릉역 1번 출구

3-2 본문

Computer/AI

3-2

choideu 2021. 7. 8. 07:49

K-최근접 이웃 회귀 알고리즘은 한계가 존재한다.

저번 3-1에서 다뤘던 똑같은 데이터를 가지고 한계점을 설명해보겠다.

import numpy as np

perch_length = np.array([8.413.715.016.217.418.018.719.019.620.021.0,
       21.021.021.322.022.022.022.022.022.522.522.7,
       23.023.524.024.024.625.025.626.527.327.527.5,
       27.528.028.730.032.834.535.036.536.037.037.0,
       39.039.039.040.040.040.040.042.043.043.043.5,
       44.0])
perch_weight = np.array([5.932.040.051.570.0100.078.080.085.085.0110.0,
       115.0125.0130.0120.0120.0130.0135.0110.0130.0,
       150.0145.0150.0170.0225.0145.0188.0180.0197.0,
       218.0300.0260.0265.0250.0250.0300.0320.0514.0,
       556.0840.0685.0700.0700.0690.0900.0650.0820.0,
       850.0900.01015.0820.01100.01000.01100.01000.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)

train_input = train_input.reshape(-11)
test_input = test_input.reshape(-11)

from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor(n_neighbors=3)
knr.fit(train_input, train_target)

print(knr.predict([[50]])) //1033으로 예측
print(knr.predict([[100]])) //1033으로 예측

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(501033, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

K-최근접 이웃 회귀의 문제점은 바로 새로운 샘플이 훈련 세트의 범위를 벗어나면 엉뚱한 값을 예측한다.

length의 길이가 45 이상만 되어도 그것과 가까운 이웃은 변하지 않기 때문에 50, 100을 length값으로 가지는 농어 모두 weight값이 1033g으로 예측된 것이다.

 

이를 해결할 수 있는 알고리즘은 선형 회귀(linear regression)알고리즘으로 특성이 하나인 경우 어떤 직선을 학습하는 알고리즘이다. 특성을 잘 표현하는 직선을 찾는 것이 핵심이다.

위키백과

import numpy as np

perch_length = np.array([8.413.715.016.217.418.018.719.019.620.021.0,
       21.021.021.322.022.022.022.022.022.522.522.7,
       23.023.524.024.024.625.025.626.527.327.527.5,
       27.528.028.730.032.834.535.036.536.037.037.0,
       39.039.039.040.040.040.040.042.043.043.043.5,
       44.0])
perch_weight = np.array([5.932.040.051.570.0100.078.080.085.085.0110.0,
       115.0125.0130.0120.0120.0130.0135.0110.0130.0,
       150.0145.0150.0170.0225.0145.0188.0180.0197.0,
       218.0300.0260.0265.0250.0250.0300.0320.0514.0,
       556.0840.0685.0700.0700.0690.0900.0650.0820.0,
       850.0900.01015.0820.01100.01000.01100.01000.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)

train_input = train_input.reshape(-11)
test_input = test_input.reshape(-11)

from sklearn.linear_model import LinearRegression
lr = LinearRegression()

lr.fit(train_input, train_target)

print(lr.predict([[50]])) // [1241.83860323]

선형 회귀 알고리즘 적용 결과 length가 50인 농어의 weight가 1241로 예측되었다.

 

중학교 수학에서 배웠듯이 하나의 직선을 그리기 위해서는 1차 방정식이 필요하다.

y = ax+b에서 x가 농어의 길이, y가 농어의 무게라면 linearRegression은 데이터에 가장 잘 맞는 a, b를 찾는 것이다.

LinearRegression 클래스가 찾는 a, b는 lr 객체의 coef_, intercept_속성에 저장되어있다.

 

*coef_, intercept_는 머신러닝 알고리즘이 찾은 값이라는 의미로 모델 파라미터라고 부른다. 이렇게 최적의 모델 파라미터를 찾는 것을 모델 기반 학습이라고 하고 k-최근접 이웃처럼 모델 파라미터가 없고 훈련 세트를 저장하는 것이 훈련의 전부인 것을 사례 기반 학습이라고 한다.

import matplotlib.pyplot as plt

plt.scatter(train_input, train_target)

plt.plot([1550], [15*lr.coef_+lr.intercept_, 50*lr.coef_+lr.intercept_]) //직선 그리기

plt.scatter(501241.8, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

이 직선이 선형 회귀 알고리즘이 훈련 데이터셋에서 찾은 최적의 직선이다.

 

print(lr.score(train_input, train_target)) // 0.9398463339976039
print(lr.score(test_input, test_target)) //  0.8247503123313558

score()로 확인한 결과 둘의 점수가 너무 낮아 과소적합돼있다고 볼 수 있다. 선형 회귀 알고리즘에도 문제가 있는데 바로 직선이 가리키는 값이다. 위의 그래프를 보면 length가 15 이하일 경우 weight가 음수가 되는 것을 알 수 있다. 

농어의 무게가 0g 이하로 내려간다는 것은 현실세계에서 있을 수 없는 일이다.

 

그래서 다항회귀(polynomial regression)를 사용한다. 최적의 직선이 아닌 최적의 곡선을 찾는 것이다.

train_poly = np.column_stack((train_input**2, train_input))
test_poly = np.column_stack((test_input**2, test_input))

lr = LinearRegression()
lr.fit(train_poly, train_target)

print(lr.predict([[50**250]])) // [1573.98423528]

선형 회귀보다 더 높은 값을 예측함

 

point = np.arange(15,50)

plt.scatter(train_input, train_target)

plt.plot(point, 1.01*point**2 - 21.6*point+116.05)
plt.scatter(501572, marker = '^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

산점도를 그려본 결과 선형 회귀와 다르게 0 이하로 내려가지 않는다.

 

print(lr.score(train_poly, train_target)) // 0.9706807451768623
print(lr.score(test_poly, test_target)) //  0.9775935108325122

과소적합의 문제도 해결되었다.

'Computer > AI' 카테고리의 다른 글

자연어 처리-1  (0) 2021.07.10
3-3  (0) 2021.07.08
3-1  (0) 2021.07.08
2  (0) 2021.07.07
1  (0) 2021.07.07
Comments