데이터 준비¶
In [1]:
import pandas as pd
df = pd.read_csv('https://bit.ly/perch_csv_data')
perch_full = df.to_numpy()
print(perch_full)
In [2]:
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])
In [3]:
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)
사이킷런의 변환기¶
변환기란 특성을 만들거나 전처리하기 위한 클래스를 일컫는 말이다.
In [4]:
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures()
poly.fit([[2, 3]])
print(poly.transform([[2,3]]))
- 2개의 특성을 가진 데이터가 6개의 특성을 가진 샘플로 바뀌었음.
- PolynomialFeatures 클래스는 기본적으로 각 특성을 제곱한 항을 추가하고 특성끼리 서로 곱한 항을 추가함.
- 1이 추가된 이유는, 상수항(y절편)에 곱해지는 고정 계수라고 생각하면 됨.
- 그러나 사이킷런의 선형 모델은 자동으로 절편을 추가하므로 굳이 1을 포함할 필요가 없음.
- include_bias = False로 지정하여 다시 특성을 변환해보자.
In [5]:
poly = PolynomialFeatures(include_bias=False)
poly.fit([[2, 3]])
print(poly.transform([[2,3]]))
- 잘 변환되었다.
- 사실 include_bias=False로 지정하지 않아도 사이킷런 모델은 자동으로 특성에 추가된 절편 항을 무시한다.
(아니 그러면 왜 시켰냐고요)
In [6]:
poly = PolynomialFeatures(include_bias=False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
In [7]:
print(train_poly.shape)
In [8]:
poly.get_feature_names()
Out[8]:
- get_feature_names() 메서드를 호출하면 9개의 특성이 각각 어떤 입력의 조합으로 만들어졌는지 알려준다.
In [9]:
# 테스트 세트도 같은 방식으로 변환한다.
test_poly = poly.transform(test_input)
다중 회귀 모델 학습시키기¶
In [10]:
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
- 두께 데이터 및 특성 공학을 활용한 새로운 데이터들을 활용한 결과 스코어가 높아졌다.
In [11]:
print(lr.score(test_poly, test_target))
- 훈련 세트의 스코어가 테스트 세트의 스코어보다 높으므로 과소적합 문제는 해결했다.
- 만약 더 많은 특성을 추가한다면?
- degree 매개변수를 이용하면 최대차수를 지정할 수 있다.
In [12]:
poly = PolynomialFeatures(degree=5, include_bias=False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input)
In [13]:
print(train_poly.shape)
특성의 개수가 55개로 늘어났다.
In [14]:
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
In [15]:
print(lr.score(test_poly, test_target))
- 특성의 개수를 늘리자 훈련 세트에 아주 가까운 모델이 학습됬다.
- 그러나 테스트 세트에서는 아주 큰 음수 값이 나온다.
- 당연하게도, 과대적합됬기 때문이다.
- 훈련 세트의 샘플 개수가 42개이므로 55개의 특성을 이용하면 완벽히 학습할 수 있는 것이 당연하다.
- 규제(regulazation)과 정규화를 추가하여 overfitting을 막아보자.
규제¶
In [16]:
from sklearn.preprocessing import StandardScaler #정규화의 일종
# 정규화를 실시하고 학습시킨다.
ss = StandardScaler()
ss.fit(train_poly)
# fit이 되었으므로 transform을 실시하여 feature의 수를 늘린다.
# 꼭 훈련 세트로 학습한 변환기를 사용해 테스트 세트까지 변환해야 한다.
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)
릿지 회귀¶
릿지 회귀란 계수를 제곱한 값을 기준으로 선형 회귀 모델에 규제를 적용하는 것을 말한다.
In [17]:
from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target))
선형 회귀에서 완벽에 가까웠던 스코어가 조금은 낮아졌다.
In [18]:
print(ridge.score(test_scaled, test_target))
- 테스트 세트 점수가 아주 큰 음수에서 정상으로 돌아왔다.
- 많은 특성을 사용했음에도 불구하고 훈련 세트에 너무 과대적합되지 않아 테스트 세트에서도 좋은 성능을 보인다.
- 릿지 모델에서 규제의 양을 조절할 수 있다.
- alpha 매개변수를 사용하면 되는데 값이 크면 규제도 크다.
- alpha값과 같이 모델이 학습하는 계수가 아니라 사용자가 직접 정해줘야 하는 계수를 하이퍼파라미터라고 한다.
- 적절한 alpha 값을 찾는 방법은 alpha값에 대한 R2 값 그래프를 그려보는 것이다.
- 이 때 훈련 세트와 테스트 세트의 점수가 가장 가까운 지점이 최적의 alpha값이 된다.
In [19]:
import matplotlib.pyplot as plt
train_score = []
test_score = []
In [20]:
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
# 릿지 모델 생성
ridge = Ridge(alpha=alpha)
# fitting
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배씩 늘렸기 때문에 로그 함수로 바꾸어 지수로 표현한다.
In [21]:
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()
- 파란색 선이 훈련 세트 그래프, 주황색 선이 테스트 세트 그래프이다.
- 왼쪽은 훈련 세트에는 잘맞고, 테스트 세트에는 잘 맞지 않는 overfitting의 양상을 띤다.
- 오른쪽은 훈련 세트와 테스트 세트의 점수가 모두 낮아지는 과소적합의 모습을 보인다.
- 적절한 alpha 값은 두 그래프가 가장 가깝고 점수가 가장 높은 -1, 즉 10^-1 = 0.1이다.
- 따라서 alpha=0.1로 지정하여 최종 모델을 훈련시킬 것이다.
In [22]:
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으로 만들어버릴 수도 있다.
In [23]:
from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target))
라쏘 역시 과대적합을 잘 억제했다.
In [24]:
print(lasso.score(test_scaled, test_target))
- 라쏘의 테스트 세트의 점수 역시 릿지만큼 좋다.
- 라쏘 역시 alpha 값을 조절할 수 있다.
In [25]:
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))
In [26]:
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이다.
In [27]:
lasso = Lasso(alpha=10)
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))
In [1]:
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:90% !important; }</style>"))
'혼자 공부하는 머신러닝 + 딥러닝' 카테고리의 다른 글
[혼공머신] 8. Stochastic Gradient Descent (0) | 2021.12.18 |
---|---|
[혼공머신] 7. Logistic Regression (0) | 2021.12.17 |
[혼공머신] 5. Linear Regression (0) | 2021.12.17 |
[혼공머신] 4. K-NN 회귀 (0) | 2021.12.17 |
[혼공머신] 3. 데이터 전처리 (0) | 2021.12.17 |