【发布时间】:2014-05-22 11:54:26
【问题描述】:
我有一个由 n 元素组成的向量 x。
现在我想获得方案s = subset(x, x<=p) 的该向量的多个子集,其中p 将包含多个值,通过向量给出。
最后,我希望根据包含p 值的向量将这些子集的长度存储在一个向量中。
你能帮我在没有循环等的情况下这样做吗?
【问题讨论】:
我有一个由 n 元素组成的向量 x。
现在我想获得方案s = subset(x, x<=p) 的该向量的多个子集,其中p 将包含多个值,通过向量给出。
最后,我希望根据包含p 值的向量将这些子集的长度存储在一个向量中。
你能帮我在没有循环等的情况下这样做吗?
【问题讨论】:
另一种占用内存较少的解决方案:
set.seed(42)
x <- rnorm(20)
p <- c(-1, 0, 1)
## sapply(p, function(pi) sum(x <= pi))
[1] 1 5 8
基准测试:
library(microbenchmark)
set.seed(42)
x <- rnorm(20000)
p <- rnorm(100)
microbenchmark(setNames(colSums(outer(x, p, "<=")), p), sapply(p, function(pi) sum(x <= pi)))
## Unit: milliseconds
## expr min lq median uq max neval
## setNames(colSums(outer(x, p, "<=")), p) 29.33870 87.21804 88.5226 89.94144 94.34427 100
## sapply(p, function(pi) sum(x <= pi)) 21.52853 22.23344 22.2959 22.46226 26.13650 100
【讨论】:
sapply 使用lapply 和lapply 调用.Internal(lapply(X, FUN)) - 这是一个“C 级循环”
for 也是用 C 实现的。在这两种情况下,您都将 R 表达式/函数传递给循环函数。
outer 有点贵(尤其是对于大p 和x).. 我在上面添加了一些基准
set.seed(42)
x <- rnorm(20)
p <- c(-1, 0, 1)
setNames(colSums(outer(x, p, "<=")), p)
#-1 0 1
# 3 10 14
解释:
在outer 中使用<= 测试x 的每个元素与p 的每个元素。计算 colwise 和给出每个 p 值的 TRUE 值的数量。最后,我们使用p 值作为名称。
【讨论】:
只是为了好玩,让我们用 Rcpp 来做。在这里,我先对输入进行排序,然后再利用它:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector countsmaller(NumericVector x, const NumericVector p) {
x=x.sort();
NumericVector sorted = clone(p).sort();
IntegerVector order=match(p, sorted);
int count = 0;
double prob=sorted(0);
int i=0;
for(int j = 0; j < x.size(); ++j) {
if (x(j) <= prob)
{
count++;
}
else
{
if (i < sorted.size()-1)
{
sorted(i)=count;
i++;
prob=sorted(i);
if (x(j) <= prob) count++; else j--;
}
}
}
sorted(sorted.size()-1) = count;
return sorted[order-1];
}
更快吗?
set.seed(42)
x <- rnorm(20000)
p <- rnorm(100)
all.equal(countsmaller(x, p),
sapply(p, function(pi) sum(x <= pi)))
#TRUE
library(microbenchmark)
microbenchmark(colSums(outer(x, p, "<=")),
sapply(p, function(pi) sum(x <= pi)),
countsmaller(x, p)
)
# Unit: milliseconds
# expr min lq median uq max neval
# colSums(outer(x, p, "<=")) 22.354525 64.833602 65.343129 66.161082 149.428049 100
# sapply(p, function(pi) sum(x <= pi)) 12.922805 13.344871 14.444304 15.009727 58.607176 100
# countsmaller(x, p) 1.650383 1.703044 1.730453 1.754937 2.222273 100
【讨论】: