회귀 알고리즘과 모델 규제

yiseonline·2023년 10월 10일
0

aistudy

목록 보기
5/8
post-thumbnail

k-최근접 이웃 회귀

지도 학습 알고리즘은 분류회귀로 나뉜다.

분류 = 샘플을 몇 개의 클래스 중 하나로 분류하는 것
회귀 = 임의의 어떤 숫자를 예측하는 것
ㄴ ex) 내년도 경제 성장률 예측, 배달 도착 시간 예측

k-최근접 이웃 알고리즘이 회귀에도 작동을 한다 !
ㄴ 예측하려는 샘플에 가장 가까운 샘플 k개 선택 -> 샘플들의 클래스를 확인하여 다수 클래스를 새로운 샘플의 클래스로 예측 ->

k-최근접 이웃회귀 = 예측하려는 샘플에 가장 가까운 샘플 k개를 선택하지만 회귀이기 때문에 이웃한 샘플의 타깃은 클래스가 아니라 수치다 !

<훈련 데이터인 농어 길이와 무게 준비>

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)

근데 훈련세트는 2차원 배열이어야 한다 !! -> perch_length가 1차원 배열이기 때문에 이를 나눈 train_inputtest_input도 1차원 배열이다

=> 이 1차원 배열을 1개의 열이 있는 2차원 배열로 바꿔야 한다 !!

특성이 1개기 때문에 수동으로 2차원 배열을 만드려면 reshape()메서드를 이용하면 된당
ex) (4,) -> (2,2)

test_array = np.array([1,2,3,4])
print(test_array.shape) # (4,)
test_array = test_array.reshape(2,2)
print(test_array.shape) # (2, 2)

이제 이 메서드를 사용해서 train_inputtest_input을 2차원 배열로 바꿀 건데 (42,) -> (42,1) 로 바꿔야 해서 train_input.reshape(42,1)을 써야한다.
또한, 넘파이는 배열의 크기를 자동으로 지정하는 기능도 제공해서 크기에 -1을 지정하면 나머지 원소 개수로 모두 채우라는 의미가 된다.
ㄴex) 첫번째 크기를 나머지 원소 개수로 채우고 두 번째 크기를 1로 하려면
train_input.reshape(-1,1)

<reshape() 메서드로 배열 크기 변경>

train_input = train_input.reshape(-1,1)
test_input = test_input.reshape(-1,1)
print(train_input.shape, test_input.shape)

output

(42, 1) (14, 1)

결정계수 (R^2)

<객체 생성하고 fit()메서드로 회귀 모델 훈련 후 테스트 세트 점수 확인하기>

from sklearn.neighbors import KNeighborsRegressor

knr = KNeighborsRegressor()

knr.fit(train_input, train_target)

print(knr.score(test_input, test_target))

output

0.992809406101064

ㄴ 이 점수는 결정계수이다 ! (= R^2)

R^2 = 1 - (타깃 - 예측)^2의 합 / (타깃 - 평균)^2의 합
-> 타깃의 평균 정도를 예측하는 수준이라면 결정계수는 0에 가까워지고, 예측이 타깃에 아주 가까워지면 1에 가까워진다 !!

결정계수가 얼마나 좋은지 딱 보고 아는 것은 어렵기 때문에 다른 값도 계산을 해보자 ~~ 타깃과 예측한 값 사이의 차이를 구해보면 어느 정도 예측이 벗어났는지 가늠하기 좋다 ~~

<타깃과 예측의 절댓값 오차를 평균해서 반환하기>

from sklearn.metrics import mean_absolute_error

test_prediction = knr.predict(test_input)
mae = mean_absolute_error(test_target, test_prediction)
print(mae)

output

19.157142857142862

ㄴ 예측이 평균적으로 19g 정도 타깃값과 다르다

여태까지는 훈련 세트를 사용해서 모델 훈련 후 테스트 세트로 모델을 평가했는데, 이번에는 훈련 세트를 사용해서 평가해보면 어떨까? = score()메서드에 훈련 세트를 전달해서 점수를 출력해보는 것!!

과대적합 vs 과소적합

<훈련한 모델을 사용해서 훈련 세트의 결정계수 점수 확인하기>

print(knr.score(train_input, train_target))

output

0.9698823289099254

ㄴ 앞에서 테스트 세트를 사용한 점수가 더 높다 !!

