Search code examples
rdplyrcase

R replace only specific values and keep all others in dataframe


my code looks like this:

library(tidyverse)
df <- read.table(header=TRUE, text='
 subject sex control q1 q2
       1   M     7.9  1  1
       2   F     6.3  2  3
       3   F     9.5  3  1
       4   M    11.5  7  6
')

df %>% mutate_all(~case_when(
                              . == 1 ~ 7,
                              . == 7 ~ 1,
                              TRUE ~ . )
                  )

I want to replace all 1 with 7 and vice versa but keep everything else.

The error states:

Error: Problem with mutate() column subject. i subject = (structure(function (..., .x = ..1, .y = ..2, . = ..1) .... x must be a double vector, not an integer vector.

A solution indicates TRUE ~ as.numeric(as.character(.)) ) works, but then the sex colum is NA

How can I fix this?

Edit (add): A suggestion was to use nested if-else, which would work, but I really hope there is a better solution than: df %>% mutate_all(~ifelse(. == 1, 7, ifelse(. == 7, 1, .)))

imagine a long list of values to be replaced.


Solution

  • You can use either mutate_at() or mutate_if() to selectively choose which columns to apply the transformation to.

    df %>% mutate_at(c(3:5), ~case_when(
       . == 1 ~ 7,
       . == 7 ~ 1,
       TRUE ~ as.numeric(.))
    )
    
    df %>% mutate_if(is.numeric, ~case_when(
       . == 1 ~ 7,
       . == 7 ~ 1,
       TRUE ~ as.numeric(.))
    )
    

    Edit: a non-deprecated version without mutate_if would be:

    df %>% mutate(
          across(
            where(is.numeric), 
              ~case_when(
               . == 1 ~ 7,
               . == 7 ~ 1,
               TRUE ~ as.numeric(.)
              )
          )
    )