1. k-최근접 이웃 회귀
회귀/ k-최근접 회귀/ 결정계수/ 과대적합과 과소적합
지도 학습 알고리즘
- 분류: 샘플 -> 몇 개의 클래스 중 하나로 분류하는 문제
- 회귀(regression): 임의의 어떤 숫자를 예측하는 문제
- ex. 내년도 경제 성장률 예측, 배달 도착할 시간 예측
- 정해진 클래스 X 임의의 수치 출력
- 두 변수 사이의 상관관계를 분석하는 방법
k-최근접 이웃 분류
- 예측하려는 샘플에 가장 가까운 샘플 k개 선택
- 샘플들의 클래스 확인 -> 다수 클래스를 새로운 샘플의 클래스로 예측
k-최근접 이웃 회귀
- 예측하려는 샘플에 가장 가까운 이웃 샘플 k개 선택
- 이웃한 샘플의 타깃은 어떤 클래스 X 임의의 수치 O
- 이웃 샘플의 수치 사용 -> 새로운 샘플 x의 타깃 예측
=> 가장 가까운 이웃 샘플을 찾고 이 샘플들의 타깃값을 평균하여 예측으로 삼음
데이터 준비
# https://gist.github.com/rickiepark/2cd82455e985001542047d7d55d50630
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])
산점도
하나의 특성 사용 -> 특성 데이터: x축/ 타깃 데이터: y축
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차원 배열로 변환
- 사이킷런에 사용할 훈련 세트 -> 2차원 배열이어야 함
- perch_length: 1차원 배열 => train_input, test_input: 1차원 배열
- 1차원 배열의 크기 -> 원소가 1개인 튜플로 나타냄
- ex. [1, 2, 3]의 크기: (3, )
- -> 2차원 배열: 열 추가 => 크기: (3, 1)
# 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_input = train_input.reshape(-1, 1)
test_input = train_input.reshape(-1, 1)
print(train_input.shape, test_input.shape) # (42, 1) (14, 1)
결정계수(coefficient of determination) $(R^2)$
KNeighborsRegressor
- k-최근접 이웃 회귀 모델 만드는 사이킷런 클래스
- n_neighbors 매개변수로 이웃의 개수 지정 (기본값: 5)
분류) 정확도 = 테스트 세트에 있는 샘플을 정확하게 분류한 개수의 비율 = 정답을 맞힌 개수의 배율
회귀) 예측하는 값, 타깃 모두 임의의 수치 -> 정확한 숫자 맞힐 수 X => 결정계수로 평가
$$ R^2 = 1 - \frac{\sum (타깃 - 예측)^2}{\sum (타깃 - 평균)^2} = \frac{\sum (y_i - \hat{y}_i)^2}{\sum (y_i - \bar{y})^2} $$
- 타깃의 평균 정도 예측(분자와 분모 비슷) -> 0에 가까운 값
- 예측이 타깃에 가까워짐(분자가 0에 가까워짐) -> 1에 가까운 값
from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor()
# k-최근접 이웃 회귀 모델 훈련
knr.fit(train_input, train_target)
# 테스트 세트 R^2 점수
print(knr.score(test_input, test_target)) # 0.992809~
mean_absolute_error
- 회귀 모델의 평균 절댓값 오차 계산
- 첫 번째 매개변수: 타깃/ 두 번째 매개변수: 예측값
mean_squared_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.157142~ = 예측이 평균적으로 19g 정도 타깃값과 다름
과대적합 vs 과소적합
훈련 세트 vs 테스트 세트 -> 훈련 세트 > 테스트 세트
=> 훈련 세트에서 모델을 훈련했기 때문
- 과대적합(overfitting)
- 훈련 세트가 너무 높은 경우
- 훈련 세트에만 잘 맞는 모델 -> 실전에 투입해 새로운 샘플에 대한 예측 만들 때 잘 동작 X
- 과소적합(underfitting)
- 훈련 세트 < 테스트 세트 or 두 점수 모두 낮은 경우
- 모델이 너무 단순 -> 훈련 세트에 적절히 훈련 X
- 훈련 세트와 테스트 세트의 크기 매우 작음
훈련 세트 점수(0.98048~) < 테스트 세트 점수(0.992809~) -> 과소적합
=> (해결) 모델 더 복잡하게 만듦 => 이웃의 개수 k ↓
- k ↓ -> 훈련 세트에 있는 국지적인 패턴에 민감
- k ↑ -> 데이터 전반에 있는 일반적인 패턴 따름
# 훈련 세트 R^2 점수
print(knr.score(train_input, train_target)) #0.969882~
# 이웃의 개수: 5 -> 3
knr.n_neighbors = 3
# 모델 다시 훈련
knr.fit(train_input, train_target)
# 훈련 세트 R^2 점수
print(knr.score(train_input, train_target)) #0.98048~
# 테스트 세트 R^2 점수
print(knr.score(test_input, test_target)) # 0.974645~
[문제해결 과정]회귀 문제 다루기
회귀: 임의의 수치를 예측하는 문제
k-최근접 이웃 회귀 모델
- 가까운 k개의 이웃 찾음
- 이웃 샘플의 타깃값을 평균하여 샘플의 예측값으로 사용
- 회귀 모델의 점수로 $R^2$(결정계수) 반환, 1에 가까울수록 좋음
- 정량적인 평가 방법: 절댓값 오차
- 모델 훈련 후 훈련 세트, 테스트 세트 평가 점수
- 과대적합: 테스트 세트 점수 너무 낮음
- -> 모델 덜 복잡하게 만들기: k 값 늘리기
- 과소적합: 테스트 세트 점수 너무 높음 or 두 점수 모두 낮음
- -> 모델 더 복잡하게 만들기: k 값 줄이기
2. 선형 회귀
선형 회귀/ 계수 또는 가중치/ 모델 파라미터/ 다항 회귀
k-최근접 이웃의 한계
길이 50cm인 농어 무게 예측: 1.033kg But, 실제는 훨씬 더 많이 나감
print(knr.predict([[50]])) # [1033.3333~]
산점도
훈련 세트, 50cm 농어, 농어의 최근접 이웃
kneighbors()
가장 가까운 이웃까지의 거리와 이웃 샘플의 인덱스
import matplotlib.pyplot as plt
# 50cm 농어의 이웃 구함
distnaces, indexexs = knr.kneighbors([[50]])
# 훈련 세트의 산점도 그림
plt.scatter(train_input, train_target)
# 훈련 세트 중 이웃 샘플만 다시 그리기
plt.scatter(train_input[indexes], tarin_target[indexes], marker='D')
# 50cm 농어의 데이터
plt.scatter(50, 1033, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
=> 길이 ↑ -> 농어 무게 ↑
But, 50cm 농어에서 가장 가까운 것은 45cm 근방 -> k-최근접 이웃 알고리즘: 샘플들의 무게 평균
print(np.mean(train_target[indexes])) # 1033.333333~
=> k-최근접 이웃 회귀: 가장 가까운 샘플 찾아 타깃 예측
=> 새로운 샘플이 훈련 세트 범위 벗어나면 이상한 값 예측할 수 있음
ex. 길이가 100cm인 농어의 무게: 1.033g으로 예측
print(knr.predict([[100]])) # 1033.333333~
산점도
# 100cm 농어의 이웃을 구함
distances, indexes = knr.kneighbors([[100]])
# 훈련 세트의 산점도
plt.scatter(train_input, train_target)
# 훈련 세트 중 이웃 샘플만 다시 그림
plt.scatter(train_input[indexes], train_target[indexes], market='D')
# 100cm 농어 데이터
plt.scatter(100, 1033, market='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
=> 농어가 커도 무게 늘어나지 X
-> k-최근접 이웃 사용해 문제 해결 -> 가장 큰 농어가 포함되도록 훈련 세트 다시 만들어야 함
선형 회귀(linear regression)
- 특성과 타깃 사이의 관계를 가장 잘 나타내는 선형 방정식을 찾음
- 특성이 한 개 -> 직선 방정식
- 특성과 타깃 사이의 관계 -> 선형 방정식의 계수 or 가중치에 저장
- 가중치는 기울기와 절편을 모두 의미하는 경우 ↑
- 모든 농어의 무게를 하나로 예측
- IF. 훈련 세트의 평균에 가깝다면 $R^2$는 0에 가까운 값이 됨
- 길이 ↓ 농어의 무게 ↑/ 길이 ↑ 농어의 무게 ↓ => $R^2$ 음수가 될 수 있음
LinearRegression
- 사이킷런의 선형 회귀 클래스
- fit_intercept 매개변수 False로 지정 -> 절편 학습 X (기본값: True)
- 학습된 모델의 coef_ 속성: 특성에 대한 계수를 포함한 배열
- 배열의 크기 = 특성의 개수
- intercept_ 속성: 절편이 저장되어 있음
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
# 선형 회귀 모델을 훈련
lr.fit(train_input, train_target)
# 50cm 농어에 대해 예측
print(lr.predict([[50]]) # [1241.838603223]
$$ y = a * x + b (x: 농어의 길이, y: 농어의 무게) $$
print(lr.coef_, lr.intercept_) # [39.01714496] -709.0186449535477
기울기 = 계수(coefficient) = 가중치(weight)
모델 파라미터(model parameter)
- 머신러닝 알고리즘이 찾은 값
- 머신러닝 모델이 특성에서 학습한 파라미터
- ex. coef_, intercept_
- 모델 기반 학습: 머신러닝 알고리즘의 훈련 과정은 최적의 모델 파라미터를 찾는 것
- 사례 기반 학습: 훈련 세트를 저장하는 것
- 모델 파라미터 X
- ex. k-최근접 이웃 알고리즘
- 사례 기반 학습: 훈련 세트를 저장하는 것
산점도 + 직선
농어의 길이 15 ~ 50까지 직선
기울기, 절편 -> (15, 15*39-709)와 (50, 50*39-709) 두 점 이음
# 훈련 세트의 산점도
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.ylbael('weight')
plt.show()
# 훈련 세트
print(lr.score(train_input, train_target)) # 0.939846~
# 테스트 세트
print(lr.score(test_input, test_target)) # 0.82475031~
다항 회귀(polynomial regression)
- 다항식(polynomial) 사용 -> 특성과 타깃 사이의 관계를 나타냄
- 비선형일 수 있지만, 선형 회귀로 표현할 수 있음
농어의 무게가 0g 이하로 내려가는 것은 현실에서 있을 수 X
-> 최적의 직선이 아닌 최적의 곡선 찾기
=> 길이를 제곱한 항이 훈련 세트에 추가 되어야 함
column_stack()
훈련 세트, 테스트 세트 모두 열 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)
train_poly
선형 회귀 모델 다시 훈련
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)
=> 2차 방정식 그래프 찾기 위해 훈련 세트에 제곱 항 추가 But, 타깃값 그대로 사용
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.01 * 길이^2 - 21.6 * 길이 + 116.05 $$
산점도
짧은 직선 이어 그려서 곡선처럼 표현
# 구간별 직선을 그리기 위해 15 ~ 49까지 정수 배열을 만듦
point = np.arrage(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.xlable('length')
plt.ylable('weight')
plt.show()
print(lr.score(train_poly, train_target)) # 0.970680~
print(lr.score(test_poly, test_target)) # 0.977593~
=> 훈련 세트와 테스트 세트에 대한 점수 크게 높아짐
But, 여전히 테스트 세트의 점수가 조금 더 높음 = 과소 적합
-> 조금 더 복잡한 모델 필요
[문제해결 과정] 선형 회귀로 훈련 세트 범위 밖의 샘플 예측
k-최근접 이웃 회귀 사용해서 농어의 무게 예측
-> (-) 훈련 세트 범위 밖의 샘플을 예측할 수 X
아무리 멀리 떨어져 있더라도 무조건 가장 가까운 샘플의 타깃을 평균하여 예측
=> (해결) 선형 회귀
- 훈련 세트에 잘 맞는 직선의 방정식 사용
- 최적의 기울기와 절편 구한다
- coef_, intercept_ 속성
- 사이킷런의 LinearRegression 클래스 사용
- (-) 모델이 단순 -> 농어의 무게 음수일 경우 O
=> (해결) 다항 회귀
- 농어의 길이 제곱 -> 훈련 세트에 추가 -> 선형 회귀 모델 다시 훈련
- 2차 방정식의 그래프 형태를 학습, 훈련 세트가 분포된 형태 잘 표현
- 훈련 세트, 테스트 세트의 성능이 훨씬 ↑
- (-) 훈련 세트의 성능 < 테스트 세트의 성능 = 과소적합 경향 남아 있음
=> (해결) 조금 더 복잡한 모델 만듦
3. 특성 공학과 규제
다중 회귀/ 특성 공학/ 릿지/ 라쏘/ 하이퍼파라미터
다중 회귀(multiple regression)
- 여러 개의 특성을 사용하는 회귀 모델
- 특성 ↑ 강력한 성능 발휘
- 특성 1개 -> 직선
- 특성 2개 -> 평면 학습
- 타깃값과 함께 3차원 공간 형성
- $ 타깃 = a * 특성1 + b * 특성2 + 절편 $
=> 3차원 공간 이상 그리거나 상상 X
선형 회귀 단순한 직선 or 평면으로 생각 -> 성능 무조건 낮다? (X)
특성 ↑ 고차원 -> 선형 회귀) 매우 복잡한 모델 표현 O
농어의 길이 + 높이, 두께 데이터 추가
-> 3개의 특성 각각 제곱하여 추가, 새로운 특성 만들어서 추가(농어 길이 * 농어 높이)
특성 공학(feature engineering)
기존의 특성을 사용해 새로운 특성을 뽑아내는 능력
데이터 준비
csv 파일 -> 판다스 데이터 프레임: pd.read_csv() -> 넘파일 배열: to_numpy()
read_csv()
- csv 파일을 로컬 컴퓨터나 인터넷에서 읽어 판다스 데이터프레임으로 변환하는 함수
- sep: csv 파일의 구분자 지정 (기본값: 콤마(,))
- header: 데이터프레임의 열 이름으로 사용할 csv 파일의 행 번호 지정 (기본값: 첫 번째 행 -> 열 이름으로 사용)
- skiprows: 파일에서 읽기 전에 건너뛸 행의 개수 지정
- nrows: 파일에서 읽을 행의 개수 지정
import pandas as pd
df = pd.read_csv('https://bit.ly/perch_csv_data')
perch_full = df.to_numpy()
print(perch_full)
# [[8.4 2.11 1.41]
# [13.7 3.53 2. ]
# [15. 3.82 2.43]
# ...
# [44. 12.49 7.6 ]]
# https://bit.ly/perch_data
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])
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)
특성을 만들거나 전처리하기 위한 다양한 클래스 제공
LinearRegression 같은 사이킷런의 모델 클래스는 추정기(estimator)라고도 부름
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures()
poly.fit([[2, 3]])
print(poly.transform([[2, 3]]) # [[1. 2. 3. 4. 6. 9.]]
=> 변환기는 입력 데이터를 변환하는 데 타깃 데이터 필요 X
-> 모델 클래스와 다르게 fit() 메서드에 입력 데이터만 전달
$$ 무게 = a * 길이 + b * 높이 + c * 두께 + d * 1 $$
선형 방정식의 절편: 항상 값이 1인 특성과 곱해지는 계수
-> 특성: 길이, 높이, 두께, 1
But, 선형 모델: 자동으로 절편 추가
PolynomialFeatures
- 주어진 특성을 조합하여 새로운 특성을 만듦
- degree: 최고 차수 지정 (기본값: 2)
- interactoin_only=True: 거듭제곱 항 제외, 특성 간의 곱셈 항만 추가 (기본값: False)
- include_bias=False: 절편을 위한 특성 추가 X (기본값: True)
# 절편을 위한 항 제거, 특성의 제곱과 특성끼리 곱한 항만 추가
# include_bias=False 지정하지 않아도 자동으로 특성에 추가된 절편 항 무시
poly = PolynomialFeatures(include_bias=False)
poly.fit([[2, 3]])
print(poly.transform([[2, 3]]) # [[2. 3. 4. 6. 9.]]
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()
# ['x0', 'x1', 'x2', 'x0^2', 'x0 x1', 'x0 x2', 'x1^2', 'x1 x2', 'x2^2']
# x0: 첫 번째 특성 의미, x0^2: 첫 번째 특성의 제곱, x0 x1: 첫 번째 특성과 두 번째 특성 곱
테스트 세트 변환
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.99031834~
print(lr.score(test_poly, test_target)) # 0.97145599~
=> 과소적합 문제 해결
-> 특성 더 많이 추가하면? ex. 3제곱, 4제곱 항 추가
=> PolynomialFeatures 클래스의 degree 매개변수 사용 -> 필요한 고차항의 최대 차수 지정
poly = PolynomialFeatures(degree=5, include_bias=False) # 5제곱
poly.fit(train_input)
train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input)
print(train.poly.shape) # (42, 55)
=> 만들어진 특성의 개수: 55개
train_poly 배열의 열의 개수 = 특성의 개수
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target)) # 0.999999999~
print(lr.score(test_poly, test_target)) # -144.40579~
=> 테스트 세트에 대한 점수가 음수
=> 특성 개수 ↑ -> 선형 모델 강력해짐 = 훈련 세트에 대해 거의 완벽하게 학습
But, 훈련 세트에 너무 과대적합
규제(regularization)
- 머신러닝 모델이 훈련 세트를 너무 과도하게 학습하지 못하도록 훼방하는 것
- 모델이 훈련 세트에 과대적합되지 않도록 만드는 것
- 선형 회귀 모델) 특성에 곱해지는 계수(or 기울기)의 크기 작게 만드는 것
특성의 스케일 정규화 X -> 곱해지는 계수 값의 차이 => 공정하게 제어 X
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_poly)
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)
선형 회귀 모델 + 규제 -> sklearn.linear_model
- 릿지 (조금 더 선호)
- 계수를 제곱한 값을 기준으로 규제 적용
- 계수의 크기 줄임
- 라쏘
- 계수가 절댓값을 기준으로 규제 적용
- 계수의 크기 줄임, 0으로 만들 수 있음
릿지 회귀
- 규제가 있는 선형 회귀 모델 중 하나
- 선형 모델의 계수 작게 만들어 과대적합 완화
- 효과가 좋아 널리 사용하는 규제 방법
Ridge
- 규제가 있는 회귀 알고리즘인 릿지 회귀 모델 훈련
- alpha 매개변수: 규제의 강도 조절
- alpha 값 ↑ -> 규제 ↑ (기본값: 1)
- solver 매개변수: 최적의 모델 찾기 위한 방법 지정 (기본값: auto)
- random_state: solver가 sag나 saga일 때 넘파이 난수 시드값 지정
- sag: 확률적 평균 경사 하강법 알고리즘/ 특성과 샘플 수 ↑ -> 성능 빠르고 좋음
- saga: sag의 개선 버전
from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target)) # 0.989610~
print(ridge.score(test_scaled, test_target)) # 0.97906939~
alpha 값 ↑ -> 규제 강도 ↑ => 계수 값 ↓, 조금 더 과소적합되도록 유도
적절한 alpha 값 찾는 방법: alpha 값에 대한 $R^2$의 그래프 그려 보는 것
훈련 세트와 테스트 점수가 가장 가까운 지점 -> 최적의 alpha 값
import matplotlib.pyplot as plt
train_score = []
test_score = []
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))
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()
=> 훈련 세트와 테스트 세트의 점수 차이가 큼
L: 훈련 세트에 잘 맞고, 테스트 세트에 과대적합/ R: 훈련 세트와 테스트 세트 점수 모두 과소적합
=> 적합한 alpha 값: -1 ($10^{-1}=0.1$)
ridge = Ridge(alpha=0.1)
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target)) # 0.9903815~
print(ridge.score(test_scaled, test_target)) # 0.9827976~
라쏘 회귀
- 또 다른 규제가 있는 선형 회귀 모델
- 릿지와 달리 계수 값을 아예 0으로 만들 수 있음
Lasso
- 규제가 있는 회귀 알고리즘인 라쏘 회귀 모델 훈련
- 최적의 모델 찾기 위해 좌표축을 따라 최적화 수행(좌표 하강법)
- alpha와 random_state 매개변수 = Ridge 클래스
- max_iter: 알고리즘의 수행 반복 횟수 지정 (기본값: 1000)
from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target)) # 0.989789~
print(lasso.score(test_scaled, test_target)) # 0.980059~
train_score = []
test_score = []
alpha_test = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
# 라쏘 모델 만듦
lasso = Lasso()
# 라쏘 모델 훈련
lasso.fit(train_scaled, train_target)
# 훈련 점수와 테스트 점수 저장
train_score.append(lasso.score(train_scaled, train_target))
test_score.append(lasso.score(test_scaled, test_target))
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()
L: 과대적합/ R: 훈련 세트와 테스트 세트의 점수가 좁혀짐
=> 최적의 alpha 값: 1 ($10^{1}=10$)
lasso = Lasso()
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target)) # 0.9888067~
print(lasso.score(test_scaled, test_target)) # 0.9824470~
계수 0으로 만들기
print(np.sum(lasso.coef_ == 0)) # 40
[문제해결 과정] 모델의 과대적합을 제어하기
선형 회귀 알고리즘 -> 농어의 무게를 예측하는 모델 훈련
But, 훈련 세트에 과소적합
(해결)
- 농어의 길이 + 높이, 두께 사용 => 다중 회귀 모델 훈련
- 다항 특성 ↑ 추가
- -> 선형 회귀 성능 ↑ But, 과할 경우 제약하기 위한 도구 필요(릿지, 라쏘)
- 최적의 alpha 값 찾아 릿지와 라쏘 모델의 규제 양 조절
=> 훈련 세트에서 거의 완벽에 가까운 점수 얻는 모델 훈련
출처
'Artificial Intelligence' 카테고리의 다른 글
[혼자 공부하는 머신러닝+딥러닝] Chapter 04 다양한 분류 알고리즘 (0) | 2024.07.25 |
---|---|
[밑바닥부터 시작하는 딥러닝] CHAPTER 2 퍼셉트론 (0) | 2023.03.30 |
[밑바닥부터 시작하는 딥러닝] CHAPTER 1 헬로 파이썬 (0) | 2023.03.28 |
[머신러닝 교과서 with 파이썬, 사이킷런, 텐서플로] 2장 간단한 분류 알고리즘 훈련 (0) | 2023.03.16 |
[머신러닝 교과서 with 파이썬, 사이킷런, 텐서플로] 1장 컴퓨터는 데이터에서 배운다 (1) | 2023.03.16 |