分组依据+汇总R中具有子集行的多列

Groupby + summarise on multicolumns with subseted rows in R

我正在尝试找出一个干净且 tidy 的表达式,以使用 group_bysummarise 的子集行来聚合多个列的统计信息。下面是一个用循环解决的例子。

# example data
dat <- data.frame(
  method = rep(c("A", "B", "baseline"), 2),
  id = rep(1:2, each = 3),
  X = round(rnorm(6, 1, 0.2),3),
  Y = round(runif(6, 1, 2),3)
)
print(dat)
#>     method id     X     Y
#> 1        A  1 0.859 1.003
#> 2        B  1 0.993 1.922
#> 3 baseline  1 1.401 1.959
#> 4        A  2 1.084 1.432
#> 5        B  2 1.083 1.883
#> 6 baseline  2 0.943 1.341

我们将ABbaseline作为方法名,XY作为评价标准,id作为重复实验的ID。然后,我们想弄清楚方法 A 和方法 B 在 XY 意义上获得了多少改进。改进衡量为评估标准相对于基线的相对收缩方法。

result <- dat[0,]
for (i in unique(dat$id)) {
  score_A <- dat[dat$id == i & dat$method == "A", c("X", "Y")]
  score_B <- dat[dat$id == i & dat$method == "B", c("X", "Y")]
  score_baseline <- dat[dat$id == i & dat$method == "baseline", c("X", "Y")]
  
  result <- rbind(
    result,
    cbind(
      data.frame(method = c("A", "B")),
      rbind(
        (score_baseline - score_A) / score_baseline,
        (score_baseline - score_B) / score_baseline
      )
    )
  )
}
print(result)
#>    method          X           Y
#> 3       A  0.3868665  0.48800408
#> 31      B  0.2912206  0.01888719
#> 6       A -0.1495228 -0.06785981
#> 61      B -0.1484624 -0.40417599

现在,对于上面的结果,我想要一个更 tidy 的解决方案。

使用 across 你可以:

注意:使用随机数据时应使用set.seed。因此,我的随机数据与您提供的数据不同。

library(dplyr)

dat %>%
  group_by(id) %>%
  mutate(across(c(X, Y), ~ (.x[method == "baseline"] - .x) / .x[method == "baseline"])) %>%
  ungroup() %>%
  filter(!method == "baseline")
#> # A tibble: 4 × 4
#>   method    id     X      Y
#>   <chr>  <int> <dbl>  <dbl>
#> 1 A          1 0.323 -0.521
#> 2 B          1 0.273 -0.426
#> 3 A          2 0.245 -0.823
#> 4 B          2 0.236 -0.196

数据

set.seed(123)

dat <- data.frame(
  method = rep(c("A", "B", "baseline"), 2),
  id = rep(1:2, each = 3),
  X = round(rnorm(6, 1, 0.2), 3),
  Y = round(runif(6, 1, 2), 3)
)