rdplyr

dplyr::case_when throws "no non-missing arguments" with na.rm=TRUE even when compensating for all NA cases


I'm trying to calculate the minimum across rows while compensating for rows where all values of interest are NA:

library(dplyr)

testDf <- tibble(a = 1:4,
                 b = c(NA, 5:7),
                 c = c(NA, 8, NA, 10),
                 d = c(NA, 11:13)
                 ) %>%
  rowwise() %>%
  mutate(e = case_when(all(is.na(c_across(b:d))) ~ NA_integer_,
                       .default = min(c_across(b:d), na.rm=TRUE))
         ) %>%
  ungroup()

I get the following warning for row 1:

Caused by warning in min(): ! no non-missing arguments to min; returning Inf

However, the output indicates that the code works as intended:

testDf

# A tibble: 4 × 5
      a     b     c     d     e
  <int> <int> <dbl> <int> <dbl>
1     1    NA    NA    NA    NA
2     2     5     8    11     5
3     3     6    NA    12     6
4     4     7    10    13     7

Column e has NA in the first row, 6 in the third, and no Inf values. I've tried replacing .default = with TRUE ~ and !all(is.na(c_across(b:d))) ~, as well as replacing NA_integer_ with NA_real_ and still get the same warning.

My understanding is that .default in case_when only applies when the left side of the previous equation returns FALSE or NA. Testing with the following does indeed yield TRUE for the first row of f and FALSE for the rest, so it seems like the operation on the right side of the .default line should skip the first row:

testDf %>%
  rowwise() %>%
  mutate(f = all(is.na(c_across(b:d))))

# A tibble: 4 × 6
# Rowwise: 
      a     b     c     d     e f    
  <int> <int> <dbl> <int> <dbl> <lgl>
1     1    NA    NA    NA    NA TRUE 
2     2     5     8    11     5 FALSE
3     3     6    NA    12     6 FALSE
4     4     7    10    13     7 FALSE

I'm not a fan of suppressing warnings in general, and when there doesn't appear to be a problem in particular. Can't seem to pin down where I've gone wrong or if it's just a bug.


Solution

  • I believe the warning message is correct. case_when evaluates all its possible values before "deciding" which one to return. You're applying min to columns c and d in a rowwise manner. Some rows have NA in these columns. Therefore, case_when attempts to evaluate min(NA, na.rm = TRUE) for these rows and reports the warning for these intermediate values. But then case_when applies its logic to determine the final result.

    I agree it's better to avoid errors and warnings rather than suppressing them. To avoid the warning, you can switch to ifelse, which evaluates its arguments lazily:

    testDf <- tibble(
      a = 1:4,
      b = c(NA, 5:7),
      c = c(NA, 8, NA, 10),
      d = c(NA, 11:13)
    ) %>%
    rowwise() %>%
    mutate(
      e = ifelse(
        all(is.na(c_across(b:d))), 
        NA_integer_,
        min(c_across(b:d), na.rm=TRUE)
      )
    ) %>%
    ungroup()