通过data.table或dplyr中的分组列为每个数值列选择绝对值的最大值
下面是my data.frame的外观示例:通过data.table或dplyr中的分组列为每个数值列选择绝对值的最大值,r,data.table,dplyr,R,Data.table,Dplyr,下面是my data.frame的外观示例: opts <- seq(-0.5, 0.5, 0.05) df <- data.frame(combo1=sample(opts, 6), combo2=sample(opts, 6), combo3=sample(opts, 6), gene=rep(c("g1", "g2", "g3"), each=2), stringsAsFact
opts <- seq(-0.5, 0.5, 0.05)
df <- data.frame(combo1=sample(opts, 6),
combo2=sample(opts, 6),
combo3=sample(opts, 6),
gene=rep(c("g1", "g2", "g3"), each=2), stringsAsFactors=F)
df
combo1 combo2 combo3 gene
1 0.40 0.50 -0.10 g1
2 0.10 -0.20 -0.35 g1
3 -0.35 -0.35 0.40 g2
4 0.00 0.10 -0.30 g2
5 -0.45 -0.10 0.05 g3
6 -0.40 -0.40 -0.05 g3
选择
普雷德斯组合酒店
#添加到df_最终版本
类(combo_preds)基类R中的一个方法可以工作(还有许多其他方法)
这里有一个更简单、更快的dplyr
方法:
df %>% group_by(gene) %>%
summarise_each(funs(.[which.max(abs(.))]))
在可复制的数据上尝试:
set.seed(495)
opts <- seq(-0.5, 0.5, 0.05)
df <- data.frame(combo1=sample(opts, 6),
combo2=sample(opts, 6),
combo3=sample(opts, 6),
gene=rep(c("g1", "g2", "g3"), each=2), stringsAsFactors=F)
df
请注意,在上述情况下,combo2
和gene=g1
的绝对值是相等的。如果这很重要,你需要决定如何打破关系
我的dplyr
方法和@mathematic.coffee的data.table
方法的稍快版本的计时(使用更大的样本数据框):
因此,data.table
版本的运行时间大约是dplyr
版本的一半
更新:为了回应@Arun的评论,这里有一个更大的样本数据框,包含更多的列和更多的基因
类别
# Large sample of fake data
set.seed(194)
genes=apply(expand.grid(letters,letters), 1, paste, collapse="")
df = data.frame(replicate(50, rnorm(26*26*1e3)), gene=genes)
object.size(df)
# 273 MB
microbenchmark::microbenchmark(
dplyr=setDF(df) %>% group_by(gene) %>%
summarise_each(funs(.[which.max(abs(.))])),
data.table={setDT(df)[, lapply(.SD, function (col) col[which.max(abs(col))]), by='gene']},
times=10
)
更新2:与上述相同,但组数更大(26^3而不是26^2)。正如@Arun所讨论的,data.table
速度优势随着组数的增加而增加
# Large sample of fake data
set.seed(194)
genes=apply(expand.grid(letters,letters,letters), 1, paste, collapse="")
df = data.frame(replicate(50, rnorm(26*26*26*50)), gene=genes)
object.size(df)
# 356 MB
microbenchmark::microbenchmark(
dplyr=setDF(df) %>% group_by(gene) %>%
summarise_each(funs(.[which.max(abs(.))])),
data.table={setDT(df)[, lapply(.SD, function (col) col[which.max(abs(col))]), by='gene']},
times=1
)
您当然可以使用data.table
来完成此操作。(我没有针对您的版本进行基准测试)
这里的df.wide
看起来像您的数据框,每个组合一列,每个基因的每个复制一行
这是原始的数据。表答案:
# data.table option
library(data.table)
dt <- data.table(df.wide)
system.time({
out <- dt[, lapply(.SD, function (col) col[which.max(abs(col))]), by='gene']
})
# user system elapsed
# 10.757 0.364 12.612
@Mathematic.coffee的答案对于lapply来说很好,但是有一种更具数据表的方法来实现相同的目标:
opts <- seq(-0.5, 0.5, 0.05)
dt <- data.table(combo1=sample(opts, 6),
combo2=sample(opts, 6),
combo3=sample(opts, 6),
gene=rep(c("g1", "g2", "g3"), each=2))
dt
很晚了,但希望这对其他人有所帮助:(在创建随机示例数据集之前,您可能希望使用set.seed
。不,这是正确的,除非OP希望最大绝对值而不是最大值。您的基准数据大小为2.7MB(甚至完全适合缓存),而Mathematic.coffee的容量约为230MB。如果没有合理大小的数据,很难了解工具的性能/伸缩性。我认为这也是因为他/她的数据集有很多列。并且,dplyr
分别计算每一列(以便您可以在其中直接参考上一列),只要函数针对混合求值进行了优化,这就可以了,但在其他方面效率很低。与原始方法相比,可以看到更好的代码,但由于某些原因,需要花费大约一分钟的时间(2.62分钟vs 3.53分钟).相比之下,@mathematic.coffee的data.table方法的计时时间为42秒。@eipi10,感谢您的跟进。虽然不是全部,但要好得多。这有助于更好地理解性能差异的原因。谢谢。
df %>% group_by(gene) %>%
summarise_each(funs(.[which.max(abs(.))]))
gene combo1 combo2 combo3
1 g1 -0.45 0.50 -0.25
2 g2 0.35 -0.40 -0.30
3 g3 0.15 -0.35 -0.40
set.seed(495)
opts <- seq(-0.5, 0.5, 0.05)
df <- data.frame(combo1=sample(opts, 9e4, replace=TRUE),
combo2=sample(opts, 9e4, replace=TRUE),
combo3=sample(opts, 9e4, replace=TRUE),
gene=rep(c("g1", "g2", "g3"), each=3e4), stringsAsFactors=F)
microbenchmark::microbenchmark(
dplyr=setDF(df) %>% group_by(gene) %>%
summarise_each(funs(.[which.max(abs(.))])),
data.table={setDT(df)[, lapply(.SD, function (col) col[which.max(abs(col))]), by='gene']}
)
Unit: milliseconds
expr min lq mean median uq max neval cld
dplyr 10.013623 11.839132 14.156735 12.284574 12.675220 32.35739 100 b
data.table 4.434841 6.008701 6.947104 6.222775 6.415083 29.52652 100 a
# Large sample of fake data
set.seed(194)
genes=apply(expand.grid(letters,letters), 1, paste, collapse="")
df = data.frame(replicate(50, rnorm(26*26*1e3)), gene=genes)
object.size(df)
# 273 MB
microbenchmark::microbenchmark(
dplyr=setDF(df) %>% group_by(gene) %>%
summarise_each(funs(.[which.max(abs(.))])),
data.table={setDT(df)[, lapply(.SD, function (col) col[which.max(abs(col))]), by='gene']},
times=10
)
Unit: milliseconds
expr min lq mean median uq max neval cld
dplyr 1240.1695 1299.0425 1375.8298 1318.5343 1385.5854 1748.8112 10 b
data.table 464.5597 493.8959 527.7097 519.3607 585.1482 603.3916 10 a
# Large sample of fake data
set.seed(194)
genes=apply(expand.grid(letters,letters,letters), 1, paste, collapse="")
df = data.frame(replicate(50, rnorm(26*26*26*50)), gene=genes)
object.size(df)
# 356 MB
microbenchmark::microbenchmark(
dplyr=setDF(df) %>% group_by(gene) %>%
summarise_each(funs(.[which.max(abs(.))])),
data.table={setDT(df)[, lapply(.SD, function (col) col[which.max(abs(col))]), by='gene']},
times=1
)
Unit: seconds
expr min lq mean median uq max neval
dplyr 27.567790 27.567790 27.567790 27.567790 27.567790 27.567790 1
data.table 2.765047 2.765047 2.765047 2.765047 2.765047 2.765047 1
library(data.table)
dt <- data.table(df)
dt[, lapply(.SD, function (col) col[which.max(abs(col))]), by='gene']
opts <- seq(-0.5, 0.5, 0.05)
n.combos <- 600
n.genes <- 10000
n.rows.per.gene <- 5
# columns are called X1 X2 instead of combo1 combo2 but no matter.
df.wide <- data.frame(replicate(n.combos, sample(opts, n.rows.per.gene, replace=T)),
gene=rep(paste0("g", 1:n.genes), each=n.rows.per.gene))
# data.table option
library(data.table)
dt <- data.table(df.wide)
system.time({
out <- dt[, lapply(.SD, function (col) col[which.max(abs(col))]), by='gene']
})
# user system elapsed
# 10.757 0.364 12.612
# reshape to long
dt.long <- melt(dt, id.vars='gene', variable.name='combo')
# > head(dt.long)
# gene combo value
# 1: g1 X1 0.20
# 2: g1 X1 0.30
# 3: g1 X1 0.10
# 4: g1 X1 0.05
# 5: g1 X1 0.30
# 6: g2 X1 0.20
system.time({out.long <- dt.long[, value[which.max(value)], by='gene,combo']})
user system elapsed
8.000 0.472 9.525
system.time({
out.dplyr <- df.wide %>% group_by(gene) %>%
summarise_each(funs(.[which.max(abs(.))]))
})
# user system elapsed
# 163.106 7.989 189.788
opts <- seq(-0.5, 0.5, 0.05)
dt <- data.table(combo1=sample(opts, 6),
combo2=sample(opts, 6),
combo3=sample(opts, 6),
gene=rep(c("g1", "g2", "g3"), each=2))
dt
combo1 combo2 combo3 gene
1: -0.20 -0.40 -0.10 g1
2: 0.15 0.15 0.40 g1
3: 0.35 0.10 -0.05 g2
4: 0.45 -0.15 -0.25 g2
5: 0.00 -0.25 0.50 g3
6: 0.10 0.20 0.25 g3
dt2 <- dt[, .(combo1=max(combo1), combo2=max(combo2), combo3=max(combo3)),
keyby=gene]
dt2
gene combo1 combo2 combo3
1: g1 0.15 0.15 0.40
2: g2 0.45 0.10 -0.05
3: g3 0.10 0.20 0.50