촉촉한초코칩
[혼공머신] Ch03 본문
Ch03. 회귀 알고리즘과 모델 규제
- 지도 학습 알고리즘의 한 종류인 회귀 알고리즘 배우기
- 다양한 선형 회귀 알고리즘의 장단점 이해
03-1 k-최근접 이웃 회귀
지도 학습의 한 종류인 회귀 문제를 이해하고 k-최근접 이웃 알고리즘을 사용해 농어의 무게를 예측하는 회귀 문제 풀기
문제 : 농어의 길이, 높이, 두께를 측정한 데이터를 가지고 농어 무게 예측하기
지도학습 알고리즘
- 분류 : 샘플을 몇 개의 클래스 중 하나로 분류하는 문제
- 회귀 (Regression) : 임의의 어떤 숫자 예측하는 문제 → k-최근접 이웃 알고리즘이 회귀에도 작동
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차원 배열 → 2차원 배열로 바꿔야 함
농어 특성이 1개이기 때문에 수동으로 2차원 배열을 만들어야 함
#reshape() : 배열 크기 지정, 변경
#크기가 바뀐 새로운 배열을 반환할 때 지정한 크기가 원본 배열에 있는 원소의 개수와 다르면 에러 발생할 수 있다.
#-1 : 나머지 원소 개수로 모두 채우기
train_input = train_input.reshape(-1,1)
test_input = test_input.reshape(-1,1)
print(train_input.shape, test_input.shape)
결정계수 (R^2)
사이킷런에서 k-최근접 이웃 회귀 알고리즘을 구현할 클래스 : KNeighborsRegressor
from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor()
knr.fit(train_input, train_target)
print(knr.score(test_input, test_target)) #0.992 : 테스트 세트에 있는 샘플을 정확하게 분류한 개수의 비율 (정답을 맞힌 개수의 비율)
회귀는 예측하는 값이나 타깃 모두 임의의 수치이기 때문에 정확한 숫자를 맞히는 것은 거의 불가능하다.
결정계수 (Coefficient of Determination)
- 각 샘플의 타깃과 예측한 값의 차이를 제곱하여 더한다.
- 타깃과 타깃 평균의 차이를 제곱하여 더한 값으로 나눈다.
- 만약 타깃의 평균 정도를 예측하는 수준이라면 R^2는 0에 가까워지고, 예측이 타깃에 가까워지면 1에 가까운 값이 된다.
→ 이 값은 1에 가까울 수록 좋다.
타깃과 예측한 값 사이의 차이를 구해 보면 어느 정도 예측이 벗어났는지 가늠할 수 있다.
#mean_absolute_error() : 타깃과 예측의 절댓값 오차를 평균하여 반환
from sklearn.metrics import mean_absolute_error
#테스트 세트에 대한 예측 만들기
test_prediction = knr.predict(test_input)
#테스트 세트에 대한 평균 절댓값 오차 계산
mae = mean_absolute_error(test_target, test_prediction)
print(mae) #19.157142857142862
→ 결과에서 예측이 평균적으로 19g 정도 타깃값과 다르다는 뜻
훈련 세트를 사용해 평가해본다.
과대적합 vs 과소적합
print(knr.score(train_input, train_target)) #0.9698823289099254
모델을 훈련 세트와 테스트 세트에서 평가하면 보통 훈련 세트의 점수가 조금 더 높게 나온다. (훈련 세트에서 모델을 훈련했기 때문)
과대적합 (Overfiting) : 훈련 세트에서 점수가 좋았는데 테스트 점수에서 점수가 나쁠 때
테스트 세트와 새로움 샘플에 대한 예측을 만들 때 잘 동작하지 않게 된다.
과소적합 (Underfiting) : 훈련 세트보다 테스트 세트의 점수가 높거나 두 점수가 모드 낮을 때
모델이 너무 단순해서 훈련 세트에 적절히 훈련되지 않은 경우, 훈련세트와 테스트 세트의 크기가 매우 작을 경우 발생
k-최근접 이웃 회귀로 평가한 훈련 세트와 테스트 세트 점수의 경우 훈련 세트의 점수가 낮게 나왔으므로 과소적합이다.
해결방법 : 훈련 세트에 더 잘 맞게 모델을 복잡하게 만들기 → 이웃의 개수 k를 줄인다.
* 이웃의 개수를 줄이면 훈련 세트에 있는 국지적인 패턴에 민감해지고, 이웃의 개수를 늘리면 데이터 전반에 있는 일반적인 패턴을 따르게 된다.
#이웃 개수 설정
knr.n_neighbors = 3
#모델 다시 훈련
knr.fit(train_input, train_target)
print(knr.score(train_input, train_target)) #0.9804899950518966
print(knr.score(test_input, test_target)) #0.9746459963987609
정리 [회귀 문제 다루기]
- 문제 : 농어의 높이, 길이 등의 수치로 무게 예측하기 → 회귀 문제 (임의의 수치를 예측하는 문제)
- k-최근접 이웃 회귀 모델
- 가장 먼저 가까운 k개의 이웃을 찾는다.
- 이웃 샘플의 타깃값을 평균하여 샘플의 예측값으로 사용한다. - 사이킷런의 회귀 모델 : R^2, 결정계수 값 반환 (1에 가까울수록 좋다.)
정량적인 평가를 하고 싶다면 사이킷런에서 제공하는 다른 평가 도구 사용 가능 ex) 절댓값 오차 - 모델 훈련 후 훈련 세트와 테스트 세트에 대한 평가 점수를 구한다.
- 훈련↔테스트 세트의 점수 차이가 크면 좋지 않다.
- 일반적으로 훈련 세트의 점수가 테스트 세트보다 조금 더 높다.
과대적합 : 테스트 세트의 점수가 너무 낮아 모델이 훈련 세트에 과도하게 맞춘 것 → 모델을 더 복잡하게 만들어야 함 (k값 줄이기)
과소적합 : 테스트 세트 점수가 너무 높거나 두 점수가 모두 낮을 때
03-2 선형 회귀
k-최근접 이웃 회귀와 선형 회귀 알고리즘의 차이를 이해하고 사이킷런을 사용해 여러 가지 선형 회귀 모델 만들기
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])
#테스트를 훈련/테스트 세트로 나누고, 특성 데이터는 2차원 배열로 변환한다.
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)
#최근접 이웃 개수를 3으로 하는 모델 훈련
from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor(n_neighbors=3)
#k최근접 이웃 회귀 모델 훈련
knr.fit(train_input, train_target)
#길이가 50cm인 농어의 무게 예측하기
print(knr.predict([[50]])) #[1033.33333333]
50cm 농어의 무게를 1.033g으로 예측했지만 실제로는 훨씬 더 많이 나간다고 한다.
문제점 찾기
import matplotlib.pyplot as plt
#50cm 농어의 이웃 구하기
distances, indexes = knr.kneighbors([[50]])
#훈련 세트의 산점도 그리기
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 농어에서 가장 가까운 것은 45cm 근방이기 땜누에 이 샘플들의 무게를 평균하게 된다.
따라서 새로운 샘플이 훈련 세트의 범위를 벗어나면 엉뚱한 값으로 예측하게 된다.
#100cm 농어의 이웃 구하기
distances, indexes = knr.kneighbors([[100]])
#훈련 세트의 산점도 그리기
plt.scatter(train_input, train_target)
#훈련 세트 중에서 이웃 샘플만 다시 그리기
plt.scatter(train_input[indexes], train_target[indexes], marker='D')
#100cm 농어 데이터
plt.scatter(100, 1033, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
그나마 가장 가까운 데이터의 평균값으로 무게를 구하기 때문에 농어가 아무리 커도 무게가 더이상 늘어나지 않게 된다.
* 머신러닝 모델은 시간과 환경이 변화하면서 데이터도 바뀌기 때문에 주기적으로 새로운 훈련 데이터로 모델을 다시 훈련해야 한다.
선형 회귀 (Linear Regression)
특성이 하나인 경우 어떤 직선(특성을 가장 잘 나타낼 수 있는 직선)을 학습하는 알고리즘
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
#선형 회귀 모델 훈련
lr.fit(train_input, train_target)
#50cm 농어에 대해 예측
print(lr.predict([[50]])) #[1241.83860323]
→ k-최근접 이웃 회귀보다 농어 무게를 높게 예측함
#LinearRegression 클래스가 찾은 a, b 값
print(lr.coef_, lr.intercept_)
#농어의 길이 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()
위 직선이 선형 회귀 알고리즘이 데이터셋에서 찾은 최적의 직선이다.
훈련 세트와 테스트 세트에 대한 R^2 점수 확인하기
print(lr.score(train_input, train_target)) #훈련 세트 0.939846333997604
print(lr.score(test_input, test_target)) #테스트 세트 0.8247503123313558
다항회귀 (Polynomial Regression)
- 다항 회귀 (Polynomial Regression) : 다향식을 이용한 선형 회귀
- 선형 회귀 알고리즘의 직선은 왼쪽 아래로 쭉 뻗어있는데, 직선대로 예측하면 농어의 무게가 0g이하로 내려가 현실에서는 있을 수 없는 일이 나타난다.
농어의 길이와 무게에 대한 산접도를 자세히 보면 곡선에 가까움 → 곡선 찾기
- 2차 방정식의 그래프를 그리려면 길이를 제곱한 항이 훈련 세트에 추가되어야 한다.
모델에 훈련시킬 때는 타깃값을 그대로 사용한다.
# ** : 배열에 있는 모든 원소를 제곱한다.
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)
#50cm 농어 무게 예측
print(lr.predict([[50**2, 50]])) #1573.9
#모델 훈련 계수와 절편 출력
print(lr.coef_, lr.intercept_) #[1.01433211 -21.55792498] 116.0502107827827
무게 = 1.01 * 길이^2 - 21.6 * 길이 + 116.05
- 곡션은 짧은 직선을 이어서 그린다.
#구간별 직선을 그리기 위해 15~49까지 정수 배열을 만든다.
point = np.arange(15,50)
#훈련 세트의 산점도를 그린다.
plt.scatter(train_input, train_target)
#15~49까지 2차 방정식 그래프를 그린다.
plt.plot(point, 1.01*point**2 - 21.6*point + 116.05)
#50cm 농어 데이터
plt.scatter(50, 1574, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
훈련 세트와 테스트 세트의 R^2 점수 평가하기
print(lr.score(train_poly, train_target)) #0.9706807451768623
print(lr.score(test_poly, test_target)) #0.9775935108325122
→ 과소적합
정리 [선형 회귀로 훈련 세트 범위 밖의 샘플 예측]
- k-최근접 이웃 회귀 문제점 : 훈련 세트 범위 밖의 샘플 예측 불가능
무조건 가장 가까운 샘플의 타깃을 평균하여 예측 - 선형 회귀 : 훈련 세트에 잘 맞는 직선 방정식 찾기
가장 잘 맞는 직선의 방정식 찾기 = 최적의 기울기와 절편 구하기 (coef_, intercept_)
훈련 세트 범위 밖의 데이터도 잘 예측하지만 모델이 단순하여 음수 값이 나올 수 있음 - 다항 회귀 사용
농어의 길이를 제곱하여 훈련 세트에 추가하고 다시 모델 훈련
2차 방정식의 그래프 형태를 학습하고 훈련 세트가 분포된 형태를 잘 표현한다. - 하지만 아직 과소 적합 경향이 남아있음
03-3 특성 과학과 규제
여러 특성을 사용한 다중 회귀에 대해 배우고 사이킷런의 여러 도구 사용해보기
과대적합을 막기 위한 릿지와 라쏘 회귀 배우기
다중 회귀 (Multiple Regression)
- 여러 개의 특성을 사용한 선형 회귀
- 특성 1개 : 직선 학습
특성 2개 : 평면 학습 (타깃값과 함께 3차원 공간 형성하고 선형 회귀 방정식 타깃 = a * 특성1 + b * 특성2 + 절편은 평면이 된다.)
새로운 알고리즘
- 특성 : 농어 길이, 높이, 두께
- 3개의 특성을 각각 제곱하여 추가
- 각 특성을 서로 곱해서 또 다른 특성 생성
→ 특성 공학 (Feature Engineering) : 기존의 특성을 사용해 새로운 특성을 뽑아내는 작업
데이터 준비 (pandas사용)
#pandas 사용해서 농어 데이터를 인터넷에서 다운받기
import pandas as pd
import numpy as np
df = pd.read_csv('https://bit.ly/perch_csv_data')
perch_full = df.to_numpy() #numpy 배열로 바꾸기
print(perch_full)
#target data
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_full, perch_weight, random_state=42)
사이킷런 변환기
변환기 (Transformer) : 특성을 만들거나 전처리하기 위한 클래스 → PolynomialFeature 클래스 사용
* 변환기는 입력 데이터를 변환할 때 타깃 데이터가 필요하지 않는다.
from sklearn.preprocessing import PolynomialFeatures
#2개의 특성 2, 3으로 이루어진 샘플 하나 적용
poly = PolynomialFeatures()
#fit() : 새롭게 만들 특성 조합 찾기
poly.fit([[2, 3]])
#transform() : 실제로 데이터 변환
print(poly.transform([[2,3]]))
#[[1. 2. 3. 4. 6. 9.]]
#2** = 4, 3** = 9, 2*3 = 6
PolynomialFeature 클래스 : 각 특성을 제곱한 항을 추가하고 특성끼리 서로 곱한 항을 추가한다.
무게 = a * 길이 + b * 높이 + c * 두께 + d * 1
특성 = 길이, 높이, 두께, 1
→ 1은 자동으로 절편으로 추가된다. 없애려면 include_bias=False 지정
poly = PolynomiaFeatures(include_bias=False)
poly.fit([[2,3]])
print(poly.transform([[2,3]])) #[[2. 3. 4. 6. 9.]]
절편을 위한 항이 제거되고 특성의 제곱과 특성끼리 곱한 항만 추가되었다.
train_input에 적용하기
train_input을 변환한 데이터를 train_poly에 저장하고 배열 크기를 확인한다.
poly = PolynomialFeatures(include_bias=False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
print(train_poly.shape) #(42, 9)
#9개 특성이 어떻게 만들어졌는지 출력
poly.get_feature_names_out() #array(['x0', 'x1', 'x2', 'x0^2', 'x0 x1', 'x0 x2', 'x1^2', 'x1 x2','x2^2'], dtype=object)
#테스트 세트 변환
test_poly = poly.transform(test_input)
다중 회귀 모델 훈련하기
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(train_poly, train_target)
#훈련 세트 점수 확인
print(lr.score(train_poly, train_target)) #0.9903183436982125
#테스트 세트 점수 확인
print(lr.score(test_poly, test_target)) #0.9714559911594111
특성 더 추가하기 (3제곱, 4제곱 항) → PolynomialFeatures 클래스의 degree 매개변수 사용하여 필요한 고차항의 최대 차수 지정하기
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) #(42, 55) : train_poly 배열의 열 개수가 특성 개수가 된다.
#다시 모델 훈련 시키기
lr.fit(train_poly, train_target)
#훈련 세트 점수
print(lr.score(train_poly, train_target)) #0.9999999999996433
#테스트 세트 점수
print(lr.score(test_poly, test_target)) #-144.40579436844948
특성 개수를 늘리면 선형 모델은 아주 강력해진다.
하지만 훈련 세트에 너무 과대적합되므로 테스트 세트 점수는 엉뚱한 값이 나오게 된다.
ex) 42개의 참새를 맞추기 위한 횟수 : 55번 → 한번 쏠 때보다 참새를 맞출 수 있는 확률이 높아짐
해결방법 : 특성 줄이기
규제 (Regularization)
- 머신러닝 모델이 훈련 세트를 너무 과도하게 학습하지 못하도록 훼방하는 것 (모델이 훈련 세트에 과대적합되지 않도록 만듦)
ex) 선형 회귀 모델: 특성에 곱해지는 계수 (기울기)의 크기를 작게 만든다.
- 정규화 진행하여 계수 값의 크기 맞추기 → StandardScaler 클래스 사용
- 55개의 특성으로 훈련한 선형 회귀 모델의 계수를 규제하여 훈련 세트의 점수를 낮추고 테스트 세트의 점수를 높인다.
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
#객체 훈련
ss.fit(train_poly)
#훈련 세트로 학습한 변환기를 사용해 테스트 세트까지 변환해야 한다.
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)
릿지(Ridge), 라쏘(Lasso) : 선형 회귀모델에 규제를 추가한 모델
- 릿지 : 계수를 제곱한 값을 기준으로 규제 적용
- 라쏘 : 계수의 절댓값을 기준으로 규제 적용
릿지 회귀
: 선형 모델의 계수를 작게 만들어 과대적합을 완화시킨다.
from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(train_scaled, train_target)
#훈련 세트 점수
print(ridge.score(train_scaled, train_target)) #0.9896101671037343
#테스트 세트 점수
print(ridge.score(test_scaled, test_target)) #0.9790693977615387
릿지와 라쏘 모델은 규제 양을 임의로 조절할 수 있다. → alpha 매개변수 사용
- alpha 값이 클 때 : 규제 강도 세짐 → 계수 값 줄여서 과소적합되도록 유도
- alpha 값이 작을 때 : 규제 강도 약해짐 → 선형 회귀 모델과 유사해지면서 과대적합될 가능성이 커짐
* 하이퍼파리미터 (Hyperparameter) : 머신러닝 모델이 학습할 수 없고 사람이 알려줘야 하는 파라미터
적절한 alpha 값 찾는 방법 : alpha 값에 대한 R^2 값의 그래프 그려보기
→ 훈련 세트와 테스트 세트의 점수가 가장 가까운 지점이 최적의 alpha 값이 된다.
import matplotlib.pyplot as plt
import numpy as np
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))
#alpha 값을 0.001부터 10배씩 늘렸기 때문에 그래프를 출력하면 왼쪽이 너무 촘촘해진다.
#alpha_list에 있는 6개의 값을 동일한 간격을 나타내기 위해 로그 함수로 바꿔서 지수로 표현한다.
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 = 0.01)
ridge = Ridge(alpha=0.1)
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target)) #0.9903815817570367
print(ridge.score(test_scaled, test_target)) #0.9827976465386928
→ 훈련/테스트 세트의 점수가 비슷하게 모두 높고 과대적합과 과소적합 사이에서 균형을 맞추고 있다.
라쏘 회귀 (Lasso Regression)
: 릿지와 달리 계수 값을 아예 0으로 만들 수도 있다.
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 매개변수 사용해서 규제 강도 조절하기
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.fit(train_scaled, train_target)
#훈련 점수와 테스트 점수 저장
train_score.append(lasso.score(train_scaled, train_target))
test_score.append(lasso.score(test_scaled, test_target))
#train_score, test_score 리스트 사용해서 그래프 그리기
#x축은 로그 스케일로 바꿔 그린다.
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)) #0.9888067471131867
print(lasso.score(test_scaled, test_target)) #0.9824470598706695
정리 [모델의 과대적합 제어하기]
- 문제점 : 훈련 세트에서 과소적합 발생
해결방법 : 높이, 두께 특성 추가해서 회귀모델 훈련 - 다항 특성 많이 추가하여 훈련 세트에서 높은 점수를 얻는 모델 훈련
→ 특성을 많이 추가하면 선형 회귀는 매우 강력해짐 - 하지만 특성이 너무 많으면 선형 회귀 모델을 제약하기 위한 도구 필요
→ 릿지 회귀, 라쏘 회귀 모델의 규제 양을 조절하기 위해 최적의 alpha 값 찾음 - 사이킷런 사용 → 다중 회귀 모델, 릿지/라쏘 모델 훈련
'Study > PBL' 카테고리의 다른 글
[혼공머신] Ch05 (0) | 2024.07.23 |
---|---|
[혼공머신] Ch04 (0) | 2024.07.18 |
[혼공머신] Ch01, 2 (2) | 2024.07.12 |
딥러닝 모델 경량화 (0) | 2024.07.11 |
Deep Fake voice recognition (0) | 2024.07.11 |