1. 회귀 알고리즘
회귀란, 분류와 구별되는 단어로 관찰된 연속형 변수들로 모형을 정하고 변숫값을 예측하고, 그 알고리즘의 적합도를 측정하는 것이다. 분류는 보통 타킷의 클래스를 구분하지만, 이 둘은 모두 정확도를 측정한다는 것에 공통점이 있다.
우리는 저번 강의 때 K-최근접 이웃 분류에 대해 배웠다. 이는 최근접 이웃들로 알고자 하는 타켓의 클래스를 분류하는 알고리즘이었다. 하지만 K-최근접 이웃 회귀 알고리즘은 이와 다르게 이웃된 값들로 타켓의 값 자체를 예측하는 알고리즘이다.
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(perch_legth, 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()
knr.score(test_input, test_target)
knr.score(test_input, test_target)
from sklearn.metrics import mean_absolute_error
test_prediction = knr.predict(test_input)
mae = mean_absolute_error(test_target, test_prediction)
print(mae)
위 코드는 훈련 세트를 준비한 뒤, K-최근접 이웃 회귀 알고리즘의 모델을 훈련한 코드이다. 여기서 이제 "R2 = 1 - (타겟 - 예측)2의 합/(타깃 - 평균)2의 합"이라는 식을 얻을 수 있다. 여기서 R2은 결정 계수를 뜻하는데 보통 타킷 - 예측의 합보단 타킷 - 평균의 합이 더 크기 때문에 이 값은 0과 1사이에 존재한다.
여기서 얻은 결정계수로 과대 적합과 과소적합을 알 수 있는데, 위 코드 중
knr.score(train_input, train_target)
를 확인 할 수 있을 것이다. 이 수가 바로 결정 계수를 얻는 코드인데, 여기서 나온 수로 과대적합과 과소적합 여부를 확인할 수 있는 것이다. 보통 이웃의 개수가 적을수록 비교하고 예측할 수 있는 샘플의 수가 적어지므로 과대적합이 나타난다. 반대로 이웃의 개수가 너무 많아 하나의 수만 얻을 수 있기에 과소적합이 나타난다. 이 때문에 과소적합과 과대적합의 중간을 잘 찾아 알고리즘을 짜는 것이 중요하다. 나중에 나오겠지만 과대적합과 과소적합을 해소하기 위해 규제라는 것을 하게 될 것이다.
방금 전과 같은 K-최근접 이웃 회귀 알고리즘은 하나의 문제점을 가지고 있다. 바로 범위가 일정 수준(x축과 y축의 범위)으로 정해져 있다는 것이다. 즉, 이는 이 범위에 들지 않는 튄 타깃의 값을 예측하지 못한다는 말이 된다. 이 때문에 선형 회귀 알고리즘이 필요한 것이다. 선형 알고리즘은 하나의 선(혹은 곡선)으로 값들을 연결지어 나타낸 것이다. 이로 인해 선 내외에 있는 값들도 어느정도 예측이 가능해지고 일정 수준을 넘은 타깃의 값도 예측가능해지는 것이다.
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(train_input, train_target)
print(lr.predict([50]))
[1241.83860323]
print(lr.coef_, lr.intercept_)
[39.01714496] -709.0186449535477
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='^')
print(lr.score(train_poly, train_target))
print(lr.score(test_poly, test_target))
from sklearn.preprocessing import PolynomialFeatures
degree = 2
poly = PolynomialFeatures()
poly.fit([[2, 3]])
print(poly.transform([2, 3]))
[[1. 2. 3. 4. 6. 9.]]
위 코드는 선형 회귀 알고리즘을 다항 특성을 만들어서 만든 코드이다. 여기서 훈련 세트를 대입해보면 -144.40579242684848이라는 값을 얻을 수 있는데, 이는 과대적합이다. 이 때문에 우리는 규제라는 작업으로 완화해야 한다.
2. 규제
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))
위 코드는 규제 전 거쳐야 하는 표쥰화 작업을 끝내고 릿지 회귀 이용하여 규제를 진행하였다. 릿지 규제는 가중치(기울기)에 제곱하여 구하는 L2규제를 이용한다.
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라는 변수 안에 가중치를 넣고 for문을 이용하여 하나하나 대입해본 결과 0.1이 가장 과대적합에서 벗어난 값이라는 알아냈다.
from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(train_scaled, train_target)
lasso.score(train_scaled, train_target)
lasso.score(test_scaled, test_target)
위 코드는 가중치에 절댓값을 걸어 만드는 L1 규제를 체택하는 라쏘 회귀 알고리즘이다.