keep value when using data.table::fcase() instead of dplyr::case_when()

52 Views Asked by At

I want to take advantage of the fast data.table::fcase() instead of using dplyr::case_when(), but I don't know how to keep the value of a given row as the default (and not a fixed value)

Say you have

dt <- data.table(v1 = c("1","2", "3", NA))

Using dplyr's case_when()

dt %>%
  mutate( v2 = case_when(is.na(v1) ~ "0",
                         TRUE ~ v1))

you get the expected result

> dt %>%
+   mutate( v2 = case_when(is.na(v1) ~ "0",
+                          TRUE ~ v1))
     v1 v2
1:    1  1
2:    2  2
3:    3  3
4: <NA>  0

Using data.table's fcase()

dt[ , v2 := fcase(is.na(v1), "0",
                  default = v1)]

(or anything similar to that code) you get the error

> dt[ , v2 := fcase(is.na(v1), "0",
+                   default = v1)]
Error in fcase(is.na(v1), "0", default = v1) : 
  Length of 'default' must be 1.

I believe because v1 is viewed as the full column v1

How do I fix it?

2

There are 2 best solutions below

1
r2evans On BEST ANSWER

The data.table-equivalent of dplyr::case_when(TRUE ~ expr) is fcase(rep(TRUE, .N), expr).

dt[ , v2 := fcase(is.na(v1), "0", rep(TRUE, .N), v1)]
#        v1     v2
#    <char> <char>
# 1:      1      1
# 2:      2      2
# 3:      3      3
# 4:   <NA>      0

But in this case, both dplyr and data.table's "coalesce" function is a better fit for that logic:

dt |>
  mutate(v2 = coalesce(v1, "0"))
#        v1     v2
#    <char> <char>
# 1:      1      1
# 2:      2      2
# 3:      3      3
# 4:   <NA>      0
dt[, v2 := fcoalesce(v1, "0")]
#        v1     v2
#    <char> <char>
# 1:      1      1
# 2:      2      2
# 3:      3      3
# 4:   <NA>      0
0
B. Christian Kamgang On

You can also solve your problem as follow either using fifelse from data.table or the built-in functions pmax/pmin:

dt[, v2 := fifelse(is.na(v1), "0", v1)]
# or
dt[, v2 := pmax(v1, "0", na.rm=TRUE)]

#        v1     v2
#    <char> <char>
# 1:      1      1
# 2:      2      2
# 3:      3      3
# 4:   <NA>      0