dplyr 使用条件列和特定行进行变异

Posted

技术标签:

【中文标题】dplyr 使用条件列和特定行进行变异【英文标题】:dplyr mutate using conditional column and specific rows 【发布时间】:2018-06-24 19:47:21 【问题描述】:

我有一个带有两个分数列的 data.frame。我想逐行有条件地使用其中一个的数据。我用下面的例子来解释......

> dff <- data.frame(dataset = c('Main','Main','b','b','c','c','d','d'), 
+                  score1 = c(0.01,0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08), 
+                  score2 = c(0.001, 0.2, 0.003, 0.4, 0.005, 0.6, 0.007, 0.8),
+                  name = c('A','B','A','B','A','B','A','B')); 
> dff
  dataset score1 score2 name
1    Main   0.01  0.001    A
2    Main   0.02  0.200    B
3       b   0.03  0.003    A
4       b   0.04  0.400    B
5       c   0.05  0.005    A
6       c   0.06  0.600    B
7       d   0.07  0.007    A
8       d   0.08  0.800    B

我正在尝试从一个分数中为name == 'A' 的所有行选择所有值,name == 'B' 的值类似。我选择哪个分数取决于dataset == 'Main' 时哪个分数较小。

因此,例如,在此示例中,当 name == 'A' 时,score2 低于 score1Main 数据集。因此,对于name == 'A' 所在的所有行,我将使用它们来自score2 的值。

name == 'B' 时,score1 低于 score2Main 数据集。因此,对于name == 'B' 所在的所有行,我将使用它们来自score1 的值。最终结果如下所示:

  dataset score1 score2 name final
1    Main   0.01  0.001    A 0.001
2    Main   0.02  0.200    B 0.020
3       b   0.03  0.003    A 0.003
4       b   0.04  0.400    B 0.040
5       c   0.05  0.005    A 0.005
6       c   0.06  0.600    B 0.060
7       d   0.07  0.007    A 0.007
8       d   0.08  0.800    B 0.080

所以我要做的是有条件地变异并创建新的final 列,具体取决于该行的名称,以及具有相同名称的Main 数据集的哪一列较小。我试图想出一些优雅的东西来完成这个,而不是一堆奇怪的代码行,但我还没有能够完成那个。

编辑: 我在这里包含了我的实际数据的样本。

structure(list(datasets = c("main", "main", "bms", "bms", "sny", 
"sny", "chen", "chen", "van", "van"), test_high = c(0.639654382299527, 
0.561881930194033, NA, NA, 0.909598942079794, 0.651429614317738, 
0.189274551669056, 0.541845226349475, 0.41969855766237, 0.555858598773613
), test_low = c(0.402779917451124, 0.469868712458501, NA, NA, 
0.106383376175001, 0.381060050671353, 0.824427629626441, 0.468590829264603, 
0.594646024750062, 0.460036802365713), cell = c("high", "low", 
"low", "high", "high", "low", "high", "low", "low", "high")), .Names = c("datasets", 
"test_high", "test_low", "cell"), class = c("tbl_df", "tbl", 
"data.frame"), row.names = c(NA, -10L))


   # A tibble: 10 x 4
   datasets test_high  test_low  cell
      <chr>     <dbl>     <dbl> <chr>
 1     main 0.6396544 0.4027799  high
 2     main 0.5618819 0.4698687   low
 3      bms        NA        NA   low
 4      bms        NA        NA  high
 5      sny 0.9095989 0.1063834  high
 6      sny 0.6514296 0.3810601   low
 7     chen 0.1892746 0.8244276  high
 8     chen 0.5418452 0.4685908   low
 9      van 0.4196986 0.5946460   low
10      van 0.5558586 0.4600368  high

在这种情况下,Final 最终将与 test_low 相同,因为对于两个 Mains(即当单元格为“高”且单元格为“低”时),test_low 列小于 test_high 列。

【问题讨论】:

在编辑中,预期的输出列是什么。看起来main 的 'test_high' 比 'high' 和 'low' 更高 【参考方案1】:

一个选项是case_when

library(dplyr)
dff %>%
    mutate(final =  case_when(name == "A" & dataset == "Main" ~ score2,
                       name == "B" & dataset=="Main" ~score1, 
                       TRUE ~ pmin(score1, score2)))
#  dataset score1 score2 name final
#1    Main   0.01  0.001    A 0.001
#2    Main   0.02  0.200    B 0.020
#3       b   0.03  0.003    A 0.003
#4       b   0.04  0.400    B 0.040
#5       c   0.05  0.005    A 0.005
#6       c   0.06  0.600    B 0.060
#7       d   0.07  0.007    A 0.007
#8       d   0.08  0.800    B 0.080

基于编辑的数据集('dfn'),

dfn %>%
     filter(datasets == "main") %>% 
     gather(test, val, test_high:test_low) %>% 
     group_by(cell) %>% 
     summarise(test = test[which.max(val)]) %>% 
     left_join(dfn, .) %>%
     rowwise() %>% 
     mutate(final = get(test)) %>%
     select(-test)

【讨论】:

对,但问题在于使用哪一列应该取决于数据集 == 'Main' 时的值。所以有时我可能同时拥有 score1 和 score1,或者同时拥有 score2 和 score2,等等。 @Brandon 我也在逻辑中添加了Main 啊,我明白这个逻辑在做什么了。我需要对此进行调整,以便其他行使用数据集 ==“Main”时的信息。所以事情是这样开始的:case_when(name == "A" & dataset == "Main" ~ pmin(score1, score2), name == "B" & dataset == "Main" ~ pmin(score1, score2) , name == "A" ~ 当 name =="A" 和 dataset =="Main" 时使用任何列是最小值,name == "B" ~ 当 name = 时使用任何列是最小值="B" 和数据集 =="Main")。这有意义吗? @Brandon 我认为您的示例有点造成混淆。你能否再举一个例子来给出一个独特的输出,而不是仅仅做一些ifelse 并获得预期的输出 @Brandon 我更新了一个解决方案。请检查是否符合您的预期【参考方案2】:
dff$final <- ifelse(dff$score2 < dff$score1 & dff$dataset == 'Main', dff$score2, dff$score1)

【讨论】:

以上是关于dplyr 使用条件列和特定行进行变异的主要内容,如果未能解决你的问题,请参考以下文章

从具有特定列和条件的数据框中选择行(不使用列名)

在特定条件下从数据框中提取行

dplyr 变异()。变异一个变量的问题,取决于匹配由matches()选择的特定名称的其他列中的非缺失值

R 根据多个条件获取行 - 使用 dplyr 和 reshape2

R:dplyr条件汇总并按列重新编码值

Dplyr条件逻辑计数行数