如果您真的关心效率,那么这段简短的 Rcpp 代码将很难被击败。将以下内容存储在文件中,例如/tmp/rnormClamp.cpp
:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector rnormClamp(int N, int mi, int ma) {
NumericVector X = rnorm(N, 0, 1);
return clamp(mi, X, ma);
}
/*** R
system.time(X <- rnormClamp(50000, -3, 3))
summary(X)
*/
使用sourceCpp()
(也来自Rcpp)来构建和运行它。在我的计算机上实际绘制和夹紧大约需要 4 毫秒:
R> sourceCpp("/tmp/rnormClamp.cpp")
R> system.time(X <- rnormClamp(50000, -3, 3))
user system elapsed
0.004 0.000 0.004
R> summary(X)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-3.00000 -0.67300 -0.00528 0.00122 0.68500 3.00000
R>
clamp()
糖函数在 Romain 之前的 SO 回答中得到了介绍,其中还指出您需要 Rcpp 的 0.10.2 版。
编辑:根据 Ben 的提示,我似乎误解了。这是 C++ 和 R 的混合:
// [[Rcpp::export]]
List rnormSelect(int N, int mi, int ma) {
RNGScope scope;
int N2 = N * 1.25;
NumericVector X = rnorm(N2, 0, 1);
LogicalVector ind = (X < mi) | (X > ma);
return List::create(X, ind);
}
哪个可以附加到较早的文件。然后:
R> system.time({ Z <- rnormSelect(50000, -3, 3);
+ X <- Z[[1]][ ! Z[[2]] ]; X <- X[1:50000]})
user system elapsed
0.008 0.000 0.009
R> summary(X)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-3.00000 -0.68200 -0.00066 -0.00276 0.66800 3.00000
R>
我将重新讨论我必须查找的逻辑索引和行子集。明天吧。但是 9 毫秒仍然不算太糟糕 :)
编辑2:看起来我们真的没有逻辑索引。我们必须添加这个。这个版本是“手动”完成的,但并不比从 R 中索引快多少:
// [[Rcpp::export]]
NumericVector rnormSelect2(int N, int mi, int ma) {
RNGScope scope;
int N2 = N * 1.25;
NumericVector X = rnorm(N2, 0, 1);
LogicalVector ind = (X >= mi) & (X <= ma);
NumericVector Y(N);
int k=0;
for (int i=0; i<N2 & k<N; i++) {
if (ind[i]) Y(k++) = X(i);
}
return Y;
}
和输出:
R> system.time(X <- rnormSelect2(50000, -3, 3))
user system elapsed
0.004 0.000 0.007
R> summary(X)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-2.99000 -0.66900 -0.00258 0.00223 0.66700 2.99000
R> length(X)
[1] 50000
R>