I know this has already been answered, but as mutate_at() has been superseded, I thought I would contribute an answer using mutate(across(), which will also allow for the single underscore at the end of the new names in a single line. Using @FJCC's example data.frame above
DF3 <- DF %>%
mutate(across(.cols = last_col() + (-3:0),
.fns = ~if_else(. <= 0,"Low","High"),
.names = "{.col}_"))
Explanation:
across() takes three arguments (plus ...), they are the columns we want to act on (very similar to the first argument in mutate_at(), the functions we want to apply and a new naming format for the output.
For the .cols argument, I've passed the last_col() + (-3:0), which will select the last 4 columns (and doesn't require a look back at the original dataset with ncol(.) or ncol(DF))
For .fns, I used a lambda function where the input is substituted for the ..
For the naming, I used a glue-style string where {.col} evaluates to the name of the input column for each iteration. If we were using multiple functions in a list (just like in mutate_at(), we could use {.fn} as a substitute for the name of the function in the list. Word of warning, I had to update my dplyr to V1.0.2 for this last bit to work