[머신러닝] 규제(regulariztion)와 릿지 회귀(ridge), 라쏘 회귀(lasso)

규제(regulariztion)와 릿지(ridge), 라쏘(lasso)



규제란?

규제는 머신러닝 모델이 훈련 세트에 과대적합 되지 않도록 만드는 것이다. 즉, 모델이 훈련 세트를 과도하게 훈련하지 못하도록 훼방을 놓는 것이다.



과대적합(Over Fitting)

훈련세트의 점수가 굉장히 좋은데, 테스트 세트에서 점수가 심하게 나쁘다면 과대적합(overfitting)되었다고 말한다.



과대적합 예제

과대적합 예제를 토대로 규제를 적용하는 방법에 알아보자.
1. 예제를 보면 PolynomialFeatures클래스의 dgree 속성을 5를 설정하여 5제곱까지 특성을 만들었다.
2. train_poly.shpae 로 배열의 크기를 확인하니 55개의 속성이 만들어졌다.
3. 훈련 세트와 테스트 세트를 평가 해보니 점수가 엄청 차이 나는 과대적합이 발생했다.

과대 적합이 일어난 이유는 특성의 개수가 너무 많기 때문이다. 특성 개수를 늘리면 모델은 거의 완벽하게 훈련이 가능하지만 너무 많으면 과대 적합이 발생한다. 
import pandas as pd

#특성 가져오기
df = pd.read_csv('https://bit.ly/perch_csv_data')
perch_full = df.to_numpy()
#print(perch_full)

#타깃 데이터
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)

# 특성 만들기
from sklearn.preprocessing import PolynomialFeatures

#degree=5 로 하여 5제곱 특성만들기
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) 55개 특성이 만들어짐.


#모델 훈련 시키기
from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(train_poly, train_target) #선형 회귀 모델 훈련

#훈련 세트 평가
print(lr.score(train_poly, train_target))

#테스트 세트 평가
print(lr.score(test_poly, test_target))
<결과>
(42, 55)    #특성이 55개
0.9999999999997232    #훈련 세트
-144.40564483377855    #테스트 세트



정규화

규제를 적용하여 과대적합을 없애기 전에 할 작업이 있다.
예제는 선형 회귀 모델이다. 선형 회귀 모델에 규제를 적용하려면 특성에 곱해지는 계수 또는 기울기를 작게 만들어야 한다. 
곱해지는 계수기울기를 작게 만들기 전 특성의 스케일을 정규화 해야한다. 정규화 하지 않으면 곱해지는 계수 값의 크기가 달라진다.
아래 예제를 입력하자.
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)

train_scaled 와 test_scaled를 표준 점수로 변환했다.
이제는 규제를 추가하면 된다.
선형 회귀 모델에 규제를 추가한 모델을 릿지라쏘라고 부르며 두 개의 모델을 서로 규제 하는 방법이 다르다.



릿지 회귀 모델 훈련 

릿지 회귀로 모델을 훈련 시켜 보자.
릿지는 계수를 제곱 한 값을 기준으로 규제를 적용한다.
규제를 적용한다는 것은 계수의 값을 조절 한다는 것이다.
#릿지
from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(train_scaled, train_target)

print(ridge.score(train_scaled, train_target))
print(ridge.score(test_scaled, test_target))
<결과>
0.9896101671037343
0.9790693977615387

전 보다 훈련 세트의 점수는 줄었지만 테스트 점수가 정상이 되었다. 


alpha 매개변수

릿지라쏘 모델 둘 다 alpha 매개변수 값을 바꾸면 규제의 강도를 조절 할 수 있다.
alpha 값이 크면 규제 강도가 강해지므로 계수 값을 줄이고 과소 적합에 가까워진다.
반대로 alpha 값이 작아 질 수록 계수 값을 줄이는 역할이 줄어들고 과대 적합에 가까워진다.



적절한 alpha 값 찾기

alpha 값에 따라 규제의 강도가 달라지므로 적절한 alpha 값을 찾아야 한다. 적절한 alpha 값을 찾는 방법 중 하나는 R² 값의 그래프를 그리는 방법이다.


평가 점수 담을 리스트 만들기

alpha 값을 바꿀 때 마다 훈련 세트와 테스트 세트의 점수를 담을 리스트 2개를 만든다.
train_score = []
test_score = []


훈련 세트, 테스트 세트 점수 담기

