본문 바로가기
Study/혼자 공부하는 머신러닝

혼자 공부하는 머신러닝 + 딥러닝 - 회귀분석(2)

by Wanooky 2022. 3. 9.

첫번째 파트에서는 k-최근접 이웃 회귀에 대해서 알아봤다. 결정계수, 과대 적합과 과소 적합에 대해서 알아봤다.

 

이제는 앞에서 만든 모델로 예측을 해보겠다.

길이가 50인 물고기의 무게를 예측해보려고 한다.

print(knr.predict([[50]]))

[1033.33333333]

이와 같이 예측을 했는데, 실제로는 더 많이 나온다고 한다.

 

길이가 50인 물고기들의 이웃들을 봐보자.

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('length')
plt.ylabel('weight')
plt.show()

산점도를 그려보면, 50 이상의 어떤 값을 넣어도 저 세개의 값의 평균을 무게로 측정한다.

print(np.mean(train_target[indexes]))

1033.3333333333333

기존의 k-최근접 이웃 회귀로는 한계가 있음을 확인했다. 이제는 선형 회귀를 도입해서 문제를 풀어보자.

 

내가 알고 있는 선형회귀분석은 직선 혹은 곡선의 형태로 예측하는 것이다.

선형 회귀를 하기 위해서는 sklearn.linear_model 패키지의 LinearRegression 클래스를 이용하는 것이다.

사이킷런의 모델 클래스들은 매서드 이름의 모두 동일하다.

import sklearn.linear_model import LinearRegression
lr = LinearRegression()

lr.fit(train_input, train_target)

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

[1241.83860323]

기본적으로 선형 회귀식은 y=ax + b의 꼴을 띈다.

a와 b를 알아보려면 lr 객체의 coef_ 와 intercept_ 속성에 저장되어 있다.

#기울기와 절편
print(lr.coef_, lr.intercept_)

[39.01714496] -709.0186449535477

그러면 산점도와 직선을 함께 그려보자.

plt.scatter(train_input, train_target)

plt.plot([15,50], [15*lr.coef_+lr.intercept_, 50*lr.coef_+lr.intercept_])

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

lr.score(train_input, train_target)
lr.score(test_input, test_target)

0.939846333997604
0.8247503123313558

둘다 점수가 낮아 과소적합되었다고 볼 수 있다. 애초에 직선 자체가 weight가 마이너스 값이 나오기 때문에 차수를 늘려서 곡선으로 만든다. 이를 다항회귀라고 한다.

 

 

다항회귀를 하기 위해서는 제곱항을 만들어주어야 한다.

앞에서 사용한 column_stack() 함수를 사용하여 제곱값 열을 또 만든다.

 

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**2, 50]]))


[1573.98423528]

print(lr.coef_, lr.intercept_)

[  1.01433211 -21.55792498] 116.0502107827827
즉 1.02*길이 제곱 - 21.5 * 길이 + 116.05 의 회귀 식을 얻는다.
 
산점도를 그려보자.
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(50, 1574, marker = '^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

아주 잘 적합되었는지 결정 계수도 출력해보자.

print(lr.score(train_poly, train_target))
print(lr.score(test_poly, test_target))



0.9706807451768623
0.9775935108325122

비슷하지만, 약간의 과소적합이 남아있다. 이를 해결하려면 어떻게 할까?