按其他列因子聚合列[重复]
Posted
技术标签:
【中文标题】按其他列因子聚合列[重复]【英文标题】:Aggregate columns by other column factor [duplicate] 【发布时间】:2021-01-30 02:18:18 【问题描述】:我有一些数据,其中包含每个样本中的单个物种及其数量。每个物种也按其营养模式标记。它看起来像这样:
OTU_ID Trophic.Mode Sample1 Sample2 Sample3 Sample4
gatca Symbiotroph 4 5 6 1
atca Pathotroph 4 3 4 4
gatac Pathotroph 7 1 2 1
以此类推,它有 2700 行,带有标记营养模式的物种计数。 我想聚合数据,以便每个样本都有一个更简单的功能社区,按 Trophic.Mode 列(它有 5 个因素,所以我期待一个有 5 行的数据框),所以我最终得到这个:
Trophic.Mode Sample1 Sample2 Sample3 Sample4
Symbiotroph 4 5 6 1
Pathotroph 13 18 15 11
因此我使用了以下代码:
agg = aggregate(data,
by = list(data$Trophic.Mode),
FUN = sum)
这只是返回一个错误
"Error in Summary.factor(c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, :
‘sum’ not meaningful for factors
但我不确定我是否理解 - 我想按这些因素对其他列求和。
【问题讨论】:
它试图对data
参数中的所有列求和。您需要告诉 aggregate
它不需要对 OTU_ID
或 Trophic.Mode
列求和 - 这是因素。将 data
更改为 data[-(1:2)]
以省略前两列。 (编辑:需要删除前 2 列)
谢谢,Gregor 成功了,我有点尴尬,我没有意识到这一点
“我有点尴尬,我没有意识到这一点” 别这样。这就是为什么这个网站上有成千上万的 R 问题。
【参考方案1】:
我更喜欢聚合的公式语法,因为公式右侧的分组列将自动从摘要中省略:
aggregate(. ~ Trophic.Mode, data = data[-1], FUN = sum)
by
的非公式接口在您想按数据中不是列的内容进行分组时非常有用。
【讨论】:
【参考方案2】:我想按这些因素对其他列求和。
这就是rowsum
的用途:
rowsum(data[, -(1:2)], data$Trophic.Mode)
#R> Sample1 Sample2 Sample3 Sample4
#R> Pathotroph 11 4 6 5
#R> Symbiotroph 4 5 6 1
这在击键和计算时间方面都很难被击败:
# simulate your ~2700 row data set
set.seed(1)
n <- 2700L
sim_dat <- data.frame(
Trophic.Mode = sample.int(5, n, replace = TRUE),
sample = matrix(sample.int(10, n * 4L, replace = TRUE), n))
colnames(sim_dat)[-1] <- paste0("sample", 1:4)
head(sim_dat, 3)
#R> Trophic.Mode sample1 sample2 sample3 sample4
#R> 1 1 9 6 9 6
#R> 2 4 1 6 3 1
#R> 3 1 9 9 10 9
# check that we get the same
r1 <- aggregate(. ~ Trophic.Mode, data = sim_dat, FUN = sum)
r2 <- rowsum(sim_dat[, -1], sim_dat$Trophic.Mode)
all.equal(r1[, -1], r2, check.attributes = FALSE)
#R> [1] TRUE
library(tidyverse)
r3 <- sim_dat %>%
group_by(Trophic.Mode) %>%
summarise_all(sum) %>%
ungroup()
all.equal(r3[, -1], r2, check.attributes = FALSE)
#R> [1] TRUE
# check the computation time
bench::mark(
aggregate = aggregate(. ~ Trophic.Mode, data = sim_dat, FUN = sum),
rowsum = rowsum(sim_dat[, -1], sim_dat$Trophic.Mode),
tidy = sim_dat %>%
group_by(Trophic.Mode) %>%
summarise_all(sum) %>%
ungroup(),
min_time = 2, check = FALSE)
#R> # A tibble: 3 x 13
#R> expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
#R> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
#R> 1 aggregate 2.28ms 2.45ms 396. 1.37MB 17.4 612 27 1.55s
#R> 2 rowsum 110.93µs 129.8µs 7449. 53.23KB 11.2 9985 15 1.34s
#R> 3 tidy 3.49ms 4.63ms 209. 93.41KB 6.56 383 12 1.83s
这比其他方法快了近 20 倍,但几毫秒的开始不算什么......
更新
根据要求,这是带有n <- 500000L
(500k 行)和不带ungroup
的基准:
bench::mark(
aggregate = aggregate(. ~ Trophic.Mode, data = sim_dat, FUN = sum),
rowsum = rowsum(sim_dat[, -1], sim_dat$Trophic.Mode),
tidy = sim_dat %>%
group_by(Trophic.Mode) %>%
summarise_all(sum),
min_time = 2, check = FALSE)
#R> # A tibble: 3 x 13
#R> expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
#R> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
#R> 1 aggregate 203.5ms 264.5ms 3.64 234.56MB 25.5 8 56 2.19s
#R> 2 rowsum 11ms 11.2ms 84.8 7.82MB 14.0 170 28 2s
#R> 3 tidy 12.8ms 13.4ms 64.8 17.36MB 25.9 130 52 2s
对于n <- 10000000L
(10M):
bench::mark(
aggregate = aggregate(. ~ Trophic.Mode, data = sim_dat, FUN = sum),
rowsum = rowsum(sim_dat[, -1], sim_dat$Trophic.Mode),
tidy = sim_dat %>%
group_by(Trophic.Mode) %>%
summarise_all(sum),
min_time = 30, check = FALSE)
#R> expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
#R> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
#R> 1 aggregate 5.82s 5.92s 0.168 5.05GB 2.18 6 78 35.8s
#R> 2 rowsum 275.46ms 285.37ms 3.41 204.29MB 0.796 103 24 30.2s
#R> 3 tidy 233.38ms 264.47ms 3.66 331.03MB 2.03 110 61 30.1s
事实证明,对于较大的数据集而言,差异很小。
【讨论】:
如果您要运行基准测试,请在足够重要的数据版本上进行 - 我建议至少 500k 行。如果您要进行基准测试(如果性能很重要),您也应该输入data.table
。
我也会摆脱ungroup()
- 总结自动取消分组。
OP 状态有 2700 行。但是,我将在更新版本中以 500k 运行它。
是的,2700 行的 20 倍加速是... 2.32 毫秒。 OP 需要运行代码数十万次,以节省阅读此答案和更改代码所需的计算时间。除非 OP 正在使用高度调整的生产系统,否则性能差异在 2700 行时无关紧要。但是,如果数据在性能可能很重要的地方变得足够大,那么排名和相对性能可能会发生变化。
我喜欢rowsum
解决方案——它是解决这个问题最好的(虽然最不通用)base
方法。我的观点是对于这种大小的数据,所有建议的方法都很快 - 最慢的方法只需要几分之一秒。新的 R 用户应该专注于理解方法和代码的可读性,而不是过早的优化。即使在 500k 行中,差异也会变得很明显。【参考方案3】:
library(tidyverse)
df %>%
select(-OTU_ID) %>%
group_by(Trophic.Mode) %>%
summarise_all(sum) %>%
ungroup()
我的首选是tidyverse
。
【讨论】:
为了帮助 OP 入门,而不是广泛推荐tidyverse
,我将 OP 直接指向 dplyr
- 这就是这里所需要的。 (summarise_all
即将退出,summarise(across(everything(), sum))
是现代方式。这很好,因为我们可以切换到 summarise(across(where(is.numeric), sum))
,而不是手动 select(-OTU_ID)
。【参考方案4】:
也许试试这个选项。这是一个base R
选项。正如 @GregorThomas 在 cmets 中所说,您必须告诉函数必须考虑哪些变量。在这种情况下,在公式中我们避免使用OTU_ID
。代码如下:
#Option 1
Out1 <- aggregate(cbind(Sample1,Sample2,Sample3,Sample4)~Trophic.Mode,data=df,sum,na.rm=T)
输出:
Trophic.Mode Sample1 Sample2 Sample3 Sample4
1 Pathotroph 11 4 6 5
2 Symbiotroph 4 5 6 1
使用的一些数据:
#Data
df <- structure(list(OTU_ID = c("gatca", "atca", "gatac"), Trophic.Mode = c("Symbiotroph",
"Pathotroph", "Pathotroph"), Sample1 = c(4L, 4L, 7L), Sample2 = c(5L,
3L, 1L), Sample3 = c(6L, 4L, 2L), Sample4 = c(1L, 4L, 1L)), class = "data.frame", row.names = c(NA,
-3L))
【讨论】:
【参考方案5】:试试这个
library(dplyr)
read_table("TU_ID Trophic.Mode Sample1 Sample2 Sample3 Sample4
gatca Symbiotroph 4 5 6 1
atca Pathotroph 4 3 4 4
gatac Pathotroph 7 1 2 1") %>%
group_by(Trophic.Mode) %>%
summarise(across(where(is.numeric), sum))
`summarise()` ungrouping output (override with `.groups` argument)
# A tibble: 2 x 5
Trophic.Mode Sample1 Sample2 Sample3 Sample4
<chr> <dbl> <dbl> <dbl> <dbl>
1 Pathotroph 11 4 6 5
2 Symbiotroph 4 5 6 1
【讨论】:
【参考方案6】:考虑aggregate
的公式版本,可以说它更具可读性,因为您可以明确地看到数字和分组列。但您可能仍需要过滤公式列。
还要注意aggregate
公式与非公式方法在处理缺失值方面可能不同。见aggregate methods treat missing values (NA) differently。 @Rorschach 的fix 应用在下面。
# EXPLICIT NUMERIC COLUMNS
agg <- aggregate(cbind(Sample1, Sample2, Sample3, Sample4) ~ Trophic.Mode,
data = data,
FUN = sum,
na.rm = TRUE,
na.action = na.pass)
# IMPLICIT "ALL" NUMERIC COLUMNS
agg <- aggregate(. ~ Trophic.Mode,
data = data[,grep("Trophic|Sample", names(data))],
na.rm = TRUE,
na.action = na.pass)
【讨论】:
以上是关于按其他列因子聚合列[重复]的主要内容,如果未能解决你的问题,请参考以下文章