`ifelse`는 `Date`를 싫어해
ifelse
Hadley가 쓴 Advanced R(2nd ed.)을 보면, ifelse에 대해 이렇게 설명한다.
ifelse(cond, yes, no)는yes와no가 같은 타입일 때만 쓰길 권장한다. 만약yes와no의 타입이 다르다면 결과 타입을 정확하게 예측하기가 어렵다.
아마도 아래와 같이 조건(cond)을 모두 만족하느냐, 그렇지 않느냐에 따라 결과 벡터의 타입이 달라질 수 있음을 우려한 것 같다.
x <- c(0,1,2,3)
ifelse(x > 1, "Yes", TRUE) # 결과 : 문자
## [1] "TRUE" "TRUE" "Yes" "Yes"
ifelse(x > -1, "Yes", TRUE) # 문자
## [1] "Yes" "Yes" "Yes" "Yes"
ifelse(x > 4, "Yes", TRUE) # 논리
## [1] TRUE TRUE TRUE TRUE
사실 Hadley는 결과 벡터가 항상 동일한 형태가 되는 것을 좋아하며, R의 많은 함수를 그런 방식으로 수정하기도 했다. 하지만 그게 꼭 흠일 수만은 없다고 본다.
예를 들어 그 흔한 recycling의 경우도 많은 논리 오류의 원인이 되기도 하지만, 그걸 또 명시적으로 구현하려고 하면 불편한게 사실이다.
예를 들어 아래와 같이 간단하게 쓸 수 있는 경우에, recycling이 안 된다면,
a = 1:4
b = 1:3
cbind(a,b)
## Warning in cbind(a, b): number of rows of result is not a multiple of vector length (arg 2)
## a b ## [1,] 1 1 ## [2,] 2 2 ## [3,] 3 3 ## [4,] 4 1
다음과 같이 수고로운 변환 과정을 거쳐야 한다.
a = 1:4
b = 1:3
if ((la <- length(a))>(lb <- length(b))) {
repn <- la %/% lb
remain <- la %% lb
b = c(rep(b, repn), b[1:remain])
} else {
repn <- lb %/% la
remain <- lb %% la
a = c(rep(a, repn), a[1:remain])
}
cbind(a,b)
## a b ## [1,] 1 1 ## [2,] 2 2 ## [3,] 3 3 ## [4,] 4 1
ifelse! & Date
그런데 ifelse()는 결과의 타입보다 중대한 결함이 있었다. 다음은 ifelse()와의 인터뷰이다.
저는 태생적으로 Date를 싫어합니다. 우리에게 중요한 것은 Unix Epoch(1970-01-01)이죠. 그날로부터 몇일이나 지났는지만 알면 됩니다.
x <- as.Date(c('2011-01-03', '2022-04-01'))
ifelse(x > as.Date('2021-05-01'), as.Date('1970-01-01'), as.Date('2021-05-01'))
## [1] 18748 0
반면 dplyr의 case_when은 잘 작동하는 듯하다.
dplyr::case_when(
x > as.Date('2014-05-01') ~ as.Date('2010-01-01'),
TRUE ~ as.Date('2010-01-01')
)
## [1] "2010-01-01" "2010-01-01"
ifelse!! & POSIXct
예상대로 POSIXct의 경우도 마찬 가지 문제가 발생한다.
x <- as.POSIXct(c('2011-01-03 13:14', '2022-04-01 01:01'))
ifelse(x > as.POSIXct('2021-05-01'),
as.POSIXct('1970-01-01 00:00'),
as.POSIXct('2021-05-01 12:00'))
## [1] 1619838000 -32400
dplyr::case_when(
x > as.POSIXct('2021-05-01') ~ as.POSIXct('1970-01-01 00:00'),
TRUE ~ as.POSIXct('2021-05-01 12:00')
)
## [1] "2021-05-01 12:00:00 KST" "1970-01-01 00:00:00 KST"
Leave a comment