我必须在一个大矩阵上计算一系列统计数据,我想以向量作为分组因子以最有效的方式做到这一点。
行是我要分组的变量,而列是示例。
例如:
mat = matrix(seq(1,10000), ncol = 100)
vect_group = c(1,1,1,1,1,2,2,2,3,3,3, ...)
我想计算索引为1、2、3等的所有行的平均列。因此,在这种情况下,请获得一个新矩阵,该矩阵的行数与vect_group
的级别以及匹配列中的相应统计信息一样。
到目前为止,我已经通过索引获得了这种循环,并且每次都对这些子矩阵使用apply,但是我想加快该过程。我尝试了doParallel
和foreach
,但没有成功。
我苦苦挣扎的关键部分是拆分/聚合过程以生成较小的矩阵。另外,我不知道这些开销是否会影响多线程计算的选择。
答案 0 :(得分:1)
我不知道您是否需要多线程。
我已经测试了两种解决方案,一种使用基数R,另一种使用dplyr
。两者在基准测试中都非常快。
mat <- matrix(seq(1,10000), ncol = 100)
vect_group <- rep(1:10, each = 10)
#--
library(dplyr)
#-- Base R
splitData <- split(as.data.frame(mat), vect_group)
meansPerGroup <- sapply(splitData, colMeans)
#-- Dplyr
df <- data.frame(mat, vect_group)
meansPerGroup <- df %>%
group_by(vect_group) %>%
summarize_at(vars(colnames(mat)), mean)
然后,我针对这两种解决方案进行了基准测试:
rbenchmark::benchmark(replications = 5000,
baseR = function(mat = mat, vect_group = vect_group) {
splitData <- split(as.data.frame(mat), vect_group)
meansPerGroup <- sapply(splitData, colMeans)
},
dplyr = function(df = df, vect_group = vect_group) {
meansPerGroup <- df %>%
group_by(vect_group) %>%
summarize_at(vars(colnames(mat)), mean)
})
基准测试结果
test replications elapsed relative user.self sys.self user.child sys.child
1 baseR 5000 0.006 1.2 0.006 0 0 0
2 dplyr 5000 0.005 1.0 0.006 0 0 0
答案 1 :(得分:0)
我同意@csgroen的观点,因为并行计算平均值非常快,并且设置起来会产生开销,所以并行执行此计算可能是不必要的,但这可能取决于问题的规模。您的矩阵有多大?
不是最快的并行方法是使用data.table
。我已经在下面对包括上一个答案在内的一些方法进行了基准测试(尽管我无法在计算机上运行dplyr版本-我认为是因为mat
没有列名)。 Data.table平均需要3毫秒左右的时间,而且聚合也不远。
mat <- matrix(seq(1,10000), ncol = 100)
vect_group = rep(1:10, each = 10)
fn1_agg <- function(mat, vg) {
aggregate(c(mat)~rep(vg, ncol(mat)), FUN = mean)
}
fn2_dt <- function(mat, vg){
DT <- data.table::data.table(m = c(mat), v = rep(vg, ncol(mat)))
data.table::setkey(DT, v)
DT[, list(m = mean(m)), by = v]
}
fn3_split <- function(mat, vg) {
splitData <- split(as.data.frame(mat), vect_group)
sapply(splitData, colMeans)
}
microbenchmark::microbenchmark(fn1_agg(mat, vect_group),
fn2_dt(mat, vect_group),
fn3_split(mat, vect_group))
#> Unit: milliseconds
#> expr min lq mean median
#> fn1_agg(mat, vect_group) 5.169709 5.437589 6.122462 6.293567
#> fn2_dt(mat, vect_group) 1.197218 1.291972 3.004166 1.472097
#> fn3_split(mat, vect_group) 15.480264 15.751230 16.998514 16.267098
#> uq max neval cld
#> 6.481626 9.454458 100 b
#> 1.538948 142.368800 100 a
#> 17.060969 60.686907 100 c
由reprex package(v0.2.1)于2019-02-07创建