만약 훈련 세트에서는 점수가 좋았는데 테스트 세트에서 점수가 나쁘다면 ? 이를 모델이 훈련 세트에 과대적합 되었다고 한다 = 훈련 세트에만 잘 맞는 모델!

만약 훈련 세트보다 테스트 세트의 점수가 더 높거나 두 점수가 모두 낮으면 ? 이를 모델이 훈련 세트에 과소적합 되었다고 한다 = 모델이 너무 단순해서 훈련 세트에 적절히 훈련되지 않았다는 것

그럼 여태까지 했던 내 코드는 테스트세트를 사용한 점수가 더 높기 때문에 과소적합인 것이다 ~~

해결책은??
= 모델을 조금 더 복잡하게 만들장

k-최근접 이웃 알고리즘으로는 이웃의 개수 k를 줄여서 모델을 더 복잡하게 만들 수 있다. 사이킷런의 k-최근접 이웃 알고리즘의 기본 k값은 5여서 이를 3으로 낮춰보장

<이웃 개수 줄이고 훈련 후 점수 출력>

knr.n_neighbors = 3

knr.fit(train_input, train_target)
print(knr.score(train_input, train_target))

ㄴ k값을 줄였더니 결정계수 점수가 높아졌다 !!

<테스트 세트의 점수 확인하기>

print(knr.score(test_input, test_target))

output

0.9746459963987609

ㄴ 테스트 세트의 점수가 훈련 세트보다 낮아져서 과소적합 문제 해결함 !!
두 점수 차가 그렇게 크지 도 않아서 모델이 과대적합 되지도 않은 것 같다 ~~


선형 회귀

k-최근접 이웃의 한계

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)

train_input = train_input.reshape(-1,1)
test_input = test_input.reshape(-1,1)

from sklearn.neighbors import KNeighborsRegressor

knr = KNeighborsRegressor(n_neighbors = 3)
knr.fit(train_input, train_target)

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

output

[1033.33333333]

ㄴ 50cm 농어의 무게를 1033.3g으로 예측했는데 사실 이 농어의 무게는 훨씬 더 많이 나간다고 한다 !! 어디서 문제가 생긴걸까?

<훈련 세트와 50cm 농어, 농어의 최근접 이웃을 산점도에 표시하기>

import matplotlib.pyplot as plt

distances, indexes = knr.kneighbors([[50]]) # 50cm 농어의 이웃 구하기

plt.scatter(train_input, train_target) # 훈련 세트의 산점도 그리기
plt.scatter(train_input[indexes], train_target[indexes], marker = 'D') # 훈련 세트 중에서 이웃 샘플만 다시 그리기

# 50cm 농어 데이터
plt.scatter(50, 1033, marker = '^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()


ㄴ 길이가 50cm, 무게가 1033g인 농어는 초록색 삼각형으로, 그 주변의 샘플은 주황색 마름모로 표현됨 !
이 산점도를 보면 길이가 커질수록 농어의 무게가 증가하는 경향이 있는데, 50cm 농어에서 가장 가까운 것은 45cm 근방이기 때문에 k-최근접 알고리즘은 이 샘플들의 무게 평균을 구한 것이었따 !!!!

<이웃 샘플의 타깃의 평균 구해보기>

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

output

1033.3333333333333

ㄴ 일치하네... k-최근접 이웃 회귀는 가장 가까운 샘플을 찾아 타깃을 평균하기 때문에 새로운 샘플이 훈련 세트의 범위를 벗어나면 이상한 값을 예측하게 된다 ~~

선형 회귀

: 특성이 하나인 경우 데이터의 특성을 가장 잘 나타낼 수 있는 직선을 학습하는 알고리즘 !!

<선형회귀 알고리즘 구현하고 훈련 및 예측하기>

from sklearn.linear_model import LinearRegression
lr = LinearRegression()

lr.fit(train_input, train_target) # 선형 회귀 모델 훈련
print(lr.predict([[50]])) # 50cm 농어에 대해 예측

output

[1241.83860323]

ㄴ k-최근접 알고리즘과는 다르게 아주 높게 예측해뜸 !!

이 선형 회귀가 학습한 직선을 그려보고 이 값이 왜 나왔는지 알아보자 ~~

일단 직선을 그리기 위해 기울기와 절편을 알아야함 (y = ax + b)
x를 농어의 길이, y를 농어의 무게로 하자

기울기와 절편은 LinearRegression()에 coef와 intercept 속성에 저장되어있다

print(lr.coef_, lr.intercept_)

output

[39.01714496] -709.0186449535477

<농어 길이 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)) #0.939846333997604
print(lr.score(test_input, test_target)) #0.8247503123313558

