有效地执行行式分布测试

Aja*_*jar 8 optimization r rollapply

我有一个矩阵,其中每一行都是一个分布的样本.我想对使用的分布进行滚动比较,ks.test并在每种情况下保存测试统计.从概念上实现这个概念的最简单方法是使用循环:

set.seed(1942)
mt <- rbind(rnorm(5), rnorm(5), rnorm(5), rnorm(5))

results <- matrix(as.numeric(rep(NA, nrow(mt))))

for (i in 2 : nrow(mt)) {

  results[i] <- ks.test(x = mt[i - 1, ], y = mt[i, ])$statistic

}
Run Code Online (Sandbox Code Playgroud)

但是,我的实际数据有大约400列和大约300,000行,我有很多例子.所以我希望这很快.Kolmogorov-Smirnov测试并不是所有数学上复杂的测试,所以如果答案是"实现它Rcpp",我会勉强接受,但我会感到有些惊讶 - 在一对上进行计算已经非常快了在R.

方法我已经尝试但无法工作:dplyr使用rowwise/do/lag,zoo使用rollapply(这是我用来生成分布),并data.table在循环中填充(编辑:这个工作,但它仍然很慢).

Kha*_*haa 7

Rcpp中快速而又脏的实现

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h> 

double KS(arma::colvec x, arma::colvec y) {
  int n = x.n_rows;
  arma::colvec w = join_cols(x, y);
  arma::uvec z = arma::sort_index(w);
  w.fill(-1); w.elem( find(z <= n-1) ).ones();
  return max(abs(cumsum(w)))/n;
}
// [[Rcpp::export]]
Rcpp::NumericVector K_S(arma::mat mt) {
  int n = mt.n_cols; 
  Rcpp::NumericVector results(n);
  for (int i=1; i<n;i++) {
    arma::colvec x=mt.col(i-1);
    arma::colvec y=mt.col(i);
    results[i] = KS(x, y);
    }
  return results;
}
Run Code Online (Sandbox Code Playgroud)

对于尺寸矩阵(400, 30000),它在1s以下完成.

system.time(K_S(t(mt)))[3]
#elapsed 
#   0.98 
Run Code Online (Sandbox Code Playgroud)

结果似乎是准确的.

set.seed(1942)
mt <- matrix(rnorm(400*30000), nrow=30000)
results <- rep(0, nrow(mt))
for (i in 2 : nrow(mt)) {
  results[i] <- ks.test(x = mt[i - 1, ], y = mt[i, ])$statistic
}
result <- K_S(t(mt))
all.equal(result, results)
#[1] TRUE
Run Code Online (Sandbox Code Playgroud)