Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dplyr - recode several columns at once

Tags:

r

dplyr

Suppose you have a dataframe with variables named X1 - X30 and Y1 - Y30. Each of these variables holds integers 1 - 5. We wish to recode some of the variables starting with X like this:

df %<>%
   mutate_at(vars(starts_with("X") & 
                  ends_with("5", "8", "16", "22", "28")), 
             recode, "1" = 5, "2" = 4, "4" = 2, "5" = 1)

This will, however, return the following error:

Error in UseMethod("recode") : 
  no applicable method for 'recode' applied to an object of class "c('tbl_df', 'tbl', 'data.frame')"

This is because recode needs to take a vector as an argument. So what is the way to bypass this?

like image 689
J. Doe Avatar asked Nov 21 '25 20:11

J. Doe


2 Answers

mutate_at is entirely designed to take functions that take vectors as an argument, like recode, that is not the issue. Your error is just because you don't use select helpers as logical calls chained with &, instead chain them using , within vars().

Also, if you want what you were aiming for, you would want to use matches to select only columns starting with X and ending with certain numbers.

library(dplyr)

set.seed(123)
df <- data.frame("X1" = sample(1:5, 10, TRUE),
                 "X2" = sample(1:5, 10, TRUE),
                 "X3" = sample(1:5, 10, TRUE)) 
df
#>    X1 X2 X3
#> 1   3  5  2
#> 2   3  3  1
#> 3   2  3  3
#> 4   2  1  4
#> 5   3  4  1
#> 6   5  1  3
#> 7   4  1  5
#> 8   1  5  4
#> 9   2  3  2
#> 10  3  2  5

df %>%
  mutate_at(vars(matches("^X.*1|2$")),
            recode, "1" = 5, "2" = 4, "3" = 3,"4" = 2, "5" = 1)
#>    X1 X2 X3
#> 1   3  1  2
#> 2   3  3  1
#> 3   4  3  3
#> 4   4  5  4
#> 5   3  2  1
#> 6   1  5  3
#> 7   2  5  5
#> 8   5  1  4
#> 9   4  3  2
#> 10  3  4  5
like image 155
caldwellst Avatar answered Nov 24 '25 11:11

caldwellst


Adding a 2021 updated solution including the across function that supersedes the mutate_* functions as well as regex and tidy_select alternatives

library(dplyr)

set.seed(123)
(df <- data.frame("X1" = sample(1:5, 10, TRUE),
                 "X2" = sample(1:5, 10, TRUE),
                 "X3" = sample(1:5, 10, TRUE)))
#>    X1 X2 X3
#> 1   3  5  2
#> 2   3  3  1
#> 3   2  3  3
#> 4   2  1  4
#> 5   3  4  1
#> 6   5  1  3
#> 7   4  1  5
#> 8   1  5  4
#> 9   2  3  2
#> 10  3  2  5

with regex

df %>%
      mutate(across(matches("^X.*1|2$"),
                recode, "1" = 5, "2" = 4, "3" = 3,"4" = 2, "5" = 1))

#>    X1 X2 X3
#> 1   3  1  2
#> 2   3  3  1
#> 3   4  3  3
#> 4   4  5  4
#> 5   3  2  1
#> 6   1  5  3
#> 7   2  5  5
#> 8   5  1  4
#> 9   4  3  2
#> 10  3  4  5

without regex

df %>%
  mutate(across((starts_with("X") & ends_with(as.character(1:2))),
                recode, "1" = 5, "2" = 4, "3" = 3,"4" = 2, "5" = 1))

    #>    X1 X2 X3
    #> 1   3  1  2
    #> 2   3  3  1
    #> 3   4  3  3
    #> 4   4  5  4
    #> 5   3  2  1
    #> 6   1  5  3
    #> 7   2  5  5
    #> 8   5  1  4
    #> 9   4  3  2
    #> 10  3  4  5
like image 33
Adrian Fletcher Avatar answered Nov 24 '25 11:11

Adrian Fletcher



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!