ㄴ 훈련 세트와 테스트 세트의 점수가 조금 차이가 난다. 전체적으로 과소적합 되었음 !!

다항 회귀

근데 과소적합이던 뭐던 지금 그래프를 보면 뭔가가 이상하다 !

weight 쪽을 잘 보면 직선이 x축에서 0과 가까워지면서 농어의 무게가 0 이하로 내려가는 것을 볼 수 있따 !!
그리고 농어의 길이와 무게에 대한 산점도를 잘 보면 직선이 아니라 왼쪽 위로 조금 구부러진 곡선에 가까움

이렇게 되면 2차 방정식의 그래프이기 때문에 길이를 제곱한 항이 훈련 세트에 추가되어야 한당


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

train_poly를 사용하여 선형 회귀 모델을 다시 훈련해야 한당. 이때 2차 방정식 그래프를 찾기 위해 훈련 세트에 제곱항을 추가했지만, 타깃값은 그대로 사용한다는 게 중요하다.

<train_poly를 사용하여 선형 회귀 모델을 다시 훈련하기>

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

print(lr.predict([[50**2, 50]])) # [1573.98423528]

<모델이 훈련한 계수와 절편 출력하기>

print(lr.coef_, lr.intercept_)

output

[  1.01433211 -21.55792498] 116.0502107827827

ㄴ> 무게 = 1.01 길이^2 - 21.6 길이 + 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()

특성 공학과 규제

다중 회귀

: 여러 개의 특성을 사용한 선형 회귀


위에서 한개의 특성을 사용했을 때는 선형 회귀 모델이 학습하는 것이 직선이였는데, 2개의 특성을 사용하면 선형회귀는 평면을 학습한다 -> 선형 회귀 방정식 타깃 = a * 특성1 + b * 특성2 + 절편이 평면이 됨

이번에는 농어의 길이 뿐만 아니라 농어의 높이와 두께도 함께 사용해보자 !!
3개의 특성을 각각 제곱해서 추가하고 여기다가 각 특성을 서로 곱해서 또 다른 특성 ( ex) 농어 길이 * 농어 높이)을 만들거임 !! = 이렇게 기존 특성을 사용해서 새 특성을 뽑아내는 작업을 특성 공학이라고 함

데이터 준비

import pandas as pd
df = pd.read_csv("https://bit.ly/perch_csv_data")
perch_full = df.to_numpy() #to_numpy() = 넘파이 배열로 바꿔주는 메소드
print(perch_full)

output

<타깃 데이터 준비>

import numpy as np

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

<perch_full과 perch_weight를 훈련 세트와 테스트 세트로 나누기>

from sklearn.model_selection import train_test_split

train_input, test_input, train_target, test_target = train_test_split(perch_full, perch_weight, random_state = 42)

사이킷런의 변환기

사이킷런은 특성을 만들거나 전처리하기 위한 다양한 클래스를 제공하는데 이런 클래스를 변환기라고 부른다!

<객체 만들고 메서드 호출>

from sklearn.preprocessing import PolynomialFeatures

poly = PolynomialFeatures()
poly.fit([[2,3]]) # 새롭게 만들 특성 조합을 찾음
print(poly.transform([[2,3]])) # 실제로 데이터를 변환

output

[[1. 2. 3. 4. 6. 9.]]

-> 변환기는 입력 데이터를 변환하는데 타깃 데이터가 필요하지 않아서 fit()메서드에 입력 데이터만 전달 했당 => 여기에선 2개의 특성을 가진 샘플 [2,3]이 6개의 특성을 가진 샘플로 바뀌었음

PolynomialFeatures()는 기본적으로 각 특성을 제곱한 항을 추가하고 특성끼리 서로 곱한 항을 추가함 그래서 2와 3을 제곱한 4와 9가 추가되었고 2와 3을 곱한 6이 추가된 것!! -> 그럼 1은 왜 추가 되었냐
무게 = a * 길이 + b * 높이 + c * 두께 + d * 1
여기서 절편 = 항상 값이 1인 특성과 곱해지는 계수
특성은 (길이, 높이, 두께, 1)이 됨. 사이킷런의 선형 모델은 자동으로 절편을 추가하므로 굳이 이렇게 특성을 만들 필요가 없어서 include_bias = False로 지정하여 다시 특성을 변환하면

