通过另一个 df 中的值修改 df 中的值 - 通过另一列中的相同列名和相同值

问题描述 投票:0回答:1

我有两个从我的数据派生的数据框。

一个包含限制:

lim <- structure(list(cpx = c("A", "B", "C", "D"), par_1 = c(5, 10, 
5, 1), par_2 = c(KET = 4.34, HNK = 8.68, NKT = 4.3, DHNK = 0.86
), par_3 = c(KET = 18.24, HNK = 36.21, NKT = 19.22, DHNK = 3.87
)), out.attrs = list(dim = c(4L, 2L), dimnames = list(Var1 = c("Var1=HNK", 
"Var1=KET", "Var1=NKT", "Var1=DHNK"), Var2 = c("Var2=LLOQ", "Var2=ULOQ"
))), class = "data.frame", row.names = c(NA, -4L))

第二个包含测量数据:


data <- structure(list(smp_id = c("aa", "aa", "aa", "aa", "bb", "bb", 
"bb", "bb", "cc", "cc", "cc", "cc", "dd", "dd", "dd", "dd", "ee", 
"ee", "ee", "ee"), cpx = c("A", "B", "C", "D", "A", "B", "C", 
"D", "A", "B", "C", "D", "A", "B", "C", "D", "A", "B", "C", "D"
), par_1 = c(4, 8, 4, 4, 4.5, 83, 6, 0.5, 5.5, 9, 4.5, 0.5, 20, 
13, 18, 0.5, 100, 33, 53, 0.5), par_2 = c(4, 4, 4, 4, 4.5, 3, 
3, 0.5, 5.5, 3, 3, 0.5, 20, 3, 3, 0.5, 100, 3, 3, 0.5), par_3 = c(4, 
4, 4, 0.4, 4.5, 3, 3, 0.9, 5.5, 3, 3, 2, 20, 3, 3, 4, 100, 3, 
3, 44)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-20L))

参数列的数量可能因设置而异。 此外,每个样本的 cpx 值数量可能会因集合而异(但在一组中是相同的)。

我需要将数据表中低于限制表中的 cpx/参数对值的每个值替换为 NA

我想出了如何分别对每个 cpx 值执行此操作。

limm_a <- limm %>% 
  filter(cpx == "A")

data_a <- data %>% 
  filter(cpx == "A") %>%
  mutate(across(matches("par"),
                ~if_else(.x < limm_a[[cur_column()]], NA, .x)
                  ))

我知道我可以在这个集合中的每个唯一的 cpx 上循环关闭它...... 但这不是我喜欢用的。

我尝试过一些组合,例如:

data <- data %>% 
  mutate(across(matches("par"),
                ~if_else(.x < limm[[cur_column()]][limm$cpx == data$cpx], NA, .x)
                  ))

尝试以不同的方式进行行过滤:

data <- data %>% 
  mutate(across(matches("par"),
                ~if_else(.x < filter(limm, cpx == .$cpx)[[cur_column()]], NA, .x)
                  ))

但这一切都失败了。 我对 R 还很陌生,仍在学习中。 我想以比使用 for 循环更优雅的方式来完成它。

br 拉德克

r dplyr tidyverse
1个回答
1
投票

我确信一定有一种更优雅的方法可以在没有

limcol <- get(paste0(cur_column(), "_lim"))
的情况下做到这一点,但我认为这会得到您所需的结果:

编辑:已更新以显示值小于要求的 NA

data %>%
  left_join(lim, by = "cpx", suffix = c("", "_lim")) %>%
  mutate(across(matches("^par_\\d$"), \(x) {limcol <- get(paste0(cur_column(), "_lim" )); if_else(x < limcol, NA_real_, x)})) %>%
  select(!matches("_lim"))

# A tibble: 20 × 5
   smp_id cpx   par_1  par_2  par_3
   <chr>  <chr> <dbl>  <dbl>  <dbl>
 1 aa     A       5     4.34  18.2 
 2 aa     B      10     8.68  36.2 
 3 aa     C       5     4.3   19.2 
 4 aa     D       4     4      3.87
 5 bb     A       5     4.5   18.2 
 6 bb     B      83     8.68  36.2 
 7 bb     C       6     4.3   19.2 
 8 bb     D       1     0.86   3.87
 9 cc     A       5.5   5.5   18.2 
10 cc     B      10     8.68  36.2 
11 cc     C       5     4.3   19.2 
12 cc     D       1     0.86   3.87
13 dd     A      20    20     20   
14 dd     B      13     8.68  36.2 
15 dd     C      18     4.3   19.2 
16 dd     D       1     0.86   4   
17 ee     A     100   100    100   
18 ee     B      33     8.68  36.2 
19 ee     C      53     4.3   19.2 
20 ee     D       1     0.86  44   
© www.soinside.com 2019 - 2024. All rights reserved.