`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