머신러닝 2: 혼공머신 3장
3장: 회귀 알고리즘과 모델 규제
k-최근접 이웃 회귀
- 정해진 클래스가 없고 오히려 임의의 수치를 반환
- 예시:
- 내년도 경제 성장률을 예측
- 배달 도착하는 시간 예측
k최근접 이웃 분류 | k-최근접 이웃 회귀 |
---|---|
샘플을 몇 개의 클래스 중 하나로 분류 | 임의의 어떤 숫자를 예측 |
샘플에 가장 가까운 샘플 k개의 새로운 샘플을 다수 클래스로 예측 | 샘플에 가장 가까운 샘플 k개의 수치의 평균을 구하여 새로운 샘플의 타깃값이 그 평균으로 예측 |
데이터 준비
배열 크기 변환
- 사이킷런에 사용할 훈련 세트는 2차원 배열이어야 해서 어떤 배열은 2차원 아닌 배열인 경우 2차원으로 나타내야 한다.
즉:
넘파이 reshape() 메서드를 이용하여 어떤 배열의 크기를 바꿀 수 있다.
1 2 3 4 5
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)를 출력
- reshape(-1, 1)를 이용하여 크기를 자동으로 지정할 수 있다
- -1는 나머지 원소 개수로 모두 채우라는 의미
- 1는 2번째 크기를 1로 지정함
1 2 3
train_input = train_input.reshape(-1, 1) test_input = test_input.reshape(-1, 1) print(train_input.shape, test_input.shape) # (42, 1) (14, 1)를 출력
- reshape(-1, 1)를 이용하여 크기를 자동으로 지정할 수 있다
결정계수 ($\mathsf{R}^2$)
- 사이킷런에서 KNeighborsClassifier와 비슷한 k-최근접 이웃 회귀 알고리즘을 구현하는 KNeighborsRegressor라는 클래스가 있다.
1
2
3
4
5
6
7
8
from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor()
# k-최근접 이웃 회귀 모델을 훈련한다
knr.fit(train_input, train_target)
print(knr.score(test_input, test_target)) # 0.9928....를 출력
knr.score()가 출력된 점수는 졍정계수(coefficient of determination(또는 $\mathsf{R}^2$))라고 부른다. 계산 방식은 아래와 같다.
\[R^2 = 1 - \frac{(타깃 - 예측)^2}{(타깃 - 평균)^2}\]- 만약 타깃의 평균 정도를 예측하는 수준이라면 $\mathsf{R}^2$는 0에 가까워지고 타깃이 예측에 아주 가까워지면 1에 가까운 값이 됩니다.
정확도처럼 $\mathsf{R}^2$가 직감적으로 얼마나 좋은지 이해하기는 어려워 타깃과 예측한 값 사이의 차이를 구해 보면 어느 정도 예측이 벗어났는지 가늠하기 좋다.
- 사이킷런의 sklearn.metrics 패키지가 제공하는 mean_absolute_error는 타깃과 예측의 절대값 오차를 평균하여 반환한다.
1
2
3
4
5
6
7
8
from sklearn.metrics import mean_absolute_error
# 테스트 세트에 대한 예측을 만든다
test_prediction = knr.predict(test_input)
# 테스트 세트에 대한 평균 절댓값 오차를 계산한다
mae = mean_absolute_error(test_target, test_prediction)
print(mae) # 19.157..... 출력
과대적합 vs. 과소적합
모델을 훈련 세트에 훈련하여 훈련 세트에 잘 맞는 모델이 만들어지므로 $\mathsf{R}^2$ 점수가 보통은 훈련 세트에서 테스트 세트에서보다 더 좋은 점수가 나온다.
과대적합 (overfitting) | 과소적합 (underfitting) |
---|---|
훈련 세트에서 점수가 굉장히 좋았지만 테스트 세트에서 점수가 굉장히 나쁘다 | 훈련 세트보다 테스트 세트의 점수가 높거나 두 점수가 모두 너무 낮다 |
훈련 세트에만 잘 맞는 모델 | 모델이 너무 단순하여 훈련 세트에 적절히 훈련되지 않는다 |
해결: 덜 복잡한 모델을 만들어야 한다 | 해결: 더 복잡한 모델을 만들어야 한다 |
k-최근접 이웃 알고리즘으로 더(아니면 덜) 복잡하는 모델을 만드는 법:
과대적합을 해결 | 과소적합을 해결 |
---|---|
개수 k를 늘리기 | 개수 k를 줄이기 |
개수 k를 높아지면 데이터 전반에 있는 일반적인 패턴을 따를 것이고 개수 k를 줄이면 훈련 세트에 있는 국지적인 패턴을 민감해질 것이다.
1
2
# 이웃의 개수를 3으로 설정한다
knr.n_neighbors = 3
선형 회귀
사이킷런은 sklearn.linear_model 패키지 아래에 LinearRegression 클래스로 선형 회귀 알고리즘을 구현할 수 있다.
- 사이킷런의 모델 클래스들은 훈련, 평가, 예측하는 메서드 이름이 모두 동일한다.
1
2
3
4
5
6
7
8
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
# 선형 회귀 모델을 훈련한다
lr.fit(train_input, train_target)
# 50cm 농어에 대해 예측한다
print(lr.predict([[50]]))
수학적으로 선형 회귀의 직선이 아래와 같이 표현할 수 있다. \(y=ax+b\)
여기서는 x는 특성이고 y는 타깃이다. 따라서 LinearRegression 클래스가 어떤 데이터에 가장 잘 맞는 a와 b를 찾고 coef_와 intercept_ 라는 속성을 이용하여 확인할 수 있다.
1
print(lr.coef_, lr.intercept_) # a, b의 값 출력
다항 회귀
- 다항식을 이용하여 특성과 타깃 사이의 관계를 나타낸다
- 비선형일 수 있는데 선형 회귀로도 표현할 수 있다
2차 다항 회귀 예시
1차 선형 회귀 비슷하는데 위에 방정식 대신에 아래의 2차 방정식으로 계산하여 예측한다. \(y = ax^2 + bx + c\) 그래프를 그려보면 아래 그래프를 나타난다.
혼공머신 교재에 있는 데이터가 1차원이므로 2차원으로 변환해야 한다. column_stack() 함수를 이용하여 1차원 데이터가 2차원으로 변환 할 수 있다
1
2
3
4
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) 출력
특성 공학과 규제
다중 회귀란?
특성 공학이란?
- 기존의 특성을 이용하여 새로운 특성을 뽑아내는 과정
데이터 준비
판다스
- 데이터 분석 라이브러리
- 데이터프레임: 판다스의 핵심 데이터 구조
- to_numpy() 메서드를 이용하여 넘파이 배열로 쉽게 바꿀 수도 있다
- read_csv() 함수를 이용하여 csv 파일을 쉽게 읽을 수 있다
1
2
3
4
import pandas as pd
df = pd.read_csv('https://bit.ly/perch_csv')
perch_full = df.to_numpy()
print(perch_full) # 넘파이 배열 출력
사이킷런의 변환하기
- 변환기: 특성을 만들거나 전처리하기 위한 클래스
1
2
3
4
5
6
from sklearn.preprocessing import PolynomialFeatures # 사이킷런 제공하는 변환기들이 중 하나
poly = PolynomialFeatures()
poly.fit([[2, 3]]) # 새롭게 만들 특성 조합을 찾는다
print(poly.transform([[2, 3]])) # 셀제로 데이터를 변환한다
# [[1. 2. 3. 4. 6. 9.]] 출력
PolynomialFeatures 클래스는 기본적으로 각 특성을 제곱한 항을 추가하고 특성끼리 서로 곱한 항을 추가한다
- 위의 예시의 경우, 2와 3을 각기 제곱한 4와 9가 추가되었다
- 2와 3을 곱한 6이 추가되었다
- $y = ax_0 + bx_1 + c*1$이므로 1이 추가되었다
- include_bias=False가 지정하면 1이 추가되지 않는다
- 사이킷런 모델은 자동으로 특성에 추가된 절편 항을 무시하므로 지정하지 않아도 됨
- include_bias=False가 지정하면 1이 추가되지 않는다
- get_feature_names() 메서드를 이용하여 특성이 각각 어떤 입력의 조합으로 만들어졌는지 알아볼 수 있다
테스트 세트를 변환:
1
test_poly = poly.transform(test_input)
degree 매개변수를 이용하여 필요한 고차항의 최개 차수를 지정할 수 있다
1
poly = PolynomialFeatures(degree=5, include_bias=False)
규제
- 머신러닝 모델이 훈련 세트에 과대적합되지 않도록 만드는 것
- 선형 회귀 모델의 경우 특성에 곱해지는 계수(또는 기울기)의 크기를 작게 만드는 일
규제를 적용하기 전에 먼저 정규화를 해야 한다.
- 사이킷런에서 제공하는 StandardScaler 클래스를 이용하여 정규화를 할 수 있다.
- 변환기의 하나이다
1 2 3 4 5 6
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)
- 계수의 절댓값을 기준으로 규제를 적용
- 아예 0으로 만들 수도 있으므로 선호하지 않는다.
- 릿지(ridge) –> 일반적으로 더 선호한다
- 이 두 모델을 사용할 때 alpha 매개변수로 규제의 양을 임의로 조절할 수 있다.
- alpha 값이 크면 규제 강도가 세져 계수 값을 더 줄이고 과소적합이 발생 가능
- alpha 값이 작으면 계수를 줄이는 역할이 줄어들고 과대적합을 극복하지 못 할 수 있다
적절한 alpha 값을 찾는 법:
위의 그래프를 보면 적절한 alpha 값은 두 그래프가 가장 가깝고 테스트 세트의 점수가 가장 높은 -1(즉 $\mathsf{10^-1=0.01}$)이다.
참고문헌: 혼자 공부하는 머신러닝 + 딥러닝