Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

r - How can I use mutate() and case_when() in a for loop?

I'm writing a Shiny app where the user will be inputting data for conditions of their samples, and the script will "automatically" match their inputted conditions to sample names of a given file.

For simplicity, I will not include the shiny code, because I am only struggling with the actual R implementation.

If I already know what the potential conditions are, I could do something like:

library(tidyverse)
x <- data.frame(Samples = c('Low1', 'Low2', 'High1', 'High2', 
                           'Ctrl1', 'Ctrl2'))

x <- x %>% mutate(Conditions = case_when(
           str_detect(Samples, fixed("low", ignore_case = T)) ~ "low",
           str_detect(Samples, fixed("high", ignore_case = T)) ~ "high",
           str_detect(Samples, fixed("ctrl", ignore_case = T)) ~ "ctrl"))

And I would get what I am looking for, a data frame like:

Samples    Conditions
   Low1           low
   Low2           low
  High1          high
  High2          high
  Ctrl1          ctrl
  Ctrl2          ctrl

However, I want to loop through a vector of potential conditions and do something like:

library(tidyverse)
condition_options <- c('low', 'high', 'ctrl')

x <- data.frame(Samples = samplenames)
for (j in condition_options) {
   x <- x %>% mutate(Condition = case_when(
        str_detect(Samples, fixed(j, ignore_case = T)) ~ j)) 
    }

When I do this, the Condition column is re-written only giving me matches for the last value in the vector. For example:

Samples    Conditions
   Low1         <NA>
   Low2         <NA>
  High1         <NA>
  High2         <NA>
  Ctrl1         ctrl
  Ctrl2         ctrl
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This might be easier if you build all parts of your case_when statement with meta-programming rather than doing a loop. Try

library(tidyverse)
condition_options <- c('low', 'high', 'ctrl')

conditions <- purrr::map(condition_options, 
                         ~quo(str_detect(Samples, fixed(!!.x, ignore_case = T))~!!.x))

# check our work
# cat(map_chr(conditions, quo_text), sep = "
")
# str_detect(Samples, fixed("low", ignore_case = T)) ~ "low"
# str_detect(Samples, fixed("high", ignore_case = T)) ~ "high"
# str_detect(Samples, fixed("ctrl", ignore_case = T)) ~ "ctrl"

x <- data.frame(Samples = samplenames)
x %>% mutate(Condition = case_when(!!!conditions) )

#   Samples Condition
# 1    Low1       low
# 2    Low2       low
# 3   High1      high
# 4   High2      high
# 5   Ctrl1      ctrl
# 6   Ctrl2      ctrl

Here the map build all the different formulas you would expect to have in the case_when statement. Then we use !!! to insert them into the mutate expression.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...