Perform a operation on the last column using mutate

Viewed 49

Is there any way to reference the last column within mutate so that you can do an operation on it? For instance:

library(dplyr)
library(tidyr)
dat <- data.frame(
  col1 = c(1, 1, 1),
  col2 = c(0, 1, 0),
  col3 = c(2, 0, 2)
)

## what i was thinking:
dat %>%
  mutate(col1_bigger_than_col3 = col1 > last_col())
#> Error in `mutate()`:
#> ! Problem while computing `col1_bigger_than_col3 = col1 > last_col()`.
#> Caused by error:
#> ! `last_col()` must be used within a *selecting* function.
#> ℹ See <https://tidyselect.r-lib.org/reference/faq-selection-context.html>.

#> Backtrace:
#>      ▆
#>   1. ├─dat %>% mutate(col1_bigger_than_col3 = col1 > last_col())
#>   2. ├─dplyr::mutate(., col1_bigger_than_col3 = col1 > last_col())
#>   3. ├─dplyr:::mutate.data.frame(., col1_bigger_than_col3 = col1 > last_col())
#>   4. │ └─dplyr:::mutate_cols(.data, dplyr_quosures(...), caller_env = caller_env())
#>   5. │   ├─base::withCallingHandlers(...)
#>   6. │   └─mask$eval_all_mutate(quo)
#>   7. └─tidyselect::last_col()
#>   8.   ├─vars %||% peek_vars(fn = "last_col")
#>   9.   └─tidyselect::peek_vars(fn = "last_col")
#>  10.     └─rlang::abort(msg, call = NULL)

## output i want
dat %>%
  mutate(col1_bigger_than_col3 = col1 > col3)
#>   col1 col2 col3 col1_bigger_than_col3
#> 1    1    0    2                 FALSE
#> 2    1    1    0                  TRUE
#> 3    1    0    2                 FALSE
3 Answers

We may use last_col() in select or in across

library(dplyr)
dat %>% 
   mutate(col1_bigger_than_col3 = col1 > across(last_col())[[1]])

-output

  col1 col2 col3 col1_bigger_than_col3
1    1    0    2                 FALSE
2    1    1    0                  TRUE
3    1    0    2                 FALSE

Or update with .names after doing the calculation inside across

dat %>%
   mutate(across(last_col(), ~ col1 > .x,
     .names = "col1_bigger_than_{.col}"))
  col1 col2 col3 col1_bigger_than_col3
1    1    0    2                FALSE
2    1    1    0                 TRUE
3    1    0    2                FALSE

One way could be using the subsetted ncol function:

library(dplyr)

dat %>%
  mutate(col1_bigger_than_col3 = col1 > .[, ncol(dat)])

  col1 col2 col3 col1_bigger_than_col3
1    1    0    2                 FALSE
2    1    1    0                  TRUE
3    1    0    2                 FALSE

Try ncol():

dat %>% 
  mutate(col1_bigger_than_col3 = col1 > .[[ncol(.)]])
#>   col1 col2 col3 col1_bigger_than_col3
#> 1    1    0    2                 FALSE
#> 2    1    1    0                  TRUE
#> 3    1    0    2                 FALSE
Related