- 해당 자료는 파이썬 머신러닝 완벽가이드 공부를 위한 필사본입니다.
Chapter 05. 회귀
01. 회귀 소개
- 회귀는 현대 통계학을 이루는 큰 축
- 회귀 분석은 유전적 특성을 연구하던 영국의 통계학자 갈톤이 수행한 연구에서 유래했다는 것이 일반론
< 회귀에 대한 예시>
“부모의 키가 크더라도 자식의 키가 대를 이어 무한정 커지지 않으며, 부모의 키가 작더라도 대를 이어 자식의 키가 무한정 작아지지 않는다”
즉, 회귀 분석은 이처럼 데이터 값이 평균과 같은 일정한 값으로 돌아가려는 경향을 이용한 통계학 기법이다.
[출처 : 인프런]
ㅡ> X는 피처값(속성)
ㅡ> Y는 결정값
회귀는 회귀 계수의 선형/비선형 여부,
독립변수의 개수, 종속변수의 개수에 따라 여러 가지 유형으로 나눌 수 있다. 회귀에서 가장 중요한 것은 바로 회귀 계수이다 이 회귀 계수가 선형이냐 아니냐에 따라 선형 회귀와 비선형 회귀로 나눌 수 있다. 그리고 독립변수의 개수가 한 개인지 여러 개인지에 따라 단일 회귀, 다중 회귀로 나뉘게 된다.
독립변수 개수 | 회귀계수의 결합 |
---|---|
1개:단일 회귀 | 선형:선형 회귀 |
여러 개:다중 회귀 | 비선형:비선형 회귀 |
<회귀 유형 구분> |
지도학습은 두 가지 유형으로 나뉘는데, 바로 분류와 회귀이다. 이 두 가지 기법의 가장 큰 차이는 분류는 예측값이 카테고리와 같은 이산형 클래스 값이고 회귀는 연속형 숫자 값이라는 것입니다.
여러 가지 회귀 중에서 선형 회귀가 가장 많이 사용된다. 선형 회귀는 실제값과 예측값의 차이(오류의 제곱 값)를 최소화하는 직선형 회귀선을 최적화하는 방식이다. 선형 회귀 모델은 규제 방법에 따라 다시 별도의유형으로 나뉠 수 있다. 규제는 일반적인 선형 회귀의 과적합 문제를 해결하기 위해서 회귀 계수에 패널티값을 적용하는 것을 말한다.
- 대표적인 선형 회귀모델
- 일반 선형 회귀: 예측값과 실제값의 RSS(Residual Sum of Squares)를 최소화할 수 있도록 회귀 계수를 최적화하며 규제(Regularization)
- 릿지(Ridge): 릿지 회귀는 선형 회귀에 L2 규제를 추가한 회귀 모델, 릿지 회귀는 L2 규제를 적용하는데 L2 규제는 상대적으로 큰 회귀 계수 값의 예측 영향도를 감소시키기 위해서 회귀 계수값을 더 작게 만드는 규제 모델
- 라쏘(Lasso): 라쏘 회귀는 선형 회귀에 L1 규제를 적용한 방식, L2 규제가 회귀 계수 값의 크기를 줄이는데 반해 L1규제는 예측 영향력이 작은 피처의 회귀 계수를 0으로 만들어 회귀 예측시 피처가 선택되지 않게 함 → 이러한 특성 때문에 L1 규제는 피처 선택 가능으로도 불림
- 엘라스틱넷(ElasticNet): L2,L1 규제를 함께 결합한 모델, 주로 피처가 많은 데이터 세트에서 적용되며 L1규제로 피처의 개수를 줄임과 동시에 L2 규제로 계수 값의 크기를 조정
- 로지스틱 회귀(Logistic Regression): 로지스틱 회귀는 회귀라는 이름이 붙어 있지만 사실은 분류에 사용되는 선형 모델, 로지스틱 회귀는 매우 강력한 분류 알고리즘이며 일반적으로 이진 분류뿐만 아니라 희소 영역의 분류, 예를 들어 텍스트 분류와 같은 영역에서 뛰어난 예측성능을 보임
02. 단순선형 회귀를 통한 회귀 이해
단순선형회귀는 독립변수도 하나 종속변수도 하나인 선형 회귀이다.
- 예시
주택가격이 주택의 크기로만 결정된다고 할때 일반적으로 주택의 크기가 크면 가격이 높아지는 경향이 있기 때문에 주택가격은 크기에 대해 선형(직선형태)의 관계로 표현할 수 있다.
[출처: 인프라]
- 오류합 계산 방법
- 절대값을 취하여 더하는 방식
- 오류값의 제곱을 구해서 더하는 방식(RSS)
일반적으로 미분 등의 계산을 편리하게 하기 위해서 RSS방식으로 오류합을 구한다
즉, Error^2 = RSS
- RSS는 이제 변수가 w0,w1인 식으로 표현 할 수 있으며 RSS를 최소로 하는 w0,w1 즉 회귀 계수를 학습을 통해서 찾는 것이 머신러닝 기반 회귀의 핵심 사항이다.
- RSS는 회귀식의 독립변수 X, 종속변수 Y가 중심 변수가 아니라 w 변수(회귀계수)가 중심 변수임을 인지하는 것이 매우 중요(학습 데이터로 입력되는 독립변수와 종속변수는 RSS에서 모두 상수로 간주한다.)
[출처 : 인프라]
03. 비용 최소화하기 - 경사 하강법(Gradient Descent)
W 파라미터의 개수가 적다면 고차원 방정식으로 비용 함수가 최소가 되는 W 변숫값을 도출할 수 있겠지만 W 파라미터가 많으면 고차원 방정식을 동원하더라도 해결하기가 어렵다. 경사 하강법은 이러한 고차원 방정식에 대한 문제를 해결해 주며서 비용 함수 RSS를 최소화하는 방법을 직관적으로 제공하는 뛰어난 방식이다.
[출처 : 인프라]
- 경사 하강법은 반복적으로 비용 함수의 반환 값, 즉 예측값과 실제값의 차이가 작아지는 방향성을 가지고 W 파라미터를 지속해서 보정해 나간다.
- 최초 오류 값이 100이었다면 두 번째 오류 값은 100보다 작은 90, 세 번째는 80과 같은 방식으로 지속해서 오류를 감소시키는 방향으로 W 값을 계속 업데이트해 나간다.
- 그리고 오류 값이 더 이상 작아지지 않으면 그 오류 값을 최소 비용으로 판단하고 그때의 W 값을 최적 파라미터로 반환한다.
경사 하강법의 핵심: “어떻게 하면 오류가 작아지는 방향으로 W 값을 보정할 수 있을까?”
[출처 : 인프런]
[출처 : 인프런]
- 경사 하강법 수행 프로세스
- 실제값을 Y=4X+6 시뮬레이션하는 데이터 값 생성
1 | import numpy as np |
<matplotlib.collections.PathCollection at 0x1d01316fdc0>
1 | X.shape, y.shape # 100개의 데이터를 다 가지고 있다는 것을 알 수 있다. |
((100, 1), (100, 1))
- w0과 w1의 값을 최소화 할 수 있도록 업데이트 수행하는 함수 생성.
예측 배열 y_pred는 np.dot(X, w1.T) + w0 임 100개의 데이터 X(1,2,…,100)이 있다면 예측값은 w0 + X(1)w1 + X(2)w1 +..+ X(100)*w1이며, 이는 입력 배열 X와 w1 배열의 내적임.
새로운 w1과 w0를 update함
1 | # w1 과 w0 를 업데이트 할 w1_update, w0_update를 반환. |
1 | w0 = np.zeros((1,1)) |
(100, 1)
(1, 1) (1, 1)
(array([[0.]]), array([[0.]]))
반복적으로 경사 하강법을 이용하여 get_weigth_updates()를 호출하여 w1과 w0를 업데이트 하는 함수 생성
1 | # 입력 인자 iters로 주어진 횟수만큼 반복적으로 w1과 w0를 업데이트 적용함. |
- 예측 오차 비용을 계산을 수행하는 함수 생성 및 경사 하강법 수행
1 | def get_cost(y, y_pred): |
w1:4.022 w0:6.162
Gradient Descent Total Cost:0.9935
1 | plt.scatter(X, y) |
[<matplotlib.lines.Line2D at 0x1d0132424f0>]
- 미니 배치 확률적 경사 하강법을 이용한 최적 비용함수 도출
1 | def stochastic_gradient_descent_steps(X, y, batch_size=10, iters=1000): |
1 | np.random.permutation(X.shape[0]) # 랜덤 샘플링을 임의로 가져옴 |
array([66, 71, 54, 88, 82, 12, 36, 46, 14, 67, 10, 3, 62, 29, 97, 69, 70,
93, 31, 73, 60, 96, 28, 27, 21, 19, 33, 78, 32, 94, 1, 41, 40, 76,
37, 87, 24, 23, 50, 2, 47, 20, 77, 17, 56, 64, 68, 25, 15, 22, 16,
98, 63, 92, 86, 38, 6, 57, 95, 44, 9, 42, 81, 99, 35, 84, 59, 48,
75, 65, 85, 90, 55, 43, 58, 89, 30, 80, 34, 18, 51, 49, 52, 74, 26,
45, 39, 4, 11, 53, 91, 79, 8, 0, 5, 13, 61, 72, 7, 83])
1 | w1, w0 = stochastic_gradient_descent_steps(X, y, iters=1000) |
w1: 4.028 w0: 6.156
Stochastic Gradient Descent Total Cost:0.9937
04. 사이킷런 LinearRegression 클래스
1 | class sklearn.linear_model.LinearRegression(fit_intercept=True,normalize=False, copy_X=True, n_jobs=1) |
LnearRegression 클래스는 예측값과 실제 값의 RSS를 최소화해 OLS 추정 방식으로 구현한 클래스이다.
LinearRegression 클래스는 fit()메서드로 X,Y 배열을 입력 받으면 회귀 계수인 W를 coef_ 속성에 저장한다.
[출처 :인프런]
(1) 회귀평가 지표
- 사이킷런 회귀 평가 API
- 사이킷런은 아쉽게도 RMSE를 제공하지 않는다. RMSE를 구하기 위해서는 MSE에 제곱근을 씌워서 계산하는 함수를 직접 만들어야 한다.
- 다음은 각 평가 방법에 대한 사이킷런의 API 및 cross_val_score나 GridSearchCV에서 평가 시 사용되는 scoring 파라미터의 적용 값이다
(2) LinearRegression을 이용한 보스턴 주택 가격 예측
1 | import numpy as np |
Boston 데이타셋 크기 : (506, 14)
CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | PRICE | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.00632 | 18.0 | 2.31 | 0.0 | 0.538 | 6.575 | 65.2 | 4.0900 | 1.0 | 296.0 | 15.3 | 396.90 | 4.98 | 24.0 |
1 | 0.02731 | 0.0 | 7.07 | 0.0 | 0.469 | 6.421 | 78.9 | 4.9671 | 2.0 | 242.0 | 17.8 | 396.90 | 9.14 | 21.6 |
2 | 0.02729 | 0.0 | 7.07 | 0.0 | 0.469 | 7.185 | 61.1 | 4.9671 | 2.0 | 242.0 | 17.8 | 392.83 | 4.03 | 34.7 |
3 | 0.03237 | 0.0 | 2.18 | 0.0 | 0.458 | 6.998 | 45.8 | 6.0622 | 3.0 | 222.0 | 18.7 | 394.63 | 2.94 | 33.4 |
4 | 0.06905 | 0.0 | 2.18 | 0.0 | 0.458 | 7.147 | 54.2 | 6.0622 | 3.0 | 222.0 | 18.7 | 396.90 | 5.33 | 36.2 |
- CRIM: 지역별 범죄 발생률
- ZN: 25,000평방피트를 초과하는 거주 지역의 비율
- NDUS: 비상업 지역 넓이 비율
- CHAS: 찰스강에 대한 더미 변수(강의 경계에 위치한 경우는 1, 아니면 0)
- NOX: 일산화질소 농도 (자동차에서 나오는 질소산화물로 탄화수소 만나면 오존층 파괴, 기관지에 안 좋음)
- RM: 거주할 수 있는 방 개수
- AGE: 1940년 이전에 건축된 소유 주택의 비율
- DIS: 5개 주요 고용센터까지의 가중 거리
- RAD: 고속도로 접근 용이도
- TAX: 10,000달러당 재산세율
- PTRATIO: 지역의 교사와 학생 수 비율
- B: 지역의 흑인 거주 비율
- LSTAT: 하위 계층의 비율
- MEDV: 본인 소유의 주택 가격(중앙값)
- 각 컬럼별로 주택가격에 미치는 영향도 조사
1 | # 2개의 행과 4개의 열을 가진 subplots를 이용. axs는 4x2개의 ax를 가짐. |
결과 해석
다른 칼럼보다 RM과 LSTAT의 PRICE 영향도가 가장 두드러지게 나타남
RM(방 개수)은 양방향의 선형성이 가장 크다
→ 방의 크기가 클수록 가격이 증가함LSTAT는 음방향의 선형성이 가장 큼
→ LSTAT이 적을수록 PRICE가 증가함
- LinearRegression 클래스로 보스턴 주택 가격의 회귀 모델 만들기
1 | from sklearn.model_selection import train_test_split |
MSE : 17.297 , RMSE : 4.159
Variance score : 0.757
1 | # 절편과 회귀 계수 값 보기 |
절편 값: 40.995595172164585
회귀 계수값: [ -0.1 0.1 0. 3. -19.8 3.4 0. -1.7 0.4 -0. -0.9 0.
-0.6]
1 | # coef_ 속성은 회귀 계수 값만 가지고 있어, 이를 피처별 회귀 계수 값으로 재 매핑 |
RM 3.4
CHAS 3.0
RAD 0.4
ZN 0.1
B 0.0
TAX -0.0
AGE 0.0
INDUS 0.0
CRIM -0.1
LSTAT -0.6
PTRATIO -0.9
DIS -1.7
NOX -19.8
dtype: float64
- 결과 해석
- RM이 양의 값으로 회귀 계수가 가장 큼
- NOX 피처의 회귀 계수 - 값이 너무 커보임
→ 최적화를 수행하면서 피처 codfficients의 변화 살필 예정
- 5개의 폴드 세트에서 cross_val_score()로 교차 검증하기: MSE, RMSE 측정
사이킷런은 cross_val_score()를 이용하는데, RMSE를 제공하지 않으므로 MSE 수치 결과를 RMSE로 변환해야 한다. cross_val_score()의 인자로 scoring=’neg_mean_squared_error’를 지칭하면 반환되는 수치 값은 음수이다. 사이킷런은 높은 지표 값일수록 좋은 모델로 평가히는데 반해, 회귀는 MSE 값이 낮을수록 좋은 회귀 모델로 평가한다.
1 | from sklearn.model_selection import cross_val_score |
5 folds 의 개별 Negative MSE scores: [-12.46 -26.05 -33.07 -80.76 -33.31]
5 folds 의 개별 RMSE scores : [3.53 5.1 5.75 8.99 5.77]
5 folds 의 평균 RMSE : 5.829
- 결과 해석
- 5개 폴드 세트 교차 검증 수행 결과, 평균 RMSE는 약 5.836이 나옴
- corss_val_score(scoring=”neg_mean_squared_error”)로 반환된 값은 모두 음수로 확인됨
05. 다항 회귀, 과(대)적합/과소적합
(1) 다항 회귀 이해
- 현재까지 설명한 회귀는 y = $w_{0} + w_{1}*x_{1} + w_{2}*x_{2} + , … , + w_{n}*x_{n}$과 같이 독립변수(feature)와 종속변수(target) 관계가 일차 방정식 형태로 표현된 회귀
- 세상의 모든 관계를 직선으로만 표현할 수 없기 때문에 다항 회귀 개념이 필요
- 다항(Polynomial) 회귀: 회귀가 독립변수의 단항식이 아닌 2차, 3차 방정식과 같은 다항식으로 표현되는 것
- y = $w_{0} + w_{1}*x_{1} + w_{2}*x_{2} + w_{3}*x_{1}*x_{2} + w_{4}*x_{1}^{2} + w_{5}*x_{2}^{2}$
- 다항 회귀는 선형 회귀(비선형 회귀가 아님)
- cf) 회귀에서 선형/비선형을 나누는 기준은 회귀 계수가 선형/비선형인지에 따른 것으로, 독립변수의 선형/비선형 여부와는 무관함
- 사이킷런은 다항 회귀를 위한 클래스를 명시적으로 제공하지 않아, 비선형 함수를 선형 모델에 적용시키는 방법으로 구현
- PolynomialFeatures 클래스로 피처를 다항식 피처로 변환함
1 | from sklearn.preprocessing import PolynomialFeatures |
일차 단항식 계수 feature:
[[0 1]
[2 3]]
변환된 2차 다항식 계수 feature:
[[1. 0. 1. 0. 0. 1.]
[1. 2. 3. 4. 6. 9.]]
- 3차 다항 회귀 함수를 임의로 설정하고 회귀 계수 예측하기
1 | def polynomial_func(X): |
일차 단항식 계수 feature:
[[0 1]
[2 3]]
[0 2]
[1 3]
삼차 다항식 결정값:
[ 5 125]
- 일차 단항식 계수를 삼차 다항식 계수로 변환하고, 선형 회귀에 적용
1 | # 3 차 다항식 변환 |
3차 다항식 계수 feature:
[[ 1. 0. 1. 0. 0. 1. 0. 0. 0. 1.]
[ 1. 2. 3. 4. 6. 9. 8. 12. 18. 27.]]
Polynomial 회귀 계수
[0. 0.18 0.18 0.36 0.54 0.72 0.72 1.08 1.62 2.34]
Polynomial 회귀 Shape : (10,)
- 결과 해석
- 일차 단항식 계수 피처는 2개였지만, 3차 다항식 Polynomial 변환 이후에는 다항식 계수 피처가 10개로 늘어남
- 늘어난 피처 데이터 세트에 LinearRegression을 통해 3차 다항 회귀 형태의 다항 회귀를 적용하면 회귀 계수가 10개로 늘어남
- 10개의 회귀 계수가 도출됐으며 원래 다항식 계수 값과는 차이가 있지만, 다항 회귀로 근사함을 알 수 있음
- 사이킷런의 Pipeline 객체를 이용해 한 번에 다항 회귀 구현하기
1 | from sklearn.preprocessing import PolynomialFeatures |
Polynomial 회귀 계수
[0. 0.18 0.18 0.36 0.54 0.72 0.72 1.08 1.62 2.34]
(2) 다항 회귀를 이용한 과소적합 및 과적합 이해
- 다항 회귀는 피처의 직선적 관계가 아닌, 복잡한 다항 관계를 모델링할 수 있음
- 다항식 차수가 높아질수록 매우 복잡한 피처 관계까지 모델링이 가능함
- 단, 다항 회귀의 차수(degree)를 높일수록 학습 데이터에 너무 맞춘 학습이 이루어져서 테스트 데이터 환경에서 예측 정확도가 떨어짐
→ 차수가 높아질수록 과적합 문제가 크게 발생
- 다항 회귀의 과소적합과 과적합 문제를 잘 보여주는 예시
- 원본
- 소스코드 설명
- 피처 X와 target y가 잡음(Noise)이 포함된 다항식의 코사인 그래프 관계를 가지게 만듦
- 이에 기반해 다항 회귀의 차수를 변화시키며 그에 따른 회귀 예측 곡선과 예측 정확도를 비교하는 예제
- 학습 데이터: 30개의 임의 데이터 X, X의 코사인 값에서 약간의 잡음 변동 값을 더한 target
1 | import numpy as np |
- 예측 결과를 비교할 다항식 차수를 각각 1, 4, 15로 변경하며 예측 결과 비교하기
- 다항식 차수별로 학습 수행 후, cross_val_score()로 MSE 값을 구해 차수별 예측 성능 평가
- 0부터 1까지 균일하게 구성된 100개의 테스트용 데이터 세트로 차수별 회귀 예측 곡선 그리기
1 | plt.figure(figsize=(14, 5)) |
Degree 1 회귀 계수는 [-2.] 입니다.
Degree 1 MSE 는 0.41 입니다.
Degree 4 회귀 계수는 [ 0. -18. 24. -7.] 입니다.
Degree 4 MSE 는 0.04 입니다.
Degree 15 회귀 계수는 [-2.98300000e+03 1.03899000e+05 -1.87416100e+06 2.03716240e+07
-1.44873341e+08 7.09315840e+08 -2.47066022e+09 6.24561781e+09
-1.15676672e+10 1.56895187e+10 -1.54006300e+10 1.06457475e+10
-4.91378589e+09 1.35919961e+09 -1.70381209e+08] 입니다.
Degree 15 MSE 는 182594790.08 입니다.
- 실선: 다항 회귀 예측 곡선
- 점선: 실제 데이터 세트 X, Y의 코사인 곡선
- 학습 데이터: 0부터 1까지 30개의 임의 X값과 그에 따른 코사인 Y값에 잡음을 변동 값으로 추가해 구성
- MSE(Mean Squared Error) 평가: 학습 데이터를 10개의 교차 검증 세트로 나누어 측정한 후 평균한 것
결과 해석
Degree 1 예측 곡선
- 단순한 직선으로 단순 선형 회귀와 동일
- 실제 데이터 세트인 코사인 데이터 세트를 직선으로 예측하기에는 너무 단순함
- 예측 곡선이 학습 데이터 패턴을 반영하지 못하는 과소적합 모델
- MSE값: 약 0.407
Degree 4 예측 곡선
- 실제 데이터 세트와 유사한 모습
- 변동하는 잡음까지는 예측하지 못했지만, 학습 데이터 세트를 비교적 잘 반영해 코사인 곡선 기반으로 테스트 데이터를 잘 예측한 곡선을 가진 모델
- MSE값: 0.043 (가장 뛰어난 예측 성능 = well-fit)
Degree 15 예측 곡선
- MSE값이 182815432이 될 정도로 이상한 오류 값 발생(과적합 강조를 위해 만든 예측 곡선)
- 데이터 세트의 변동 잡음까지 지나치게 반영한 결과, 예측 곡선이 학습 데이터 세트만 정확히 예측하고 테스트 값의 실제 곡선과는 완전히 다른 형태의 예측 곡선이 만들어짐
- 학습 데이터에 너무 충실하게 맞춘 심한 과적합 모델
- 결론
- 좋은 예측 모델은 학습 데이터 패턴을 잘 반영하면서도 복잡하지 않은, 균형 잡힌(Balanced) 모델을 의미
(3) 편향-분산 트레이드 오프
머신러닝이 극복해야 할 이슈
고편향(High Bias)성
- Degree 1 모델처럼 매우 단순화된 모델로서 지나치게 한 방향성으로 치우친 경향을 보임
고분산(High Variance)성
- Degree 15 모델처럼 학습 데이터 하나하나 특성을 반영하여 매우 복잡하고 지나치게 높은 변동성을 가짐
- 일반적으로 편향과 분산은 한 쪽이 높으면, 한 쪽이 낮아지는 경향이 있음
→ 편향이 높으면 분산이 낮아지고(과소적합), 분산이 높으면 편향이 낮아짐(과적합)
- 편향과 분산 관계에 따른 전체 오류 값(Total Error) 변화
- 이미지 출처
- 편향이 너무 높으면 전체 오류가 높음
- 편향을 낮출수록 분산이 높아지고 전체 오류도 낮아짐
- 골디락스: 편향을 낮추고 분산을 높이며, 전체 오류가 가장 낮아지는 지점
- 골디락스 지점을 통과하며 분산을 지속적으로 높이면 전체 오류 값이 오히려 증가하며 예측 성능이 다시 저하됨
- 정리
- 과소적합: 높은 편향/낮은 분산에서 일어나기 쉬움
- 과적합: 낮은 편향/높은 분산에서 일어나기 쉬움
→ 편향과 분산이 트레이드 오프를 이루며 오류 cost 값이 최대로 낮아지는 모델을 구축하는 것이 중요
06. 규제 선형 모델: 릿지, 라쏘, 엘라스틱넷
(1) 규제 선형 모델의 개요
- 이전까지의 선형 모델 비용 함수는 RSS를 최소화하는(실제값과 예측값의 차이를 최소화하는) 것만 고려
- 학습 데이터에 지나치게 맞추게 되고, 회귀 계수가 쉽게 커지는 문제가 발생
- 변동성이 오히려 심해져 테스트 데이터 세트에서 예측 성능이 저하되게 쉬움
→ 비용 함수는 학습 데이터의 잔차 오류값을 최소로 하는 RSS 최소화 방법과 과적합을 방지하기 위해 회귀 계수 값이 커지지 않도록 하는 방법이 균형을 이루어야 함
- 회귀 계수의 크기를 제어해 과적합을 개선하려면, 비용(Cost) 함수의 목표가 아래와 같이 를 최소화하는 것으로 변경될 수 있음
비용 함수 목표 =
- alpha: 학습 데이터 적합 정도와 회귀 계수 값의 크기 제어를 수행하는 튜닝 파라미터
- alpha가 0(또는 매우 작은 값)이라면 비용 함수 식은 기존과 동일한 가 됨
- alpha가 무한대(또는 매우 큰 값)이라면 비용 함수 식은 에 비해 값이 너무 커지므로 W 값을 0 또는 매우 작게 만들어야 Cost가 최소화 되는 비용 함수 목표를 달성할 수 있음 → alpha 값을 크게 하면 비용 함수는 회귀 계수 W의 값을 작게 해 과적합을 개선할 수 있으며 alpha 값을 작게 하면 회귀 계수 W의 값이 커져도 어느 정도 상쇄가 가능하므로 학습 데이터 적합을 더 개선할 수 있음
alpha를 0에서부터 지속적으로 값을 증가시키면 회귀 계수 값의 크기를 감소시킬 수 있음
규제(Regularization): 비용 함수에 alpha 값으로 패널티를 부여해 회귀 계수 값의 크기를 감소해 과적합을 개선하는 방식
규제 방식
L2 규제:
| | W | | 2 2 L1 규제:
| | W | | 1
(2) 릿지 회귀
- 사이킷런은 Ridge 클래스로 릿지 회귀를 구현
- 주요 생성 파라미터: alpha, 릿지 회귀의 alpha L2 규제 계수에 해당
- 보스턴 주택 가격을 Ridge 클래스로 예측하고, cross_val_score()로 평가하기
1 | # 앞의 LinearRegression예제에서 분할한 feature 데이터 셋인 X_data과 Target 데이터 셋인 Y_target 데이터셋을 그대로 이용 |
Boston 데이타셋 크기 : (506, 14)
5 folds 의 개별 Negative MSE scores: [-11.422 -24.294 -28.144 -74.599 -28.517]
5 folds 의 개별 RMSE scores : [3.38 4.929 5.305 8.637 5.34 ]
5 folds 의 평균 RMSE : 5.518
- 결과 해석
- 릿지의 5개 폴드 세트 평균 RMSE: 5.524
- 앞 예제(규제 없는 LinearRegression) 평균인 5.836보다 뛰어난 예측 성능을 보임
- 릿지의 alpha 값을 0, 0.1, 1, 10, 100으로 변화시키며 RMSE와 회귀 계수 값 변화 살펴보기
1 | # Ridge에 사용될 alpha 파라미터의 값들을 정의 |
alpha 0 일 때 5 folds 의 평균 RMSE : 5.829
alpha 0.1 일 때 5 folds 의 평균 RMSE : 5.788
alpha 1 일 때 5 folds 의 평균 RMSE : 5.653
alpha 10 일 때 5 folds 의 평균 RMSE : 5.518
alpha 100 일 때 5 folds 의 평균 RMSE : 5.330
- 결과 해석
- alpha가 100일 때, 평균 RMSE가 5.332로 가장 좋음
- alpha 값 변화에 따른 피처의 회귀 계수 값을 가로 막대 그래프로 시각화
1 | # 각 alpha에 따른 회귀 계수 값을 시각화하기 위해 5개의 열로 된 맷플롯립 축 생성 |
- 결과 해석
- alpha 값을 계속 증가시킬수록 회귀 계수 값은 지속적으로 작아짐
- 특히, NOX 피처의 경우 alpha 값을 계속 증가시킴에 따라 회귀 계수가 크게 작아지고 있음
- DataFrame에 저장된 alpha 값 변화에 따른 릿지 회귀 계수 값 구하기
1 | ridge_alphas = [0 , 0.1 , 1 , 10 , 100] |
alpha:0 | alpha:0.1 | alpha:1 | alpha:10 | alpha:100 | |
---|---|---|---|---|---|
RM | 3.809865 | 3.818233 | 3.854000 | 3.702272 | 2.334536 |
CHAS | 2.686734 | 2.670019 | 2.552393 | 1.952021 | 0.638335 |
RAD | 0.306049 | 0.303515 | 0.290142 | 0.279596 | 0.315358 |
ZN | 0.046420 | 0.046572 | 0.047443 | 0.049579 | 0.054496 |
INDUS | 0.020559 | 0.015999 | -0.008805 | -0.042962 | -0.052826 |
B | 0.009312 | 0.009368 | 0.009673 | 0.010037 | 0.009393 |
AGE | 0.000692 | -0.000269 | -0.005415 | -0.010707 | 0.001212 |
TAX | -0.012335 | -0.012421 | -0.012912 | -0.013993 | -0.015856 |
CRIM | -0.108011 | -0.107474 | -0.104595 | -0.101435 | -0.102202 |
LSTAT | -0.524758 | -0.525966 | -0.533343 | -0.559366 | -0.660764 |
PTRATIO | -0.952747 | -0.940759 | -0.876074 | -0.797945 | -0.829218 |
DIS | -1.475567 | -1.459626 | -1.372654 | -1.248808 | -1.153390 |
NOX | -17.766611 | -16.684645 | -10.777015 | -2.371619 | -0.262847 |
- 결과 해석
- alpha 값이 증가하며 회귀 계소가 지속적으로 작아짐
- 단, 릿지 회귀는 회귀 계수를 0으로 만들지 않음
(3) 라쏘 회귀
- 라쏘 회귀: W의 절댓값에 패널티를 부여하는 L1 규제를 선형 회귀에 적용한 것
- L1 규제는 를 의미하며, 라쏘 회귀 비용함수 목표는 RSS(W) + 식을 최소화하는 W를 찾는 것
- L2 규제가 회귀 계쑤 크기를 감소시키는 데 반해, L1 규제는 불필요한 회귀 계수를 급격히 감소시켜 0으로 만들고 제거함
- L1 규제는 적절한 피처만 회귀에 포함시키는 피처 선택의 득성을 가짐
- 사이킷런은 Lasso 클래스로 라쏘 회귀를 구현
- 주요 파라미터: alpha, 라쏘 회귀의 alpha L1 규제 계수에 해당
- Lasso 클래스로 라쏘의 alpha 값을 변화시키며 RMSE와 각 피처의 회귀 계수 출력하기
1 | from sklearn.linear_model import Lasso, ElasticNet |
1 | # 라쏘에 사용될 alpha 파라미터의 값들을 정의하고 get_linear_reg_eval() 함수 호출 |
####### Lasso #######
alpha 0.07일 때 5 폴드 세트의 평균 RMSE: 5.612
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.615
alpha 0.5일 때 5 폴드 세트의 평균 RMSE: 5.669
alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.776
alpha 3일 때 5 폴드 세트의 평균 RMSE: 6.189
- 결과 해석
- alpha가 0.07일 때, 가장 좋은 평균 RMSE를 보여줌
- alpha 값에 따른 피처별 회귀 계수
1 | # 반환된 coeff_lasso_df를 첫번째 컬럼순으로 내림차순 정렬하여 회귀계수 DataFrame출력 |
alpha:0.07 | alpha:0.1 | alpha:0.5 | alpha:1 | alpha:3 | |
---|---|---|---|---|---|
RM | 3.789725 | 3.703202 | 2.498212 | 0.949811 | 0.000000 |
CHAS | 1.434343 | 0.955190 | 0.000000 | 0.000000 | 0.000000 |
RAD | 0.270936 | 0.274707 | 0.277451 | 0.264206 | 0.061864 |
ZN | 0.049059 | 0.049211 | 0.049544 | 0.049165 | 0.037231 |
B | 0.010248 | 0.010249 | 0.009469 | 0.008247 | 0.006510 |
NOX | -0.000000 | -0.000000 | -0.000000 | -0.000000 | 0.000000 |
AGE | -0.011706 | -0.010037 | 0.003604 | 0.020910 | 0.042495 |
TAX | -0.014290 | -0.014570 | -0.015442 | -0.015212 | -0.008602 |
INDUS | -0.042120 | -0.036619 | -0.005253 | -0.000000 | -0.000000 |
CRIM | -0.098193 | -0.097894 | -0.083289 | -0.063437 | -0.000000 |
LSTAT | -0.560431 | -0.568769 | -0.656290 | -0.761115 | -0.807679 |
PTRATIO | -0.765107 | -0.770654 | -0.758752 | -0.722966 | -0.265072 |
DIS | -1.176583 | -1.160538 | -0.936605 | -0.668790 | -0.000000 |
- 결과 해석
- alpha의 크기가 증가함에 따라 일부 피처 회귀 계수는 아예 0으로 바뀜
- NOX 속성은 alpha가 0.07일 때부터 회귀 계수가 0이며, alpha를 증가시키며 INDUS, CHAS와 같은 속성 회귀 계수가 0으로 바뀜
- 회귀 계수가 0인 피처는 회귀 식에서 제외되며 피처 선택의 효과를 얻을 수 있음
(4) 엘라스틱넷 회귀
- 엘라스틱넷(Elastic Net) 회귀: L2 규제와 L1 규제를 결합한 회귀
- 엘라스틱넷 회귀 비용함수 목표: 식을 최소화하는 W를 찾는 것
- 엘라스틱넷은 라쏘 회귀가 상관관계가 높은 피처들의 경우에, 중요 피처만을 선택하고 다른 피처 회귀 계수는 0으로 만드는 성향이 강함
- alpha 값에 따라 회귀 계쑤 값이 급격히 변동할 수 있는데, 엘라스틱넷 회귀는 이를 완화하기 위해 L2 규제를 라쏘 회귀에 추가한 것
- 엘라스틱넷 회귀의 단점은 L1과 L2 규제가 결합된 규제로 인해 수행 시간이 상대적으로 오래 걸림
- 사이킷런은 Elastic Net 클래스로 엘라스틱넷 회귀를 구현
- 주요 파라미터: aplha, l1_ration
- Elastic Net 클래스의 aplha는 Ridge와 Lasso 클래스의 alpha 값과는 다름
- 엘라스틱넷 규제는 a * L1 + b * L2로 정의될 수 있으며, 이 때 a는 L1 규제의 alpha값, b는 L2 규제의 alpha 값
- 따라서 ElasticNet 클래스의 alpha 파라미터 값은 a + b 값
- ElasticNet 클래스의 l1_ratio 파라미터 값은 a / (a + b)
- l1_ratio가 0이면 a가 0이므로 L2 규제와 동일하고, l1_ratio가 1이면 b가 0이므로 L1 규제와 동일
- Elastic Net 클래스로 엘라스틱넷 alpha 값을 변화시키며 RMSE와 각 피처의 회귀 계수 출력하기
- l1_ratio를 0.7로 고정한 이유: 단순히 alpha 값의 변화만 살피기 위해
1 | # 엘라스틱넷에 사용될 alpha 파라미터의 값들을 정의하고 get_linear_reg_eval() 함수 호출 |
####### ElasticNet #######
alpha 0.07일 때 5 폴드 세트의 평균 RMSE: 5.542
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.526
alpha 0.5일 때 5 폴드 세트의 평균 RMSE: 5.467
alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.597
alpha 3일 때 5 폴드 세트의 평균 RMSE: 6.068
1 | # 반환된 coeff_elastic_df를 첫번째 컬럼순으로 내림차순 정렬하여 회귀계수 DataFrame출력 |
alpha:0.07 | alpha:0.1 | alpha:0.5 | alpha:1 | alpha:3 | |
---|---|---|---|---|---|
RM | 3.574162 | 3.414154 | 1.918419 | 0.938789 | 0.000000 |
CHAS | 1.330724 | 0.979706 | 0.000000 | 0.000000 | 0.000000 |
RAD | 0.278880 | 0.283443 | 0.300761 | 0.289299 | 0.146846 |
ZN | 0.050107 | 0.050617 | 0.052878 | 0.052136 | 0.038268 |
B | 0.010122 | 0.010067 | 0.009114 | 0.008320 | 0.007020 |
AGE | -0.010116 | -0.008276 | 0.007760 | 0.020348 | 0.043446 |
TAX | -0.014522 | -0.014814 | -0.016046 | -0.016218 | -0.011417 |
INDUS | -0.044855 | -0.042719 | -0.023252 | -0.000000 | -0.000000 |
CRIM | -0.099468 | -0.099213 | -0.089070 | -0.073577 | -0.019058 |
NOX | -0.175072 | -0.000000 | -0.000000 | -0.000000 | -0.000000 |
LSTAT | -0.574822 | -0.587702 | -0.693861 | -0.760457 | -0.800368 |
PTRATIO | -0.779498 | -0.784725 | -0.790969 | -0.738672 | -0.423065 |
DIS | -1.189438 | -1.173647 | -0.975902 | -0.725174 | -0.031208 |
- 결과 해석
- alpha 0.5일 때, RMSE가 5.468로 가장 좋은 예측 성능을 보임
- alpha 값에 따른 피처들의 회귀 계수 값이 라쏘보다는 0 되는 값이 적음
(5) 선형 회귀 모델을 위한 데이터 변환
- 선형 회귀 모델과 같은 선형 모델은 일반적으로 피처와 타겟 간에 선형의 관계가 있다 가정하고, 이러한 최적의 선형함수를 찾아내 결과를 예측
- 선형 회귀 모델은 피처값과 타겟값의 분포가 정규 분포(즉 평균을 중심으로 종 모양으로 데이터 값이 분포된 형태) 형태를 매우 선호함
- 타겟값의 경우 정규 분포 형태가 아니라 특정값의 분포가 치우친 왜곡된 형태의 분포도일 경우 예측 성능에 부정적인 영향을 미칠 가능성이 높음
- 피처값 역시 왜곡된 분포도로 인해 예측 성능에 부정적인 영향을 미칠 수 있음
- 일반적으로 선형 회귀 모델을 적용하기전에 데이터에 대한 스케일링/정규화 작업을 수행함
- 단, 스케일링/정규화 작업을 선행한다고 해서 무조건 예측 성능이 향상되는 것은 아니며 중요한 피처들이나 타겟값의 분포도가 심하게 왜곡됐을 경우에 이러한 변환 작업을 수행함
- 피처 데이터 셋과 타겟 데이터 셋에 이러한 스케일링/정규화 작업을 수행하는 방법이 다름
- 사이킷런을 이용해 피처 데이터 세트에 적용하는 방법 세 가지
StandardScaler 클래스를 이용해 평균이 0, 분산이 1인 표준 정규 분포를 가진 데이터 셋으로 변환하거나 MinMaxScaler 클래스를 이용해 최소값이 0이고 최대값이 1인 값으로 정규화를 수행
스케일링/정규화를 수행한 데이터 셋에 다시 다항 특성을 적용하여 변환하는 방법이다. 보통 1번 방법을 통해 예측 성능에 향상이 없을 경우 이와 같은 방법을 적용
원래 값에 log 함수를 적용하면 보다 정규 분포에 가까운 형태로 값이 분포(= 로그 변환)된다. 실제로 선형 회귀에서는 앞서 소개한 1,2번 방법보다 로그 변환이 훨씬 많이 사용되는 변환 방법(1번 방법: 예측 성능 향상을 크게 기대하기 어려운 경우가 많음, 2번 방법: 피처 개수가 매우 많을 경우에는 다항 변환으로 생성되는 피처의 개수가 기하급수로 늘어나서 과적합의 이슈가 발생할 수 있음)
- 타겟값의 경우 일반적으로 로그 변환을 적용
- 결정값을 정규 분포나 다른 정규값으로 변환하면 변환된 값을 다시 원본 타겟값으로 원복하기 어려울 수 있음
- 왜곡된 분포도 형태의 타겟값을 로그 변환하여 예측 성능 향상이 된 경우가 많은 사례에서 검증되었기 때문에 타겟값의 경우는 로그 변환을 적용
- 보스턴 주택가격 피처 데이터 세트에 표준 정규 분포 변환, 최댓값/최솟값 정규화, 로그 변환을 적용한 후 RMSE로 각 경우별 예측 성능 측정하기
- 사용 함수: get_scaled_data()
- method 인자로 변환 방법을 결정하며, 표준 정규 분포 변환(Standard), 최댓값/최솟값 정규와(MinMax), 로그 변환(Log) 중에 하나를 선택
- p_degree: 다항식 특성을 추가할 때, 다항식 차수가 입력됨 (2를 넘기지 않음)
- np.log1p(): log() 함수만 적용하면 언더 플로우가 발생하기 쉬워 1 + log() 함수를 적용
1 | from sklearn.preprocessing import StandardScaler, MinMaxScaler, PolynomialFeatures |
1 | # Ridge의 alpha값을 다르게 적용하고 다양한 데이터 변환방법에 따른 RMSE 추출. |
(506, 13) (506, 13)
## 변환 유형:None, Polynomial Degree:None
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.788
alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.653
alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.518
alpha 100일 때 5 폴드 세트의 평균 RMSE: 5.330
(506, 13) (506, 13)
## 변환 유형:Standard, Polynomial Degree:None
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.826
alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.803
alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.637
alpha 100일 때 5 폴드 세트의 평균 RMSE: 5.421
(506, 104) (506, 13)
## 변환 유형:Standard, Polynomial Degree:2
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 8.827
alpha 1일 때 5 폴드 세트의 평균 RMSE: 6.871
alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.485
alpha 100일 때 5 폴드 세트의 평균 RMSE: 4.634
(506, 13) (506, 13)
## 변환 유형:MinMax, Polynomial Degree:None
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.764
alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.465
alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.754
alpha 100일 때 5 폴드 세트의 평균 RMSE: 7.635
(506, 104) (506, 13)
## 변환 유형:MinMax, Polynomial Degree:2
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.298
alpha 1일 때 5 폴드 세트의 평균 RMSE: 4.323
alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.185
alpha 100일 때 5 폴드 세트의 평균 RMSE: 6.538
(506, 13) (506, 13)
## 변환 유형:Log, Polynomial Degree:None
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 4.770
alpha 1일 때 5 폴드 세트의 평균 RMSE: 4.676
alpha 10일 때 5 폴드 세트의 평균 RMSE: 4.836
alpha 100일 때 5 폴드 세트의 평균 RMSE: 6.241
- 결과 해석
- 표준 정규 분포와 최솟값/최댓값 정규화로 피처 데이터 세트를 변경해도 성능상의 개선은 없음
- 표준 정규 분포로 일차 변환 후 2차 다항식 변환 시, alpha = 100에서 4.631로 성능 개선
- 최솟값/최댓값 정규화로 일차 변환 후 2차 다항식 변환 시, aplha = 1에서 4.320으로 성능 개선
- 단, 다항식 변환은 피처 개수가 많을 경우 적용하기 힘들며, 데이터 건수가 많아지면 시간이 많이 소모되어 적용하기에 한계가 있음
- 반면, 로그 변환은 alpha가 0.1, 1, 10인 경우 모두 성능이 좋게 향상됨
- 일반적으로 선형 회귀를 적용하려는 데이터 세트에, 데이터 값 분포가 심하게 왜곡되어 있을 경우에, 로그 변환을 적용하는 편이 더 좋은 결과를 기대할 수 있음
07. 로지스틱 회귀
- 로지스틱 회귀: 선형 회귀 방식을 분류에 적용한 알고리즘 → ‘분류’에 사용
- 선형 회귀 계열이나, 선형 회귀와 다른 점은 학습을 통해 선형 함수의 회귀 최적선을 찾지 않고 시그모이드(Sigmoid) 함수 최적선을 찾고 시그모이드 함수 반환 값을 확률로 간주하여 확률에 따라 분류를 결정하는 것
시그모이드 함수
- y = $\frac{1}{1+e-x}$ (-x는 제곱)
- 시그모이드 함수는 x 값이 +, -로 아무리 커지거나 작아져도 y 값은 0과 1 사이 값만 반환
- x 값이 커지면 1에 근사하며 x 값이 작아지면 0에 근사
- x가 0일 때는 0.5
회귀 분제를 분류 문제에 적용하기
- 종양의 크기에 따라 악성 종양인지(Yes = 1), 아닌지(No = 0)를 회귀를 이용하여 1과 0 값으로 예측하는 것
- 종양 크기에 따라 악성될 확률이 높다고 하면 아래 왼쪽 그림과 같이 분포하며 선형 회귀 선을 그릴 수 있으나, 해당 회귀 라인은 0과 1을 제대로 분류하지 못함
- 오른쪽 그림처럼 시그모이드 함수를 이용하면 조금 더 정확하게 0과 1을 분류할 수 있음
- 로지스틱 회귀로 암 여부 판단하기: 위스콘신 유방암 데이터 세트 이용
1 | import pandas as pd |
1 | from sklearn.preprocessing import StandardScaler |
- 로지스틱 회귀로 학습 및 예측하고, 정확도와 ROC-AUC 값 구하기
1 | from sklearn.metrics import accuracy_score, roc_auc_score |
accuracy: 0.977
roc_auc: 0.972
- 사이킷런 LogisticRegression 클래스의 주요 하이퍼 파라미터로 penalty와 C가 존재
- penalty는 규제의 유형을 설정하며 ‘l2’로 설정 시 L2 규제를, ‘l1’으로 설정 시 L1 규제를 뜻함
- C는 규제 강도를 조절하는 alpha 값의 역수로 C = $\frac{1}{alpha}$
- C 값이 작을수록 규제 강도가 큼을 의미
- 위스콘신 데이터 세트에서 해당 하이퍼 파라미터를 최적화하기
1 | from sklearn.model_selection import GridSearchCV |
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
최적 하이퍼 파라미터:{'C': 1, 'penalty': 'l2'}, 최적 평균 정확도:0.975
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
- 로지스틱 회귀는 가볍고 빠르며, 이진 분류 예측 성능까지 뛰어남
- 이진 분류의 기본 모델로 사용하는 경우가 많음
- 로지스틱 회귀는 희소한 데이터 세트 분류에서도 뛰어난 성능을 보임
- 텍스트 분류에서도 자주 사용
08. 회귀 트리
회귀 함수를 기반으로 하지 않고, 결정 트리와 같이 트리를 기반으로 하는 회귀 방식 소개
트리 기반이 회귀: 회귀 트리를 이용하는 것
- 회귀를 위한 트리를 생성하고 이를 기반으로 회귀를 예측하는 것
- 4장 분류에서 언급한 분류 트리와 비슷하나, 리프 노트에서 예측 결정 값을 만드는 과정에 차이가 있음
- 분류 트리는 특정 클래스 레이블을 결정하나, 회귀 트리는 리프 노드에 속한 데이터 값의 평균값을 구해 회귀 예측값을 계산
- 예시(p.335-336)
- 피처가 단 하나인 X 피처 데이터 세트와 결정값 Y가 2차원 평면에 있다고 가정
- 데이터 세트의 X 피처를 결정 트리 기반으로 분할하면 X값의 균일도를 반영한 지니 계수에 따라 분할됨
- 루트 노드를 Split 0 기준으로 분할하고, 분할된 규칙 노드에서 다시 Split 1과 Split 2 규칙 노드로 분할할 수 있음
- Split 2는 다시 재귀적으로 Split 3 규칙 노드로 트리 규칙으로 변환될 수 있음
- 리프 노드 생성 기준에 부합하는 트리 분할이 완료됐다면, 리프 노드에 소속된 데이터 값의 평균값을 구해 최종적으로 리프 노드에 결정 값으로 할당함
- 사이킷런 트리 기반 회귀와 분류의 Estimator 클래스
알고리즘 | 회귀 Estimator 클래스 | 분류 Estimator 클래스 |
---|---|---|
Decision Tree | DecisionTreeRegressor | DecisionTreeClassifier |
Gradient Boosting | GradientBoostingRegressor | GradientBoostingClassifier |
XGBoost | XGBRegressor | XGBClassifier |
LightGBM | LGBMRegressor | LGBMClassifier |
- 사이킷런 랜덤 포레스트 회귀 트리인 RandomForestRegressor로 보스턴 주택 가격 예측 수행하기
1 | from sklearn.datasets import load_boston |
5 교차 검증의 개별 Negative MSE scores: [ -7.88 -13.14 -20.57 -46.23 -18.88]
5 교차 검증의 개별 RMSE scores : [2.81 3.63 4.54 6.8 4.34]
5 교차 검증의 평균 RMSE : 4.423
- 결정 트리, GBM, XGBoost, LightGBM의 Regressor을 모두 이용해 보스턴 주택 가격 예측 수행
- 사용 함수: get_model_cv_prediction()
- 입력 모델과 데이터 세트를 입력 받아, 교차 검증으로 평균 RMSE를 계산하는 함수
1 | def get_model_cv_prediction(model, X_data, y_target): |
- 다양한 유형의 회귀 트리를 생성하고, 보스턴 주택 가격 예측하기
1 | from sklearn.tree import DecisionTreeRegressor |
##### DecisionTreeRegressor #####
5 교차 검증의 평균 RMSE : 5.978
##### RandomForestRegressor #####
5 교차 검증의 평균 RMSE : 4.423
##### GradientBoostingRegressor #####
5 교차 검증의 평균 RMSE : 4.269
##### XGBRegressor #####
5 교차 검증의 평균 RMSE : 4.251
##### LGBMRegressor #####
5 교차 검증의 평균 RMSE : 4.646
- feature_importances_를 이용해 보스턴 주택 가격 모델의 피처별 중요도 시각화하기
- 회귀 트리 Regressor 클래스는 선형 회귀와 다른 처리 방식으로, 회귀 계수를 제공하는 coef_ 속성이 없으나, feature_importances_를 이용해 피처별 중요도를 알 수 있음
1 | import seaborn as sns |
<matplotlib.axes._subplots.AxesSubplot at 0x1d019a2c850>
- 회귀 트리 Regressor가 예측값을 판단하는 방법을 선형 회귀와 비교하여 시각화하기
- 보스턴 데이터 세트를 100개만 샘플링하고 RM과 PRICE 칼럼만 추출
- 2차원 평면상에서 X축에 독립변수인 RM, Y축에 종속변수인 PRICE만 가지고 더 직관적으로 예측값을 시각화하기 위한 것
1 | import matplotlib.pyplot as plt |
(100, 2)
<matplotlib.collections.PathCollection at 0x1d01ef6b520>
- LinearRegression과 DecisionTreeRegressor를 max_depth 2, 7로 학습하기
1 | import numpy as np |
1 | fig , (ax1, ax2, ax3) = plt.subplots(figsize=(14,4), ncols=3) |
[<matplotlib.lines.Line2D at 0x1d01f029910>]
- 정리
- 선형 회귀: 예측 회귀선을 직선으로 표현
- 회귀 트리: 분할되는 데이터 지점에 따라 브랜치를 만들며 계단 형태로 회귀선을 만듦
- DecisionTreeRegressor의 max_depth = 7인 경우, 학습 데이터 세트의 이상치(outlier) 데이터도 학습하면서 복잡한 계단 형태의 회귀선을 만들어 과적합 되기 쉬운 모델이 됨
09. 회귀 실습- 자전거 대여 수요 예측
- 데이터 설명
- 기간: 2011년 1월 - 2012년 12월
- 날짜/시간, 기온, 습도, 풍속 등 정보
- 1시간 간격으로 자전거 대여 횟수 기록
- 데이터의 주요 칼럼 (결정값: count)
- datetime: hourly date + timestamp
- season: 1 = 봄, 2 = 여름, 3 = 가을, 4 = 겨울
- holiday: 1= 토/일요일의 주말 제외한 국경일 등의 휴일, 0 = 휴일 아닌 날
- workingday: 1 = 토/일요일의 주말 및 휴일이 아닌 주중, 0 = 주말 및 휴일
- weather: 1 = 맑음, 약간 구름 낀 흐림, 2 = 안개, 안개 + 흐림, 3 = 가벼운 눈, 가벼운 비 + 천둥, 4 = 심한 눈/비, 천둥/번개
- temp: 온도(섭씨)
- atemp: 체감온도(섭씨)
- humidity: 상대습도
- windspeed: 풍속
- casual: 사전 등록되지 않은 사용자 대여 횟수
- registered: 사전 등록된 사용자 대여 횟수
- count: 대여 횟수 (casual + registered)
(1) 데이터 클렌징 및 가공
- bike_train.csv 데이터 세트로 모델을 학습한 후, 대여 횟수(count) 예측
1 | import numpy as np |
(10886, 12)
datetime | season | holiday | workingday | weather | temp | atemp | humidity | windspeed | casual | registered | count | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2011-01-01 00:00:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 81 | 0.0 | 3 | 13 | 16 |
1 | 2011-01-01 01:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0 | 8 | 32 | 40 |
2 | 2011-01-01 02:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0 | 5 | 27 | 32 |
1 | # 데이터 타입 살펴보기 |
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10886 entries, 0 to 10885
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 datetime 10886 non-null object
1 season 10886 non-null int64
2 holiday 10886 non-null int64
3 workingday 10886 non-null int64
4 weather 10886 non-null int64
5 temp 10886 non-null float64
6 atemp 10886 non-null float64
7 humidity 10886 non-null int64
8 windspeed 10886 non-null float64
9 casual 10886 non-null int64
10 registered 10886 non-null int64
11 count 10886 non-null int64
dtypes: float64(3), int64(8), object(1)
memory usage: 1020.7+ KB
- 데이터 타입 확인
- Null 데이터 없음
- datetime 칼럼만 object형, 년-월-일 시:분:초 형식 가공 필요
1 | # 문자열을 datetime 타입으로 변경. |
datetime | season | holiday | workingday | weather | temp | atemp | humidity | windspeed | casual | registered | count | year | month | day | hour | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2011-01-01 00:00:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 81 | 0.0 | 3 | 13 | 16 | 2011 | 1 | 1 | 0 |
1 | 2011-01-01 01:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0 | 8 | 32 | 40 | 2011 | 1 | 1 | 1 |
2 | 2011-01-01 02:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0 | 5 | 27 | 32 | 2011 | 1 | 1 | 2 |
1 | # datetime 삭제 |
- 다양한 회귀 모델을 데이터 세트에 적용해 예측 성능 측정하기
- 캐글에서 요구한 성능 평가 방법은 RMSLE(Root Mean Square Log Error)로 오류 값 로그에 대한 RMSE
- 단, 사이킷런은 RMSLE를 제공하지 않아 RMSLE를 수행하는 성능 형가 함수를 만들어야 함
1 | from sklearn.metrics import mean_squared_error, mean_absolute_error |
(2) 로그 변환, 피처 인코딩, 모델 학습/예측/평가
- 회귀 모델을 이용해 자전거 대여 횟수 예측하기
- 먼저, 결괏값이 정규 분포로 되어 있는지 확인해야 함
- 카테고리형 회귀 모델은 원-핫 인코딩으로 피처를 인코딩해야 함
- 사이킷런의 LinearRegression 객체로 회귀 예측하기
1 | from sklearn.model_selection import train_test_split , GridSearchCV |
RMSLE: 1.165, RMSE: 140.900, MAE: 105.924
- 결과 해석
- 실제 Target 데이터 값인 대여 횟수(Count)를 감안하면 예측 오류로서는 비교적 큰 값
- 실제값과 예측값이 어느 정도 차이 나는지 DataFrame 칼럼으로 만들어서 오류 값이 가장 큰 순으로 5개만 확인하기
1 | def get_top_error_data(y_test, pred, n_tops = 5): |
real_count predicted_count diff
1618 890 322.0 568.0
3151 798 241.0 557.0
966 884 327.0 557.0
412 745 194.0 551.0
2817 856 310.0 546.0
- 결과 해석
- 가장 큰 상위 5 오류값은 546 - 568로 실제값을 감안하면 오류가 꽤 큼
- 회귀에서 큰 예측 오류가 발생할 경우, Target 값의 분포가 왜곡된 형태를 이루는지를 확인해야 함
- Target 값 분포는 정규 분포 형태가 가장 좋으며, 왜곡된 경우에는 회귀 예측 성능이 저하되는 경우가 쉽게 발생
- 판다스 DataFrame의 hist()를 이용해 자전거 대여 모델의 Target 값인 count 칼럼이 정규 분포를 이루는지 확인하기
1 | y_target.hist() |
<matplotlib.axes._subplots.AxesSubplot at 0x1d0203fafd0>
- 결과 해석
- count 칼럼 값이 정규 분포가 아닌, 0 - 200 사이에 왜곡된 것을 알 수 있음
- 왜곡된 값을 정규 분포 형태로 바꾸는 방법: 로그를 적용해 변환하는 것
- Numpy의 log1p()이용
- 변경된 Target 값을 기반으로 학습하고, 예측한 값은 expm1() 함수를 이용해 원래의 scale 값으로 원상 복구
- lop1p()를 적용한 ‘count’값이 분포 확인하기
1 | y_log_transform = np.log1p(y_target) |
<matplotlib.axes._subplots.AxesSubplot at 0x1d01ef87c10>
- 정규 분포 형태는 아니지만, 왜곡 정도가 많이 향상됨
- 위 데이터로 다시 학습하고 평가하기
1 | # 타겟 컬럼인 count 값을 log1p 로 Log 변환 |
RMSLE: 1.017, RMSE: 162.594, MAE: 109.286
- RMSLE 오류는 줄어들었으나, RMSE는 오히려 더 늘어남
- 각 피처의 회귀 계수 값을 시각화해 확인하기
1 | coef = pd.Series(lr_reg.coef_, index=X_features.columns) |
<matplotlib.axes._subplots.AxesSubplot at 0x1d020439100>
- 결과 해석
- Year 피처 회귀 계수 값이 독보적으로 큼
- Year는 2011, 2012 두 개의 값으로, year에 따라 자전거 대여 횟수가 크게 영향을 받는다고 할 수 없음
- Category 피처지만 숫자형 값으로 되어 있고 2011, 2012가 매우 큰 숫자라 영향을 주게 됨
- 원-핫 인코딩을 적용해 변환하여야 함
- Year 피처 회귀 계수 값이 독보적으로 큼
- 여러 칼럼 원-핫 인코딩하고 선형 회귀 모델(LinearRegression, Ridge, Lasso) 모두 학습해 예측 성능 확인하기
- 사용 함수: get_model_predict()
- 모델과 학습/테스트 데이터 세트를 입력하면 성능 평가 수치를 반환하는 함수
1 | # 'year', month', 'day', hour'등의 피처들을 One Hot Encoding |
1 | # 원-핫 인코딩이 적용된 feature 데이터 세트 기반으로 학습/예측 데이터 분할. |
### LinearRegression ###
RMSLE: 0.590, RMSE: 97.688, MAE: 63.382
### Ridge ###
RMSLE: 0.590, RMSE: 98.529, MAE: 63.893
### Lasso ###
RMSLE: 0.635, RMSE: 113.219, MAE: 72.803
- 결과 해석
- 원-핫 인코딩 적용 후, 선형 회귀 예측 성능이 많이 향상됨
- 원-핫 인코딩으로 피처가 늘어났으므로, 회귀 계수 상위 25개 피처를 추출해 시각화하기
1 | coef = pd.Series(lr_reg.coef_ , index=X_features_ohe.columns) |
<matplotlib.axes._subplots.AxesSubplot at 0x1d0204cb2e0>
- 결과 해석
- 선형 회귀 모델 시 month_9, month_8, month_7 등의 월 관련 피처와 workingday 관련 피처, hour 관련 피처의 회귀 계수가 높은 것을 알 수 있음
- 월, 주말/주중, 시간대 등 상식선에서 자전거 타는 데 필요한 피처의 회귀 계수가 높아짐
→ 선형 회귀 수행 시에는 피처를 어떻게 인코딩하는가가 성능에 큰 영향을 미칠 수 있음
- 월, 주말/주중, 시간대 등 상식선에서 자전거 타는 데 필요한 피처의 회귀 계수가 높아짐
- 선형 회귀 모델 시 month_9, month_8, month_7 등의 월 관련 피처와 workingday 관련 피처, hour 관련 피처의 회귀 계수가 높은 것을 알 수 있음
- 회귀 트리로 회귀 예측 수행하기
1 | from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor |
### RandomForestRegressor ###
RMSLE: 0.355, RMSE: 50.447, MAE: 31.270
### GradientBoostingRegressor ###
RMSLE: 0.330, RMSE: 53.336, MAE: 32.746
### XGBRegressor ###
RMSLE: 0.342, RMSE: 51.732, MAE: 31.251
### LGBMRegressor ###
RMSLE: 0.319, RMSE: 47.215, MAE: 29.029
- 결과 해석
- 앞의 선형 회귀 모델보다 회귀 예측 성능이 개선됨
- 단, 회귀 트리가 선형 트리보다 나은 성능을 가진다는 의미가 아님
- 데이터 세트 유형에 따라 결과는 얼마든지 달라질 수 있음
10. 회귀 실습- 캐글 주택 가격: 고급 회귀 기법
데이터 설명
- 변수: 79개
- 미국 아이오와주의 에임스(Ames) 지방 주택 가격 정보
- 피처별 설명 확인하기
성능 평가
- RMSLE(Root Mean Squared Log Error) 기반
- 가격이 비싼 주택일수록 예측 결과 오류가 전체 오류에 미치는 비중이 높으므로, 이를 상쇄하기 위해 오류 값을 로그 변환한 RMSLE를 이용
(1) 데이터 사전 처리(Preprocessing)
1 | import warnings |
Id | MSSubClass | MSZoning | LotFrontage | LotArea | Street | Alley | LotShape | LandContour | Utilities | ... | PoolArea | PoolQC | Fence | MiscFeature | MiscVal | MoSold | YrSold | SaleType | SaleCondition | SalePrice | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 60 | RL | 65.0 | 8450 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 2 | 2008 | WD | Normal | 208500 |
1 | 2 | 20 | RL | 80.0 | 9600 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 5 | 2007 | WD | Normal | 181500 |
2 | 3 | 60 | RL | 68.0 | 11250 | Pave | NaN | IR1 | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 9 | 2008 | WD | Normal | 223500 |
3 rows × 81 columns
1 | # 데이터 세트 전체 크기와 칼럼 타입, Null이 있는 칼럼과 건수를 내림차순으로 출력 |
데이터 세트의 Shape: (1460, 81)
전체 feature 들의 type
object 43
int64 35
float64 3
dtype: int64
Null 컬럼과 그 건수:
PoolQC 1453
MiscFeature 1406
Alley 1369
Fence 1179
FireplaceQu 690
LotFrontage 259
GarageYrBlt 81
GarageType 81
GarageFinish 81
GarageQual 81
GarageCond 81
BsmtFinType2 38
BsmtExposure 38
BsmtFinType1 37
BsmtCond 37
BsmtQual 37
MasVnrArea 8
MasVnrType 8
Electrical 1
dtype: int64
- 데이터 타입 확인
- 테이터 세트는 1460개의 레코드와 81개의 피처로 구성
- 피처 타입은 숫자형과 문자형 모두 존재
- Target을 제외한 80개 피처 중, 43개가 문자형이고 37개가 숫자형
- 1480개 데이터 중, PoolQC, MiseFeature, Alley, Fence는 1000개가 넘는 Null 값을 가짐
- Null 값이 너무 많은 피처는 drop
- 회귀 모델 적용 전, 타깃 값 분포가 정규 분포인지 확인하기
- 아래 그래프에서 볼 수 있듯, 데이터 값 분포가 왼쪽으로 치우친 형태로 정규 분포에서 벗어나 있음
1 | plt.title('Original Sale Price Histogram') |
<matplotlib.axes._subplots.AxesSubplot at 0x1d017a30310>
- 로그 변환(Log Transformation)을 적용하여, 정규 분포가 아닌 결괏값을 정규 분포 형태로 변환하기
- Numpy의 log1p()로 로그 변환한 결괏값 기반으로 학습
- 예측 시에는 결괏값을 expm1()로 환원
1 | plt.title('Log Transformed Sale Price Histogram') |
<matplotlib.axes._subplots.AxesSubplot at 0x1d017b1a790>
- SalePrice를 로그 변환해 정규 분포 형태로 결괏값이 분포함을 확인할 수 있음
- 다음 작업
- SalePrice를 로그 변환하고 DataFrame에 반영
- Null 값이 많은 피처인 PoolQC, MiseFeature, Alley, Fence, FireplaceQu 삭제
- 단순 식별자인 Id 삭제
- LotFrontage Null 값은 259개로 비교적 많으나, 평균값으로 대체
- 나머지 피처 Null 값은 많지 않으므로 숫자형의 경우 평균값으로 대체
1 | # SalePrice 로그 변환 |
## Null 피처의 Type :
MasVnrType object
BsmtQual object
BsmtCond object
BsmtExposure object
BsmtFinType1 object
BsmtFinType2 object
Electrical object
GarageType object
GarageFinish object
GarageQual object
GarageCond object
dtype: object
- 문자형 피처는 원-핫 인코딩으로 변환하기
- 사용 함수: get_dummies()
- 자동으로 문자열 피처를 원-핫 인코딩으로 변환하면서 Null 값을 ‘None’ 칼럼으로 대체해주어 Null 값을 대체하는 별도의 로직이 필요 없음
- 원-핫 인코딩을 적용하면 칼럼이 증가하기 때문에, 변환 후 늘어난 칼럼 값까지 확인하기
1 | print('get_dummies() 수행 전 데이터 Shape:', house_df.shape) |
get_dummies() 수행 전 데이터 Shape: (1460, 75)
get_dummies() 수행 후 데이터 Shape: (1460, 271)
## Null 피처의 Type :
Series([], dtype: object)
- 결과 해석
- 원-핫 인코딩 후 피처가 75개에서 272개로 증가
- Null 값을 가진 피처는 없음
(2) 선형 회귀 모델 학습/예측/평가
RMSE 평가 함수 생성
1 | def get_rmse(model): |
LinearRegression, Ridge, Lasso 학습, 예측, 평가
1 | from sklearn.model_selection import train_test_split |
LinearRegression 로그 변환된 RMSE: 0.132
Ridge 로그 변환된 RMSE: 0.128
Lasso 로그 변환된 RMSE: 0.176
[0.1318957657915403, 0.1275084633405302, 0.17628250556471403]
회귀 계수값과 컬럼명 시각화를 위해 상위 10개, 하위 10개(-값으로 가장 큰 10개) 회귀 계수값과 컬럼명을 가지는 Series생성 함수.
1 | def get_top_bottom_coef(model): |
인자로 입력되는 여러개의 회귀 모델들에 대한 회귀계수값과 컬럼명 시각화
1 | def visualize_coefficient(models): |
5 폴드 교차검증으로 모델별로 RMSE와 평균 RMSE출력
1 | from sklearn.model_selection import cross_val_score |
LinearRegression CV RMSE 값 리스트: [0.135 0.165 0.168 0.111 0.198]
LinearRegression CV 평균 RMSE 값: 0.155
Ridge CV RMSE 값 리스트: [0.117 0.154 0.142 0.117 0.189]
Ridge CV 평균 RMSE 값: 0.144
Lasso CV RMSE 값 리스트: [0.161 0.204 0.177 0.181 0.265]
Lasso CV 평균 RMSE 값: 0.198
각 모델들의 alpha값을 변경하면서 하이퍼 파라미터 튜닝 후 다시 학습/예측/평가
1 | from sklearn.model_selection import GridSearchCV |
Ridge 5 CV 시 최적 평균 RMSE 값: 0.1418, 최적 alpha:{'alpha': 12}
Lasso 5 CV 시 최적 평균 RMSE 값: 0.142, 최적 alpha:{'alpha': 0.001}
1 | # 앞의 최적화 alpha값으로 학습데이터로 학습, 테스트 데이터로 예측 및 평가 수행. |
LinearRegression 로그 변환된 RMSE: 0.132
Ridge 로그 변환된 RMSE: 0.124
Lasso 로그 변환된 RMSE: 0.12
숫자 피처들에 대한 데이터 분포 왜곡도 확인 후 높은 왜곡도를 가지는 피처 추출
1 | from scipy.stats import skew # skew: 왜곡 |
MiscVal 24.451640
PoolArea 14.813135
LotArea 12.195142
3SsnPorch 10.293752
LowQualFinSF 9.002080
KitchenAbvGr 4.483784
BsmtFinSF2 4.250888
ScreenPorch 4.117977
BsmtHalfBath 4.099186
EnclosedPorch 3.086696
MasVnrArea 2.673661
LotFrontage 2.382499
OpenPorchSF 2.361912
BsmtFinSF1 1.683771
WoodDeckSF 1.539792
TotalBsmtSF 1.522688
MSSubClass 1.406210
1stFlrSF 1.375342
GrLivArea 1.365156
dtype: float64
왜곡도가 1인 피처들은 로그 변환 적용하고 다시 하이퍼 파라미터 튜닝 후 재 학습/예측/평가
1 | house_df[skew_features_top.index] = np.log1p(house_df[skew_features_top.index]) |
1 | # Skew가 높은 피처들을 로그 변환 했으므로 다시 원-핫 인코딩 적용 및 피처/타겟 데이터 셋 생성, |
Ridge 5 CV 시 최적 평균 RMSE 값: 0.1275, 최적 alpha:{'alpha': 10}
Lasso 5 CV 시 최적 평균 RMSE 값: 0.1252, 최적 alpha:{'alpha': 0.001}
1 | # 앞의 최적화 alpha값으로 학습데이터로 학습, 테스트 데이터로 예측 및 평가 수행. |
LinearRegression 로그 변환된 RMSE: 0.128
Ridge 로그 변환된 RMSE: 0.122
Lasso 로그 변환된 RMSE: 0.119
이상치 데이터 검출을 위해 주요 피처인 GrLivArea값에 대한 산포도 확인
1 | plt.scatter(x = house_df_org['GrLivArea'], y = house_df_org['SalePrice']) |
이상치 데이터 삭제 후 재 학습/예측/평가
1 | # GrLivArea와 SalePrice 모두 로그 변환되었으므로 이를 반영한 조건 생성. |
아웃라이어 레코드 index : [ 523 1298]
아웃라이어 삭제 전 house_df_ohe shape: (1460, 271)
아웃라이어 삭제 후 house_df_ohe shape: (1458, 271)
1 | y_target = house_df_ohe['SalePrice'] |
Ridge 5 CV 시 최적 평균 RMSE 값: 0.1125, 최적 alpha:{'alpha': 8}
Lasso 5 CV 시 최적 평균 RMSE 값: 0.1122, 최적 alpha:{'alpha': 0.001}
1 | # 앞의 최적화 alpha값으로 학습데이터로 학습, 테스트 데이터로 예측 및 평가 수행. |
LinearRegression 로그 변환된 RMSE: 0.129
Ridge 로그 변환된 RMSE: 0.103
Lasso 로그 변환된 RMSE: 0.1
(3) 회귀 트리 학습/예측/평가
XGBoost와 LightGBM 학습/예측/평가
1 | from xgboost import XGBRegressor |
XGBRegressor 5 CV 시 최적 평균 RMSE 값: 0.1178, 최적 alpha:{'n_estimators': 1000}
1 | from lightgbm import LGBMRegressor |
LGBMRegressor 5 CV 시 최적 평균 RMSE 값: 0.1163, 최적 alpha:{'n_estimators': 1000}
트리 회귀 모델의 피처 중요도 시각화
1 | # 모델의 중요도 상위 20개의 피처명과 그때의 중요도값을 Series로 반환. |
(4) 회귀 모델들의 예측 결과 혼합을 통한 최종 예측
1 | def get_rmse_pred(preds): |
최종 혼합 모델의 RMSE: 0.10007930884470519
Ridge 모델의 RMSE: 0.10345177546603257
Lasso 모델의 RMSE: 0.10024170460890033
1 | xgb_reg = XGBRegressor(n_estimators=1000, learning_rate=0.05, |
최종 혼합 모델의 RMSE: 0.1017007808403327
XGBM 모델의 RMSE: 0.10738299364833828
LGBM 모델의 RMSE: 0.10382510019327311
(5) 스태킹 모델을 통한 회귀 예측
1 | from sklearn.model_selection import KFold |
기반 모델은 리지, 라소, XGBoost, LightGBM 으로 만들고 최종 메타 모델은 라소로 생성하여 학습/예측/평가
1 | # get_stacking_base_datasets( )은 넘파이 ndarray를 인자로 사용하므로 DataFrame을 넘파이로 변환. |
Ridge model 시작
폴드 세트: 0 시작
폴드 세트: 1 시작
폴드 세트: 2 시작
폴드 세트: 3 시작
폴드 세트: 4 시작
Lasso model 시작
폴드 세트: 0 시작
폴드 세트: 1 시작
폴드 세트: 2 시작
폴드 세트: 3 시작
폴드 세트: 4 시작
XGBRegressor model 시작
폴드 세트: 0 시작
폴드 세트: 1 시작
폴드 세트: 2 시작
폴드 세트: 3 시작
폴드 세트: 4 시작
LGBMRegressor model 시작
폴드 세트: 0 시작
폴드 세트: 1 시작
폴드 세트: 2 시작
폴드 세트: 3 시작
폴드 세트: 4 시작
1 | # 개별 모델이 반환한 학습 및 테스트용 데이터 세트를 Stacking 형태로 결합. |
스태킹 회귀 모델의 최종 RMSE 값은: 0.09799154066897717
11. 정리
- 선형 회귀와 비용 함수 RSS
- 경사 하강법
- 다항회귀와 과소적합/과대적합
- 규제 -L2규제를 적용한 릿지, L1규제를 적용한 라쏘, L1과 L2규제가 결합된 엘라스틱넷 회귀
- 분류를 위한 로지스틱 회귀
- CART 기반의 회귀 트리
- 왜곡도 개선을 위한 데이터 변환과 원-핫 인코딩
- 실습 예제를 통한 데이터 정제와 변환 그리고 선형회귀/회귀트리/혼합모델/스태킹 모델 학습/예측/평가비교