피처 엔지니어링 2
새로운 피처를 만드는 것이 어떻게 좋은 예측 모형을 만드는데 도움이 되는가?
다음의 R 코드는 데이터 dat
를 생성한다. 이때 설명변수는 x1
에서 x10
은 상관관계 0.1인 표준정규분포를 따른다. 실제 데이터생성모형은 다음과 같다.
\[y = 3 + \beta_1 x_1 + \beta_2 x_2 + \cdots + \beta_{10} x_{10} + e,\ \ e \sim \mathcal{N}(0,1)\]
정확한 모형을 알고 있다면 자료를 모형에 적합하여 모수( \(\beta_1, \beta_2, \cdots\) )을 추정하면 된다. 하지만 문제가 있다. 모수의 갯수가 늘어날 수록 모수를 정확하게 추정하기 위해 필요한 표본의 크기도 증가한다. 아래에서 표본의 크기(N
)는 20이다.
library(data.table)
library(dplyr)
library(ggplot2)
N <- 20
ncolMatX <- 11
sigma.cor = 0.1
library(mvtnorm)
sigma <- matrix(
sigma.cor,
ncolMatX, ncolMatX)
diag(sigma) = 1
matX <- rmvnorm(N, mean=rep(0,ncolMatX), sigma=sigma)
colnames(matX) <- c(paste0("x", 1:10), "e")
X <- data.table(matX)
paramTrue <- c(3, rnorm(5,1,0.2),
rnorm(5,-1.4,0.2))
names(paramTrue) <- paste0("beta", 0:10)
lv <- X[, .(f1 = paramTrue['beta1']*x1 +
paramTrue['beta2']*x2 +
paramTrue['beta3']*x3 +
paramTrue['beta4']*x4 +
paramTrue['beta5']*x5,
f2 = paramTrue['beta6']*x6 +
paramTrue['beta7']*x7 +
paramTrue['beta8']*x8 +
paramTrue['beta9']*x9 +
paramTrue['beta10']*x10)]
y <- 3 + lv$f1 + lv$f2 + X$e
dfParamTrue <- data.frame(key=factor(names(paramTrue),
levels= paste0("beta", 0:10)),
value=paramTrue)
dat <- data.table(X,y)
새로운 피처를 사용한 간단한 요인 모형
이때 \(\beta_1, \beta_2, \beta_3, \beta_4, \beta_5\) 가 모두 \(\textrm{Unif}(.8, 1.2)\) 의 분포를 따르면 \(\beta_6, \beta_7, \beta_8, \beta_9, \beta_{10}\) 는 \(\textrm{Unif}(-1.2,-1.6)\) 의 분포를 따른다면 이런 사실 활용할 수 없을까?
\(f_1 = x_1 + x_2 + x_3 + x_4 + x_5\) , \(f_6 = x_6 + x_7 + x_8 + x_9 + x_{10}\) 으로 놓고, 다음의 모형에 적합을 시킨다면 추정해야 할 모수가 3개로 줄어든다. (이 모형은 참 모형을 그대로 반영할 수 없다는 단점이 있지만, 모수의 추정이 정확하다는 장점이 있는 것이다.)[1]
[1]: 보통 요인 모형은 \(x_1 = \lambda_{11}f_1 + \lambda_{12}f_2 + \cdots + e_1\) 과 같은 모형을 따르지만, 여기서는 편의상 \(f_1 = x_1 + x_2 + \cdots\) 를 요인으로 칭하였다.
\[y= \beta_0 + \beta_1 f_1 + \beta_2 f_2 + e,\ \ e \sim \mathcal{N}(0,1)\]
dat2 <- X[, .(f1= x1+x2+x3+x4+x5,
f2= x6+x7+x8+x9+x10,
y = y)]
두 예측 모형에 대한 성능을 비교해보면 다음과 같다.
fit <- lm(y ~ . -e , dat)
fit2 <- lm(y ~ . , dat2)
cat('full linear model\n')
summary(fit)
cat('factor model\n')
summary(fit2)
## full linear model ## ## Call: ## lm(formula = y ~ . - e, data = dat) ## ## Residuals: ## Min 1Q Median 3Q Max ## -1.35839 -0.09420 0.08033 0.31608 0.93411 ## ## Coefficients: ## Estimate Std. Error t value Pr(>|t|) ## (Intercept) 2.8314 0.2130 13.295 3.20e-07 *** ## x1 1.0266 0.2015 5.096 0.000649 *** ## x2 1.2273 0.2966 4.139 0.002527 ** ## x3 0.5391 0.2200 2.450 0.036760 * ## x4 0.9642 0.1642 5.873 0.000237 *** ## x5 1.2303 0.2542 4.839 0.000922 *** ## x6 -1.3273 0.1842 -7.208 5.04e-05 *** ## x7 -0.7502 0.2831 -2.650 0.026482 * ## x8 -0.6236 0.3695 -1.688 0.125750 ## x9 -1.6515 0.2767 -5.969 0.000210 *** ## x10 -1.2082 0.2135 -5.658 0.000310 *** ## --- ## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 ## ## Residual standard error: 0.8244 on 9 degrees of freedom ## Multiple R-squared: 0.9726, Adjusted R-squared: 0.9422 ## F-statistic: 31.96 on 10 and 9 DF, p-value: 8.075e-06 ## ## factor model ## ## Call: ## lm(formula = y ~ ., data = dat2) ## ## Residuals: ## Min 1Q Median 3Q Max ## -2.4114 -0.7692 0.1067 0.7091 1.9319 ## ## Coefficients: ## Estimate Std. Error t value Pr(>|t|) ## (Intercept) 2.97574 0.27035 11.007 3.73e-09 *** ## f1 0.94914 0.09844 9.642 2.64e-08 *** ## f2 -1.22655 0.12202 -10.052 1.43e-08 *** ## --- ## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 ## ## Residual standard error: 1.151 on 17 degrees of freedom ## Multiple R-squared: 0.8992, Adjusted R-squared: 0.8874 ## F-statistic: 75.84 on 2 and 17 DF, p-value: 3.378e-09
일반화 성능
기존의 데이터를 적합하는 능력은 x1
~x10
을 모두 사용하는 것이 좋다. 하지만 다음의 결과에서 보듯이 새로운 데이터에 대한 MSE는 f1
과 f2
를 활용한 모형이 더 좋다.
### NEW DATA
N <- 100
ncolMatX <- 11
sigma <- matrix(
sigma.cor,
ncolMatX, ncolMatX)
diag(sigma) = 1
matX <- rmvnorm(N, mean=rep(0,ncolMatX), sigma=sigma)
colnames(matX) <- c(paste0("x", 1:10), "e")
X <- data.table(matX)
lv <- X[, .(f1 = paramTrue['beta1']*x1 +
paramTrue['beta2']*x2 +
paramTrue['beta3']*x3 +
paramTrue['beta4']*x4 +
paramTrue['beta5']*x5,
f2 = paramTrue['beta6']*x6 +
paramTrue['beta7']*x7 +
paramTrue['beta8']*x8 +
paramTrue['beta9']*x9 +
paramTrue['beta10']*x10)]
y <- 3 + lv$f1 -lv$f2 + X$e
newdat <- data.table(X,y); #head(newdat)
newdat2 <- X[, .(f1= x1+x2+x3+x4+x5,
f2= x6+x7+x8+x9+x10,
y = y)]
cat('MSE: full model\n')
print(mean((predict(fit, newdat)- newdat$y)^2))
cat('MSE: factor model\n')
print(mean((predict(fit2, newdat2)-newdat2$y)^2))
## MSE: full model ## [1] 49.39531 ## MSE: factor model ## [1] 53.05298
다시 말해 모든 변수를 사용한 선형 모형은 모수를 정확하게 추정할 자료가 부족하기 때문에 과적합되었으며, 새로운 피처를 생성하여 사용한 두 번째 모형의 경우, 참 모형을 포함할 수 없음에도 불구하여 사전지식을 활용하여 일반화가 더 좋은 모형을 만들어 낸 것이다!
물론 표본 크기(자료 갯수)가 증가함에 따라 참모형을 포함하는 full model
의 성능이 나아지기 시작한다.
전체 모형과 간단한 모형의 차이
다음 시뮬레이션을 통해 표본크기가 증가함에 따라 전체 모형(full model
), 요인 모형(factor model
), 그리고 평균 모형( \(y\) 예측값을 표본의 \(y\) 평균으로 하는 모형)의 MSE를 비교한 그래프이다(그래프의 y
는 새로운 자료에 대한 예측값의 MSE이다).
전체 모형과 요인 모형만을 따로 떼어 보면 다음과 같다.
위의 그래프를 보면 표본크기가 60 이상이 되어야 전체 모형이 요인 모형보다 성능이 좋아짐을 확인할 수 있다.
이때 한 가지 더 눈여겨 볼 점이 있다. 표본 크기가 작은 경우 전체 모형 MSE의 분포가 굉장히 넓다는 점이다. 위의 그래프는 새로운 자료를 사용하여 MSE를 구했지만 학습 자료가 부족한 상황에서 CV(Cross Validation; 교차검증)를 해야 할 경우에는 이런 점 때문에 CV의 결과를 그대로 믿기 힘들다는 점이다.
새로운 피처를 사용한 랜덤 포레스트
다음 그래프는 동일한 상황에서 적합 모형을 선형 모형에서 랜덤포레스트로 바꾼 결과이다.
눈여겨볼 점은 \(x1\) ~ \(x10\) 을 모두 설명 변수로 사용한 랜덤 포레스트와 \(f1\) 과 \(f2\) 를 사용한 랜덤 포레스트 사이의 MSE 차이가 표본크기 100에서도 크게 차이가 난다는 점이다. 표본크기를 더 늘려본 결과는 다음과 같다.
훈련 자료를 1000,000(백만개!)를 사용해도 이 차이는 좀 처럼 줄어들지 않는다!
선형 모형과 랜덤포레스트가 요구하는 훈려자료의 크기를 비교하기 위해서는 다음의 그래프를 보자.
전체 선형 모형의 경우에는 표본 크기 1000이 되기 훨씬 전에 이론적 최저 MSE인 1에 근접하고 있지만 랜덤 포레스트의 경우에는 그렇지 못하다는 점을 확인할 수 있다.
그 이유는? 랜덤포레스트의 작동 방식을 이해한다면 추측할 수 있을 것이다.
[힌트]: 적합시킨 선형 모형 또는 랜덤포레스트에 ICEbox
등의 패키지를 사용하여 모형을 이해해보자.
마무리
이 글에서는 이론적으로 뒷받침되는 새로운 피처가 어떻게 모형의 성능을 높일 수 있는지 보았다. 특히 훈련자료의 수가 적을 때에는 정확하지 않아도 모형의 모수 또는 복잡성을 줄여주는 모형이 일반화 성능을 높이는데 도움이 됨을 보았다.
그리고 적은 수의 모수를 포함한 모형을 사용하하는 것이 모형의 성능을 추정하는 데에도 도움이 된다(CV에서 얻은 값이 더 정확하다).
Leave a comment