我正在进行重新采样(即引导程序)过程,该过程涉及作为重复步骤之一,计算多个组中每个组的多个数值变量的平均值。我使用dplyr
,doBy
和data.table
找到了非常简单的解决方案,我在下面提供了这些解决方案。
但是,每个人通常需要一毫秒才能完成(按照microbenchmark
)。由于这个过程将重复几千次(以及其他操作),我想尽可能地优化它。理想情况下,它会在几微秒或更快的时间内完成。
有人能想出提高这些操作速度的方法吗?我的一个想法是将数字变量转换为矩阵并使用colMeans()
,但不确定如何快速进行子集化。
dat <- data.frame(
a = runif(1000),
b = runif(1000),
c = runif(1000),
group = factor(rep(c(1, 2), 500))
)
library(dplyr)
dat %>% group_by(group) %>% summarise_all(mean)
#microbenchmark = 7.1 milliseconds
library(doBy)
summaryBy(. ~ group, dat, FUN = mean)
#microbenchmark = 4.6 milliseconds
library(data.table)
setDT(dat)[, lapply(.SD, mean), by = 'group']
#microbenchmark = 1.8 milliseconds
#base
mat <- as.matrix(dat[, 1:(ncol(dat) - 1)])
grp <- dat$group
by(mat, grp, colMeans)
#microbenchmark = 1.2 milliseconds
更新
为了提供有关我更广泛任务的更多信息,我正在创建一个函数,该函数将从k
相互排斥的组中的n
个主题中获取g
个变量的数据。数据框(n-by-k
)。该函数的主要目的是首先通过取每个组中每个变量的平均值来聚合数据(g-by-k
),然后将统计函数分别应用于每个组的均值向量(1-by-k
)。该统计函数返回感兴趣参数的p
估计值。
此外,需要计算这些估计值的自举置信区间,因此函数会为每个r
重采样估计这些参数,并从原始数据框中进行替换(按组分层)。最后,我需要知道每个重新采样(p-by-g-by-r
)中每个组的参数估计值,以便我可以使用百分位数或其他方法来估计每个组中每个参数的置信区间。
请注意,我已经成功优化了统计函数,现在大约需要50微秒来完成最常见的矢量大小。因此,剩下的瓶颈似乎是为每个重新采样创建这些向量(即聚合和汇总)。
答案 0 :(得分:0)
我可以使用Rcpp和RcppArmadillo达到微秒级。
dat <- data.frame(
a = runif(1000),
b = runif(1000),
c = runif(1000),
group = factor(rep(c(1, 2), 500))
)
mat <- as.matrix(dat[, 1:(ncol(dat) - 1)])
grp <- as.integer(dat$group)
group_scores(mat, grp)
#microbenchmark: 48 microseconds
以下是group_scores函数的Rcpp代码:
# include <RcppArmadillo.h>
# include <RcppArmadilloExtensions/sample.h>
// [[Rcpp::depends(RcppArmadillo)]]
using namespace Rcpp;
//[[Rcpp::export]]
arma::mat submat(NumericMatrix X, NumericVector T, int TestVal) {
arma::mat Xmat(X.begin(), X.nrow(), X.ncol(), false);
arma::colvec tIdx(T.begin(), T.size(), false);
arma::mat y = Xmat.rows(find(tIdx == TestVal));
return y;
}
// [[Rcpp::export]]
arma::rowvec col_means(arma::mat x){
arma::mat X = arma::mat(x.begin(), x.n_rows, x.n_cols, false);
return arma::mean(X, 0);
}
//[[Rcpp::export]]
arma::mat group_scores(NumericMatrix X, NumericVector T) {
NumericVector levels = unique(T);
int n = levels.size();
int m = X.ncol();
arma::mat out(n, m);
for (int i(0); i < n; i++) {
int level = levels(i);
arma::mat sub = submat(X, T, level);
arma::rowvec colmeans = col_means(sub);
out.row(i) = colmeans;
}
return out;
}