分组依据+汇总R中具有子集行的多列
Groupby + summarise on multicolumns with subseted rows in R
我正在尝试找出一个干净且 tidy
的表达式,以使用 group_by
和 summarise
的子集行来聚合多个列的统计信息。下面是一个用循环解决的例子。
# 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
我们将A
、B
、baseline
作为方法名,X
、Y
作为评价标准,id
作为重复实验的ID。然后,我们想弄清楚方法 A 和方法 B 在 X
和 Y
意义上获得了多少改进。改进衡量为评估标准相对于基线的相对收缩方法。
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)
)
我正在尝试找出一个干净且 tidy
的表达式,以使用 group_by
和 summarise
的子集行来聚合多个列的统计信息。下面是一个用循环解决的例子。
# 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
我们将A
、B
、baseline
作为方法名,X
、Y
作为评价标准,id
作为重复实验的ID。然后,我们想弄清楚方法 A 和方法 B 在 X
和 Y
意义上获得了多少改进。改进衡量为评估标准相对于基线的相对收缩方法。
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)
)