【问题标题】:Mutate values in one column based on another column根据另一列改变一列中的值
【发布时间】:2021-06-10 16:30:50
【问题描述】:

我有一个包含许多数字数据列的数据框,并与相应的质量列配对。 在下面的示例中,dat 是一个数据框,其数字列 v1v3 与质量控制列 v1_av3_a 配对。 v2 没有质量控制栏。

如果v1_av3_a 中的对应值是“A”或“D”,我想将v1v3 中的所有值设置为NA_real_。我正在 dplyr 中寻找一种方法,并使用 %>% 可以扩展到任意数量的配对数字和质量控制列。

set.seed(10)
dat   <- tibble(v1 = runif(10)
                , v1_a = c("A", "A", NA, "B", NA, NA, NA, "D", NA, "A" )
                , v2 = runif(10)
                , v3 = runif(10)
                , v3_a = c(NA, "A", "D", "B", NA, "A", NA, "A", NA, "A" ))

dat
       v1 v1_a      v2    v3 v3_a 
 1 0.536  A     0.275  0.354 NA   
 2 0.0931 A     0.229  0.936 A    
 3 0.170  NA    0.0144 0.246 D    
 4 0.900  B     0.729  0.473 B    
 5 0.423  NA    0.250  0.192 NA   
 6 0.748  NA    0.161  0.583 A    
 7 0.823  NA    0.0170 0.459 NA   
 8 0.955  D     0.486  0.467 A    
 9 0.685  NA    0.103  0.400 NA   
10 0.501  A     0.802  0.505 A     

对于上述示例数据,假设我要筛选“A”和“D”(而不是“B”或 NA),结果将是:

       v1 v1_a      v2     v3 v3_a 
 1 NA     A     0.275   0.354 NA   
 2 NA     A     0.229  NA     A    
 3  0.170 NA    0.0144 NA     D    
 4  0.900 B     0.729   0.473 B    
 5  0.423 NA    0.250   0.192 NA   
 6  0.748 NA    0.161  NA     A    
 7  0.823 NA    0.0170  0.459 NA   
 8 NA     D     0.486  NA     A    
 9  0.685 NA    0.103   0.400 NA   
10 NA     A     0.802  NA     A 

为了创建上述内容,我为每个感兴趣的列使用了case_when 帮助函数,如下所示

rmkQC <- c("A","D")  # vector of values to screen
    
dat %>%
  mutate(v1 = case_when(v1_a %in% rmkQC ~ NA_real_
                        , TRUE ~ v1)
         , v3 = case_when(v3_a %in% rmkQC ~ NA_real_
                        , TRUE ~ v3))

我需要做的是概括这一点,以便它可以应用于具有未知数量的成对列的数据框。不确定这是否重要,但我可以使用以下代码识别配对列。

colQC <- names(dat)[grep("_a" , names(dat))]
colV  <- sub("_a$","",colQC)

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    这是tidyverse中的一种方法

    1. 循环across感兴趣的列('v1','v3')
    2. 获取列名(cur_column()),pastestr_c)后缀部分('_a'),get列值
    3. case_when 内创建带有%in% 的逻辑向量,并将逻辑向量中为真的向量替换为NA
    library(dplyr)
    dat1 <- dat %>%
          mutate(across(all_of(colV), ~ case_when(get(str_c(cur_column(), 
                 '_a')) %in% rmkQC ~ NA_real_, TRUE ~ .)))
    

    -输出

    dat1
    # A tibble: 10 x 5
            v1 v1_a      v2     v3 v3_a 
         <dbl> <chr>  <dbl>  <dbl> <chr>
     1 NA      A     0.652   0.865 <NA> 
     2 NA      A     0.568  NA     A    
     3  0.427  <NA>  0.114  NA     D    
     4  0.693  B     0.596   0.356 B    
     5  0.0851 <NA>  0.358   0.406 <NA> 
     6  0.225  <NA>  0.429  NA     A    
     7  0.275  <NA>  0.0519  0.838 <NA> 
     8 NA      D     0.264  NA     A    
     9  0.616  <NA>  0.399   0.771 <NA> 
    10 NA      A     0.836  NA     A   
    

    base R我们也可以这样做

    dat[colV] <-  dat[colV] * NA^`dim<-`(as.matrix(dat[colQC]) %in% 
           rmkQC, dim(dat[colQC]))
    

    【讨论】:

      【解决方案2】:

      虽然我的答案与dear Akrun's 几乎相同,但仍要向您展示它可以通过多种方式完成

      dat %>%
        mutate(across(c(v1, v3), ~ replace(., get(paste0(cur_column(), '_a')) %in% c('A', 'D'), NA)))
      
      # A tibble: 10 x 5
              v1 v1_a      v2     v3 v3_a 
           <dbl> <chr>  <dbl>  <dbl> <chr>
       1 NA      A     0.652   0.865 NA   
       2 NA      A     0.568  NA     A    
       3  0.427  NA    0.114  NA     D    
       4  0.693  B     0.596   0.356 B    
       5  0.0851 NA    0.358   0.406 NA   
       6  0.225  NA    0.429  NA     A    
       7  0.275  NA    0.0519  0.838 NA   
       8 NA      D     0.264  NA     A    
       9  0.616  NA    0.399   0.771 NA   
      10 NA      A     0.836  NA     A 
      

      【讨论】:

      • 欣赏替代策略...因为使用 paste0 避免需要使用 tidyverse(实际上是 stringr)来获取 str_c
      猜你喜欢
      • 1970-01-01
      • 2019-06-19
      • 2021-09-05
      • 1970-01-01
      • 2016-01-23
      • 2018-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多