sbradbio
sbradbio

Reputation: 169

conditional replace elements in data frame using dplyr

head(df)

    genotype.og label   genotype
MT1 MT1 MT
MT2 MT2 MT
MT3 MT3 MT
MT4 MT4 MT
MT5 MT5 MT
MT6 MT6 MT
WT1 WT1 WT
WT4 WT4 WT
WT11    WT11    WT
WT13    WT13    WT
WT27    WT27    WT
WT28    WT28    WT
WT74    WT74    WT
WT53    WT53    WT
WT68    WT68    WT
WT84    WT84    WT
WT92    WT92    WT
WT95    WT95    WT

Somewhere down the rows I have rows with WT1..WTn. Trying to change only few elements from the label column without changing others. Made a variable called old that holds the names of elements that need to be replaced/renamed.

Code

old = c("WT1","WT4","WT11","WT13","WT27","WT28","WT74","WT53","WT68","WT84","WT92","WT95")
new = c("WS1","WS4","WS11","WS13","WS27","WS28","WS74","WS53","WS68","WS84","WS92","WS95")
df$label_new <- df$label %>% rename_if(vars(old), ~ new)

Error

Error in UseMethod("tbl_vars") : 
  no applicable method for 'tbl_vars' applied to an object of class "character" 

desired output

genotype.og label   genotype    label_new
MT1 MT1 MT  MT1
MT2 MT2 MT  MT2
MT3 MT3 MT  MT3
MT4 MT4 MT  MT4
MT5 MT5 MT  MT5
MT6 MT6 MT  MT6
WT1 WT1 WT  WS1
WT4 WT4 WT  WS4
WT11    WT11    WT  WS11
WT13    WT13    WT  WS13
WT27    WT27    WT  WS27
WT28    WT28    WT  WS28
WT74    WT74    WT  WS74
WT53    WT53    WT  WS53
WT68    WT68    WT  WS68
WT84    WT84    WT  WS84
WT92    WT92    WT  WS92
WT95    WT95    WT  WS95

What am I missing?

Upvotes: 1

Views: 1366

Answers (2)

acylam
acylam

Reputation: 18661

With str_replace_all from stringr. str_replace_all takes a named vector for match and replacement, where the names are the patterns to match and the values are the replacements. ^ and $ regular expression metacharacters are wrapped onto each pattern to make sure that they are exact matches:

library(stringr)
library(dplyr)

df %>%
  mutate(label_new = str_replace_all(label, setNames(new, paste0('^', old, '$'))))

The lookup string becomes:

> setNames(new, paste0('^', old, '$'))
 ^WT1$  ^WT4$ ^WT11$ ^WT13$ ^WT27$ ^WT28$ ^WT74$ ^WT53$ ^WT68$ ^WT84$ ^WT92$ ^WT95$ 
 "WS1"  "WS4" "WS11" "WS13" "WS27" "WS28" "WS74" "WS53" "WS68" "WS84" "WS92" "WS95"

or with Base R:

df$label_new <- df$label
label_match <- match(df$label_new, old)
df$label_new[!is.na(label_match)] <- new[na.omit(label_match)]

Output:

   genotype.og label genotype label_new
1          MT1   MT1       MT       MT1
2          MT2   MT2       MT       MT2
3          MT3   MT3       MT       MT3
4          MT4   MT4       MT       MT4
5          MT5   MT5       MT       MT5
6          MT6   MT6       MT       MT6
7          WT1   WT1       WT       WS1
8          WT4   WT4       WT       WS4
9         WT11  WT11       WT      WS11
10        WT13  WT13       WT      WS13
11        WT27  WT27       WT      WS27
12        WT28  WT28       WT      WS28
13        WT74  WT74       WT      WS74
14        WT53  WT53       WT      WS53
15        WT68  WT68       WT      WS68
16        WT84  WT84       WT      WS84
17        WT92  WT92       WT      WS92
18        WT95  WT95       WT      WS95

Data:

df <- structure(list(genotype.og = c("MT1", "MT2", "MT3", "MT4", "MT5", 
"MT6", "WT1", "WT4", "WT11", "WT13", "WT27", "WT28", "WT74", 
"WT53", "WT68", "WT84", "WT92", "WT95"), label = c("MT1", "MT2", 
"MT3", "MT4", "MT5", "MT6", "WT1", "WT4", "WT11", "WT13", "WT27", 
"WT28", "WT74", "WT53", "WT68", "WT84", "WT92", "WT95"), genotype = c("MT", 
"MT", "MT", "MT", "MT", "MT", "WT", "WT", "WT", "WT", "WT", "WT", 
"WT", "WT", "WT", "WT", "WT", "WT")), .Names = c("genotype.og", 
"label", "genotype"), class = "data.frame", row.names = c(NA, 
-18L))

Upvotes: 2

Jon Spring
Jon Spring

Reputation: 66415

I prefer @avid_useR's solution, but here's an approach that shows the mapping along the way.

library(dplyr)
df <- df %>% 
  # Join with the replacement strings; NA where no replacement
  left_join(data_frame(old, new), by = c("label" = "old")) %>%
  # Update label to use replacement where available
  mutate(label = if_else(is.na(new), label, new)) %>%
  select(-new)

Upvotes: 1

Related Questions