from sklearn.preprocessing import PolynomialFeatures

poly = PolynomialFeatures(include_bias = False)
poly.fit([[2,3]])
print(poly.transform([[2,3]]))

output

[[2. 3. 4. 6. 9.]]

ㄴ 절편을 위한 항이 제고되고 특성의 제곱과 특성끼리 곱한 항만 추가되었음

<train_input을 변환한 데이터 train_poly에 저장하고 배열 크기 확인>

poly = PolynomialFeatures(include_bias = False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
print(train_poly.shape)

output

(42, 9)

get_feature_names_out() 메서드는 호출하면 특성이 어떻게 만들어졌는지 확인하는 아주 좋은 PolynomialFeatures 클래스의 방법이다

poly.get_feature_names_out()

output

array(['x0', 'x1', 'x2', 'x0^2', 'x0 x1', 'x0 x2', 'x1^2', 'x1 x2',
       'x2^2'], dtype=object)

x0은 첫 번째 특성, x0^2는 첫 번째 특성의 제곱, x0 x1은 첫 번째 특성과 두 번째 특성의 곱

<테스트 세트 변환>

test_poly = poly.transform(test_input)

다중 회귀 모델 훈련하기

<LinearRegrssion클래스 임포트 하고 train_poly를 사용해서 모델 훈련시키기>

from sklearn.linear_model import LinearRegression

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

output

0.9903183436982125

ㄴ 아주 높은 점수당 !!

<테스트 세트에 대한 점수 확인>

print(lr.score(test_poly, test_target))

output

0.9714559911594111

ㄴ 테스트 세트에 대한 점수는 높아지지 않았지만 과소적합 문제는 해결하였다

<특성 더 추가해서 만들기>

poly = PolynomialFeatures(degree = 5, include_bias = False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input)
print(train_poly.shape)

output

(42, 55)

ㄴ train_poly 배열의 열의 개수가 특성의 개수여서 만들어진 특성의 개수가55개나 된다 ㄷㄷ

<이 데이터로 선형 회귀 모델 다시 훈련>

lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))

output

0.9999999999996433

ㄴ 거의 완벽하다.. 점수가 ㅎㅎ

<테스트 세트에 대한 점수 출력하기>

print(lr.score(test_poly, test_target))

output

-144.40579436844948

아주 큰 음수가 나온 이유!
ㄴ 특성의 개수를 크게 늘리면 선형 모델은 매우 강력해져서 훈련 세트에 대해 거의 완벽하게 학습할 수 있지만 이런 애들은 훈련 세트에 너무 과대적합 되기 때문에 테스트 세트에서는 형편없는 점수를 나타냄

=> 특성을 줄여야 한다 ~~

규제

: 머신러닝 모델이 훈련 세트를 넘 과도하게 학습하지 못하도록 하는 것 (= 과대적합 되지 않도록!!)

선형 회귀 모델에서는 특성에 곱해지는 계수의 크기를 작게 만드는 일

근데 특성의 스케일이 정규화 되지 않으면 계수 값도 차이가 나기 때문에 규제를 적용하기 전에 먼저 정규화를 해야한당. 그 전에는 표준점수로 바꾸었지만 이번에는 StrandardScaler를 사용해보장

<StrandardScaler 클래스를 사용하기>

from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
ss.fit(train_poly)
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)

ㄴ StrandardScaler클래스의 객체 ss를 초기화 한 후 PolynomialFeatures 클래스로 만든 train_poly를 사용해서 객체 훈련하고 훈련세트로 학습한 변환기를 사용해서 테스트 세트까지 변환해줌

선형 회귀 모델에 규제를 추가한 모델을 릿지라쏘라고 부른다.
릿지는 계수를 제곱한 값을 기준으로 규제를 적용하고
라쏘는 계수의 절댓값을 기준으로 규제를 적용함 !

릿지 회귀

<train_scaled 데이터로 릿지 모델 훈련하기>

from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target))

output

0.9896101671037343

<테스트 세트에 대한 점수 확인하기>

print(ridge.score(test_scaled, test_target))

output

0.9790693977615387

ㄴ 테스트 점수가 정상으로 돌아왔따!!

