ifelse
data(package="ggplot2")
명령어를 통해서 ggplot2
팩키지에 내장된 데이터셋을 확인할 수 있다. dataset
팩키지 mtcars
데이터셋을 새롭게 만든 mpg
데이터셋을 활용하여 One Hot Encoding 기법을 통해서 범주형 변수를 기계학습 예측모형에 활용할 수 있는 Feature로 만들어 보자.
One Hot Encoding을 통계학에서는 가변수(dummy variable)을 만든다고 한다. 즉, 변수에 특성이 있느냐 없느냐를 가지고 두가지 수준을 갖는 범주의 차이를 계량화한다. 예를 들어 1999년 양산차와 2008년 양산차간의 연비향상이 얼마나 있었는지를 하나의 Feature로 넣는 것을 상정할 수 있다.
library(tidyverse)
mpg <- mpg %>% tbl_df
mpg %>%
select(year) %>%
table()
.
1999 2008
117 117
시내주행연비(cty
)와 고속도로연비(hwy
)에 영향을 주는 변수는 많다. 그중 10년이라는 시간이라는 요인이 연비향상에 얼마나 기여를 했는지 요약통계량을 다음과 같이 구할 수 있다.
mpg %>%
group_by(year) %>%
summarise(mean_cty = mean(cty),
mean_hwy = mean(hwy))
# A tibble: 2 x 3
year mean_cty mean_hwy
<int> <dbl> <dbl>
1 1999 17.0 23.4
2 2008 16.7 23.5
ifelse
문을 사용해서 1999년을 기준으로 회귀계수(가중치, w
)를 통해 연비에 주는 효과를 계량화해서 넣을 수 있다.
mpg %>%
mutate(decade = ifelse(year == 1999, 0, 1)) %>%
select(cty, year, decade)
# A tibble: 234 x 3
cty year decade
<int> <int> <dbl>
1 18 1999 0
2 21 1999 0
3 20 2008 1
4 21 2008 1
5 16 1999 0
6 18 1999 0
7 18 2008 1
8 18 1999 0
9 16 1999 0
10 20 2008 1
# ... with 224 more rows
case_when
case_when()
을 사용하여 ifelse
를 여러번 중첩시켜 사용하는 대신 범주를 깔끔하게 정리할 수 있다.
mpg %>%
select(class) %>%
table()
.
2seater compact midsize minivan pickup subcompact
5 47 41 11 33 35
suv
62
자동차를 소형, 중형, 중소형 등 다양하게 구분할 수 있는데 이를 다음과 같이 범주를 나눠서 정리하는 것이 예측모형의 유의미한 Feature로 탈바꿈시킬 수도 있다.
mpg %>%
mutate(`차량범주` = case_when(str_detect( class, pattern="minivan|pickup") ~ "영업용",
str_detect( class, pattern="compact") ~ "소형",
str_detect( class, pattern="midsize") ~ "중형",
TRUE ~ "여가용")) %>%
select(`차량범주`) %>%
table()
.
소형 여가용 영업용 중형
82 67 44 41
prop.table
)시내주행연비를 평균보다 높은 경우 “high”, 낮은 경우 “low”로 두고 prop.table()
함수를 통해 제조사(manufacturer
) 비율을 계산한다. 이를 hl_prop
변수로 결합시켜 너무 범주가 많아서 사용하기 어려웠던 범수형 변수를 새로운 feature로 만들어 냈다.
manufacturer_tbl <- mpg %>%
mutate(hl_mpg = ifelse(cty >17, "high", "low")) %>%
select(manufacturer, hl_mpg) %>%
table
manufacturer_prop_tbl <- prop.table(manufacturer_tbl, 1) %>% tbl_df %>%
filter(hl_mpg == "high") %>%
rename(hl_prop = n)
mpg <- inner_join(mpg, manufacturer_prop_tbl, by="manufacturer")
mpg %>%
DT::datatable()
cut
)연속형 변수의 경우 히스토그램을 통해서 분포를 확인할 수 있고, 비선형적인 특성을 적절한 범주로 표현하여 잡아내는 것이 가능하다.
mpg %>%
ggplot(aes(x=displ)) +
geom_histogram(bins = 30)
cut()
함수를 사용해서 배기량(displ
)을 2000cc 기준으로 나눠본다. 배기량에 대한 자세한 사항은 나무위키 배기량을 참고한다.
mpg <- mpg %>%
mutate(displ_cat = cut(displ, breaks = seq(1, 7.0, by=2)))
mpg %>%
select(displ_cat) %>%
table()
.
(1,3] (3,5] (5,7]
108 90 36
model.matrix
함수를 사용해서 가변수화한 후에 이를 범주형 변수로 변환하여 cbind()
함수로 결합시킨다.
mpg <- cbind(mpg, model.matrix(~ displ_cat -1, data = mpg))
mpg %>%
select(contains("disp")) %>%
head()
displ displ_cat displ_cat(1,3] displ_cat(3,5] displ_cat(5,7]
1 1.8 (1,3] 1 0 0
2 1.8 (1,3] 1 0 0
3 2.0 (1,3] 1 0 0
4 2.0 (1,3] 1 0 0
5 2.8 (1,3] 1 0 0
6 2.8 (1,3] 1 0 0
quantile
)연속형 변수를 범주형 변수로 변환시킬 때 앞서 cut()
함수의 절대값을 기준으로 나누는 대신에 분위수(quantile)를 사용해서 나누는 것이 적절할 때가 있다. 대표적으로 일일이 사람이 보는 대신에 기계적으로 자동화를 할 경우 도움이 된다.
이런 경우 ntile()
함수를 사용하면 관측점을 예를 들어 배기량(displ
) 기준으로 3개 범주집단으로 동일하게 나눠준다.
mpg %>%
mutate(displ_tile = ntile(displ, 3) %>% as.factor) %>%
select(displ_tile) %>%
table()
.
1 2 3
78 78 78
ntile()
함수로 연속형 변수 배기량(displ
)을 범주형 변수로 변환시킨 후에 이를 model.matrix()
함수로 가변수화하여 예측모형을 위한 basetable
에 일원으로 편입시킨다. 역행렬 변환이 가능한 full rank
를 맞추고자 할 경우 -1
을 빼서 넣어준다.
mpg <- mpg %>%
mutate(displ_tile = ntile(displ, 3) %>% as.factor)
# mpg <- cbind(mpg, model.matrix(~ displ_tile -1, data = mpg))
mpg <- cbind(mpg, model.matrix(~ displ_tile, data = mpg)) # full rank
mpg %>%
select(contains("disp")) %>%
head()
displ displ_cat displ_cat(1,3] displ_cat(3,5] displ_cat(5,7] displ_tile
1 1.8 (1,3] 1 0 0 1
2 1.8 (1,3] 1 0 0 1
3 2.0 (1,3] 1 0 0 1
4 2.0 (1,3] 1 0 0 1
5 2.8 (1,3] 1 0 0 2
6 2.8 (1,3] 1 0 0 2
displ_tile2 displ_tile3
1 0 0
2 0 0
3 0 0
4 0 0
5 1 0
6 1 0
연속형 변수 중 치우침이 심한 변수가 많다. 이를 변수변환하여 정규분포에 가까운 형태로 맞추게 되면 예측모형의 성능 향상과 안정성을 기대할 수 있다. 1
멱변환(Power transformation)은 멱함수(power function)를 사용하여 데이터를 단조변환시키는데 이를 통해서 분산을 안정화시키고, 정규분포에 가까운 형태로 만들 수 있어 통계학에서 유용한 도구 중 하나다. 박스-콕스 변환(Box-Cox Transformation)은 Yeo–Johnson 변환과 비교하여 0 혹은 음수인 경우에 적용에 한계가 있다.
\[y_i^{(\lambda)} = \begin{cases} ((y_i+1)^\lambda-1)/\lambda & \text{if }\lambda \neq 0, y \geq 0 \\ \log(y_i + 1) & \text{if }\lambda = 0, y \geq 0 \\ -[(-y_i + 1)^{(2-\lambda)} - 1] / (2 - \lambda) & \text{if }\lambda \neq 2, y < 0 \\ -\log(-y_i + 1) & \text{if }\lambda = 2, y < 0 \end{cases} \]
caret
팩키지 preProcess()
함수에 method="YeoJohnson"
을 통해서 한쪽으로 치우친 배기량 변수를 Yeo-Johnson 변환을 통해 치우친 분포를 바로잡을 수 있게 된다.
library(caret)
mpg_before <- mpg %>%
ggplot(aes(x=displ)) +
geom_density() +
labs(title="변환 전 배기량")
## 변수변환
mpg_displ <- mpg %>%
select(displ)
mpg_displ_transformed <- preProcess(mpg_displ, method="YeoJohnson")
mpg_df <- predict(mpg_displ_transformed, mpg)
mpg_after <- mpg_df %>%
ggplot(aes(x=displ)) +
geom_density() +
labs(title="변환 후 배기량")
cowplot::plot_grid(mpg_before, mpg_after)
정규화는 변수의 특성에 따라 다음과 같이 크게 세가지 경우로 정규화를 통해 변환시킨다.
range
)가장 먼저 range
를 통해 배기량(displ
) 척도를 0 – 1 사이로 조정시킨다.
mpg_displ_range <- preProcess(mpg_displ, method="range")
mpg_df <- predict(mpg_displ_range, mpg)
mpg_df %>%
select(displ) %>%
bind_cols(mpg %>% select(displ)) %>%
summary()
displ displ1
Min. :0.0000 Min. :1.600
1st Qu.:0.1481 1st Qu.:2.400
Median :0.3148 Median :3.300
Mean :0.3466 Mean :3.472
3rd Qu.:0.5556 3rd Qu.:4.600
Max. :1.0000 Max. :7.000
center
)평균 중심화(mean centering)을 preProcess
함수 center
를 통해 배기량(displ
) 변수를 평균이 0을 중심으로 값들을 변환시킨다.
mpg_displ_center <- preProcess(mpg_displ, method="center")
mpg_df <- predict(mpg_displ_center, mpg)
mpg_df %>%
select(displ) %>%
bind_cols(mpg %>% select(displ)) %>%
summary()
displ displ1
Min. :-1.8718 Min. :1.600
1st Qu.:-1.0718 1st Qu.:2.400
Median :-0.1718 Median :3.300
Mean : 0.0000 Mean :3.472
3rd Qu.: 1.1282 3rd Qu.:4.600
Max. : 3.5282 Max. :7.000
z-점수 표준화를 preProcess
함수 c("center", "scale")
콤보를 통해 배기량(displ
) 변수를 평균이 0, 분산이 1인 값들로 변환시킨다.
mpg_displ_z_tranform <- preProcess(mpg_displ, c("center", "scale"))
mpg_df <- predict(mpg_displ_z_tranform, mpg)
mpg_df %>%
select(displ) %>%
bind_cols(mpg %>% select(displ)) %>%
summary()
displ displ1
Min. :-1.4488 Min. :1.600
1st Qu.:-0.8296 1st Qu.:2.400
Median :-0.1330 Median :3.300
Mean : 0.0000 Mean :3.472
3rd Qu.: 0.8733 3rd Qu.:4.600
Max. : 2.7309 Max. :7.000