0.001 부터 100 까지 총 여섯 종류의 alpha 값을 지정 해 줬다. 모델을 훈련 시켜준 후 훈련 세트테스트 세트의 점수를 저장해 준다.
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
ridge = Ridge(alpha=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))


그래프 그리기 

훈련세트와 테스트 세트의 점수를 그려보자.
import matplotlib.pyplot as plt

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 이 이상적인 alpha 값이 된다.
즉 alpha 값은 10^-1 =  0.1 이 된다.



alpha 값 지정 한 릿지 회귀

alpha 매개변수에 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))
<결과>
0.9903815817570367
0.9827976465386928


라쏘 회귀

릿지와 라쏘 회귀 모델의 훈련법은 같지만 라쏘는 계수의 절댓값을 기준으로 규제를 적용하며 Lasso 클래스를 사용한다. 라쏘도 마찬가지로 alpha 값으로 규제 강도 조절이 가능다.


라쏘 회귀 모델 훈련

라쏘 회귀 모델을 훈련 시키면 점수가 좋게 나온다.
from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(train_scaled, train_target)

print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))
<결과>
0.989789897208096
0.9800593698421883


적절한 alpha 값 찾기

적절한 alpah 값을 찾아보자.
train_score = []
test_score = []

alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
lasso = Lasso(alpha=alpha)#리스트 alpha 값으로 설정
lasso.fit(train_scaled, train_target)

train_score.append(lasso.score(train_scaled, train_target))
test_score.append(lasso.score(test_scaled, test_target))

#라쏘 그래프 그리기
import matplotlib.pyplot as plt

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 값 2는 훈련 세트와 테스트 세트 점수가 너무 낮으므로 과소적합 이다.
따라서 점수가 높고 훈련 세트와 테스트 세트가 가장 가까운 alpha 값 1이 적정 alpha다. 즉 10^1 = 10이 된다.



alpha 값 지정 한 라쏘 회귀

alpha 값 지정 후 훈련 하면 점수가 아주 잘나온다.
lasso = Lasso(alpha=10)
lasso.fit(train_scaled, train_target)

print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))
<결과>
0.9888067471131867
0.9824470598706695



전체 소스코드

import pandas as pd

#특성 가져오기-------------------------------------------------------------------------
df = pd.read_csv('https://bit.ly/perch_csv_data')
perch_full = df.to_numpy()
#print(perch_full)

#타깃 데이터
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)

# 특성 만들기-------------------------------------------------------------------------
from sklearn.preprocessing import PolynomialFeatures

#degree=5 로 하여 5제곱 특성만들기
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) 55개 특성이 만들어짐.


#모델 훈련 시키기
from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(train_poly, train_target) #선형 회귀 모델 훈련

# #훈련 세트 평가
# print(lr.score(train_poly, train_target))
#
# #테스트 세트 평가
# print(lr.score(test_poly, test_target))

#정규화(표준 점수)로 변환
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_poly)
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)

#릿지 회귀-------------------------------------------------------------------------
from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(train_scaled, train_target)

print(ridge.score(train_scaled, train_target))
print(ridge.score(test_scaled, test_target))

#훈련세트, 테스트 세트 평가 점수 저장하기
train_score = []
test_score = []

alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
ridge = Ridge(alpha=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))

#릿지 그래프 그리기
import matplotlib.pyplot as plt

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


#릿지 알파 값 변경
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))


#라쏘 회귀-------------------------------------------------------------------------
from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(train_scaled, train_target)

print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))

#훈련세트, 테스트 세트 평가 점수 저장하기
train_score = []
test_score = []

alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
lasso = Lasso(alpha=alpha)#리스트 alpha 값으로 설정
lasso.fit(train_scaled, train_target)

train_score.append(lasso.score(train_scaled, train_target))
test_score.append(lasso.score(test_scaled, test_target))

#라쏘 그래프 그리기
import matplotlib.pyplot as plt

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


#라쏘 알파 값 변경
lasso = Lasso(alpha=10)
lasso.fit(train_scaled, train_target)

print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))


참조


혼자 공부하는 머신러닝 + 딥러닝(깃 허브) : https://github.com/rickiepark/hg-mldl


댓글

이 블로그의 인기 게시물

[Python] 파이썬 if문 사용법과 예제

[네트워크] 오류 제어 방식 이란?(FEC, BEC, ARQ)

[Virtual Box] 가상머신 에러 E_FAIL (0x80004005), (VERR_SUPLIB_PATH_NOT_CLEAN) 해결 방법