릿지와 라쏘 모델을 사용할 때 모델 객체를 만들 때 alpha라는 값으로 규제의 양을 임의로 조절할 수 있다. alpha값이 커지면 규제 강도가 세지므로 계수 값을 줄이고, 조금 더 과소적합 되도록 유도함. alpha값이 작으면 계수를 줄이는 역할이 줄어들고 과대적합 될 가능성이 커집니다 !

  • 그럼 적절한 alpha 값을 어떻게 찾을까? => alpha 값에 대한 결정계수 (R^2) 값의 그래프를 그리면 된다 (훈련 세트와 테스트 세트의 점수가 가장 가까운 지점이 최적의 alpha값이 된다)

<matplotlib 임포트 하고 alpha 값 바꿀때마다 score() 메서드의 결과를 저장할 리스트 만들기>

import matplotlib.pyplot as plt

train_score=[]
test_score=[]

<alpha 값 0.001에서 100까지 10배씩 늘려서 릿지 회귀모델 훈련 후 훈련 세트와 테스트 세트 점수를 리스트에 저장하기>

alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
  ridge = Ridge(alpha=alpha)
  ridge.fit(train_scaled, train_target)
  train_score.append(ridge.score(train_scaled, train_target))
  test_score.append(ridge.score(test_scaled, test_target))

ㄴ 0.001 부터 10배씩 늘렸기 때문에 그래프가 왼쪽이 매우 촘촘할 것이다 !! 동일한 간격으로 나타내기 위해서는 로그함수로 바꾸어서 지수로 표현해야함 (0.001 = -3, 0.01 = -2)

plt.plot(np.log10(alpha_list),train_score)
plt.plot(np.log10(alpha_list),test_score)
plt.xlabel('alpha')
plt.ylabel('R^2')
plt.show()


ㄴ 파랑색이 훈련 세트, 주황색이 테스트 세트다
그래프의 왼쪽을 보면 훈련세트랑은 아주 잘 맞는데 테스트 세트랑은 잘 안맞음 (=과대적합) 하지만 오른 쪽을 보면 훈련 세트와 테스트 세트의 점수가 모두 낮아짐 (=과소적합)
=> 적절한 알파값은 -1 (0.1)이다 ~~ 0.1로 알파값을 지정해서 최종 모델을 훈련하장

ridge = Ridge(alpha = 0.1)
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target))
print(ridge.score(test_scaled, test_target))

output

0.9903815817570367
0.9827976465386928

ㄴ 비슷하게 높고 과대적합과 과소 적합 사이에서 균형을 맞춘다 ~~

라쏘 회귀

라쏘 회귀는 릿지 회귀와 비슷함. Ridge 클래스를 Lasso 클래스로 바꾸면 끝 !!

from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target)) #0.989789897208096

ㄴ 과대적합을 잘 억제 했음

<테스트 세트 점수 확인>

print(lasso.score(test_scaled, test_target)) #0.9800593698421883

테스트 세트 점수도 좋다 !! 라쏘 모델도 alpha로 규제 강도 조절이 가능하다

<alpha 값 바꾸어 가며 훈련 세트와 테스트 세트 간 점수 계산>

train_score=[]
test_score=[]
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
  lasso = Lasso(alpha = alpha, max_iter = 10000) #lasso 모델 만들기
  lasso.fit(train_scaled, train_target) # lasso 모델 훈련하기
  train_score.append(lasso.score(train_scaled, train_target)) # 훈련 점수와 테스트 점수 저장하기
  test_score.append(lasso.score(test_scaled, test_target))

<train_score와 test_score 리스트를 사용해서 그래프 그리기>

plt.plot(np.log10(alpha_list),train_score)
plt.plot(np.log10(alpha_list),test_score)
plt.xlabel('alpha')
plt.ylabel('R^2')
plt.show()


ㄴ 파랑색이 훈련 세트 그래프, 주황색이 테스트 세트 그래프이다
그래프 왼쪽은 과대적합, 오른쪽으로 갈 수록 훈련 세트와 테스트 세트의 점수가 좁혀지면서 가장 오른쪽은 아주 크게 점수가 떨어짐 (과소적합)
=> 최적의 alpha 값은 1, 10^1 = 10이다

<다시 모델 훈련하기>

lasso = Lasso(alpha=10)
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))

output

0.9888067471131867
0.9824470598706695

0개의 댓글