이번 포스팅에서는 R dplyr 패키지의 case_when() 함수를 이용해서 연속형 변수를 여러개의 범주로 구분하여 범주형 변수를 만들어보겠습니다. dplyr 패키지의 case_when() 함수를 사용하면 여러개의 if, else if 조건절을 사용하지 않고도 벡터화해서 쉽고 빠르게 처리를 할 수 있습니다. R dplyr 의 case_when() 함수는 SQL의 case when 절과 유사하다고 보면 되겠습니다.
간단한 예제로 1~10 까지의 양의 정수를 "2 이하", "3~5", "6~8", "9 이상" 의 4개 범주로 구분을 해보겠습니다.
(dplyr::case_when()에서 dplyr:: 는 생략해도 되며, dplyr 패키지의 함수를 이용하다는 의미입니다)
case_when(
조건 ~ 할당값,
조건 ~ 할당값,
TRUE ~ 할당값)
의 형식으로 작성합니다.
아래의 예에서는 조건절이 총 4개 사용되었는데요, if, else if, else if, else 등의 조건절문 없이 case_when() 함수의 괄호안에 바로 조건을 나열했고, 마지막에는 앞의 조건절에 모두 해당 안되는 나머지(else)에 대해서 TRUE ~ "9~" 로 지정을 해주었습니다.
library(dplyr) x <- 1:10 x [1] 1 2 3 4 5 6 7 8 9 10 dplyr::case_when( x <= 2 ~ "~2", x <= 5 ~ "3~5", x <= 8 ~ "6~8", TRUE ~ "9~" ) [1] "~2" "~2" "3~5" "3~5" "3~5" "6~8" "6~8" "6~8" "9~" "9~" |
이때 조건절의 순서가 중요합니다. 복수의 조건절을 나열하면 앞에서 부터 순서대로(in order) 조건에 해당하는 관측치에 대해 값을 할당하게 됩니다. 따라서 만약 TRUE ~ "9~"를 case_when(() 조건절의 제일 앞에 사용하게 되면 1~10까지의 모든 값에 대해 "9~" 를 할당하게 됩니다. 따라서 조건절의 처리 순서를 반드시 고려해서 조건절을 작성해줘야 합니다.
# order matters!!! case_when( TRUE ~ "9~", x <= 2 ~ "~2", x <= 5 ~ "3~5", x <= 8 ~ "6~8", ) [1] "9~" "9~" "9~" "9~" "9~" "9~" "9~" "9~" "9~" "9~"
|
case_when() 조건절의 오른쪽(right hand side)의 데이터 유형이 모두 동일해야 합니다. 만약 데이터 유형이 다를 경우 error를 발생합니다. 가령, 아래 예에서는 오른쪽에 character를 반환하게끔 되어있는데 logical 인 NA 가 포함되는 경우 Error가 발생합니다. 이때는 'NA_character_' 를 사용해서 NA가 character로 반환되게끔 해주면 됩니다.
- 오른쪽에 문자형(character) 반환하는 경우 NA 값으로는 NA_character_ 사용
잘못된 사용 예 (오른쪽 데이터 유형 다름) |
올바른 사용 예 (오른쪽 데이터 유형 같음) |
# error as NA is logical not character case_when( x <= 2 ~ "~2", x <= 5 ~ "3~5", x <= 8 ~ "6~8", TRUE ~ NA ) Error: must be a character vector, not a logical vector Call `rlang::last_error()` to see a backtrace |
# use NA_character_ case_when( x <= 2 ~ "~2", x <= 5 ~ "3~5", x <= 8 ~ "6~8", TRUE ~ NA_character_ ) [1] "~2" "~2" "3~5" "3~5" "3~5" "6~8" "6~8" "6~8" NA NA |
- 오른쪽에 숫자형(numeric)을 반환하는 경우 NA 값으로는 NA_real_ 사용
잘못된 사용 예 (오른쪽 데이터 유형 다름) |
올바른 사용 예 (오른쪽 데이터 유형 같음) |
# error as NA is logical not numeric case_when( x <= 2 ~ 2, x <= 5 ~ 5, x <= 8 ~ 8, TRUE ~ NA ) Error: must be a double vector, not a logical vector Call `rlang::last_error()` to see a backtrace |
# use NA_real_ case_when( x <= 2 ~ 2, x <= 5 ~ 5, x <= 8 ~ 8, TRUE ~ NA_real_ ) [1] 2 2 5 5 5 8 8 8 NA NA |
dplyr의 case_when() 함수는 mutate() 함수와 함께 사용하면 매우 강력하고 편리하게 여러개의 조건절을 사용해서 새로운 변수를 만들 수 있습니다. 아래는 mtcars 데이터셋의 cyl (실린더 개수) 와 hp (자동차 마력) 의 두 개 변수를 사용해 첫번째 "or" 조건절로 "big" 유형으로 찾고, 두번째 "and" 조건절로 "medium" 유형을 찾으며, 마지막으로 나머지에 대해서는 "small" 유형을 명명해본 예입니다.
mtcars$name <- row.names(mtcars) mtcars %>% select(name, mpg, cyl, hp) %>% mutate( type = case_when( cyl >= 8 | hp >= 180 ~ "big", # or cyl >= 4 & hp >= 120 ~ "medium", # and TRUE ~ "small" ) ) name mpg cyl hp type 1 Mazda RX4 21.0 6 110 small 2 Mazda RX4 Wag 21.0 6 110 small 3 Datsun 710 22.8 4 93 small 4 Hornet 4 Drive 21.4 6 110 small 5 Hornet Sportabout 18.7 8 175 big 6 Valiant 18.1 6 105 small 7 Duster 360 14.3 8 245 big 8 Merc 240D 24.4 4 62 small 9 Merc 230 22.8 4 95 small 10 Merc 280 19.2 6 123 medium ---- 이하 생략 ----
|
위에서 R dplyr의 case_when() 함수로 진행했던 내용을 PostgreSQL, Greenplum DB에서 하려면 SQL CASE WHEN 문을 아래처럼 사용하면 됩니다. 참고하세요.
-- PostgreSQL CASE WEHN SELECT name, mpg, cyl, hp, CASE WHEN (cyl >= 8) OR (hp >= 180) THEN "big" WHEN (cyl >= 4) AND (hp >= 120) THEN "median" ELSE "small" END AS type FROM mtcars
|
많은 도움이 되었기를 바랍니다.
이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요.
'R 분석과 프로그래밍 > R 데이터 전처리' 카테고리의 다른 글
[R data.table] 데이터를 읽어와서 data.table 만들기, data.frame을 data.table로 변환하기 (0) | 2020.09.27 |
---|---|
[R data.table] data.table 은 무엇이고, 왜 data.table 인가? (0) | 2020.08.24 |
[R] 여러개의 변수를 가진 DataFrame을 무작위 층화 샘플링으로 Train, Test set 분할하고 표준화하기 (0) | 2020.01.19 |
[R] 장비 On, Off 상태로 가동 시간을 구하고, 장비 별 평균 가동 시간 구하기 (16) | 2019.10.24 |
[R] R 패키지 함수의 소스 코드를 볼 수 있는 방법 (how to see function's source codes in R package) (0) | 2019.10.22 |