分组后使用 dplyr 按列划分的多个比率

Multiple ratios by column-wise division with dplyr following grouping

我有一个 df 需要按多列分组,以便随后计算不同列的子集的比率以及逐行均值和标准差。

grouper1 grouper2 condition value
foo      baz      A         1
foo      baz      B         2
foo      oof      A         1
foo      oof      C         3
bar      zab      B         2
bar      zab      C         4

基于这个优雅的 我已经成功构建了一个通用的解决方案:

library(dplyr)
library(tidyr)
library(purrr)
library(stringr)


crossing(c("A"), c("B","C")) %>%
  pmap(~ query %>%
         group_by(grouper1, grouper2) %>%
            summarise(!! str_c('ratio_', ..1, ..2) :=
                 value[condition == ..1]/value[condition == ..2])) %>% 
            reduce(full_join, by = c('grouper1', 'grouper2')) %>% 
  ungroup() %>% mutate(mean=rowMeans(select(.,-(grouper1, grouper2)), SD=unlist(pmap(select(.,-(grouper1, grouper2)), ~sd(c(...)))))

如果在所有组中都找到 condition 列中的所有值,则此方法效果很好。如果不是这种情况,例如A 在上例中使用 grouper1 的第二个分组中不存在,我将收到以下错误:

Error: Column ratio_AC must be length 1 (a summary value), not 0

我显然可以预先选择 crossing 的值,但这需要对 df 进行筛选,这样我就失去了通用性。因此,我想要一个简单地忽略缺失组合并仍然计算指标的解决方案。

一个可能的解决方案是 pivot_wider,但在这里我无法实施计算比率的有效解决方案。

我们可以使用 pivot_wider 重塑为宽格式,然后使用该数据集

library(dplyr)
library(tidyr)
library(purrr)
library(stringr)
df1 <- df %>% 
          pivot_wider(names_from = condition, values_from = value)


crossing(v1 = c("A"), v2 = c("B","C")) %>%
  pmap(~ df1 %>%           
           transmute(grouper1, grouper2, 
          !! str_c('ratio_', ..1, ..2) :=
                 .[[..1]]/.[[..2]]))%>% 
            reduce(full_join, by = c('grouper1', 'grouper2'))  %>%
   mutate(mean = rowMeans(select(., -grouper1, -grouper2), na.rm = TRUE), 
          SD=   pmap_dbl(select(., -grouper1, -grouper2), 
              ~sd(c(...), na.rm = TRUE)))

数据

df <- structure(list(grouper1 = c("foo", "foo", "foo", "foo", "bar", 
"bar"), grouper2 = c("baz", "baz", "oof", "oof", "zab", "zab"
), condition = c("A", "B", "A", "C", "B", "C"), value = c(1L, 
2L, 1L, 3L, 2L, 4L)), class = "data.frame", row.names = c(NA, 
-6L))