Rcpp 上的相等逻辑运算符比 base R 慢 8 倍
The equality logcial operator on Rcpp is 8 times slower than on base R
看下面简单的代码和操作:
library(Rcpp)
library(microbenchmark)
set.seed(100)
x <- sample(0:1, 1000000, replace = TRUE)
y <- sample(0:1, 1000000, replace = TRUE)
cppFunction('LogicalVector is_equal_c(NumericVector x, NumericVector y) {
return x == y;
}')
is_equal_R <- function(x, y) {
return(x==y)
}
mbm <- microbenchmark(c = is_equal_c(x,y),
R = is_equal_R(x,y)
)
mbm
执行速度表现如下:
Unit: milliseconds
expr min lq mean median uq max neval cld
c 6.4132 6.6896 10.961774 11.2421 12.63245 102.5480 100 b
R 1.2555 1.2994 1.766561 1.3327 1.38220 9.0022 100 a
简单的 R 相等运算符比 Rcpp 快 8 倍。为什么会这样,是否有办法使 Rcpp 代码至少与 R 简单向量相等运算符一样快?
不,不是。
只是因为它需要将您的整数向量复制到数值向量。尝试 + 0
.
library(Rcpp)
library(microbenchmark)
set.seed(100)
x <- sample(0:1, 1000000, replace = TRUE) + 0
y <- sample(0:1, 1000000, replace = TRUE) + 0
typeof(x)
cppFunction('LogicalVector is_equal_c(NumericVector x, NumericVector y) {
return x == y;
}')
is_equal_R <- function(x, y) {
return(x==y)
}
mbm <- microbenchmark(c = is_equal_c(x,y),
R = is_equal_R(x,y)
)
mbm
Unit: milliseconds
expr min lq mean median uq max neval
c 4.2476 4.3730 5.451743 4.60745 5.00635 12.3636 100
R 3.0767 3.1513 4.242035 3.25965 3.71425 14.5210 100
正如弗洛里安已经暗示的那样,错误是你的错误,因为你将昂贵的副本从 int
强行复制到 numeric
:
> class(1:3)
[1] "integer"
> class(1:3 + 0) # Florian's conversion
[1] "numeric"
>
因为整数值实际上 'lighter' 而不是数值(在 32 位和 64 位),我们不妨坚持使用整数 并相应地修改您的 C++ 函数签名 。
在我的电脑上,C++ 打败了 R,但两者都是虚拟代码,正如您在 R 中已经矢量化的实现中所期望的那样。
修改代码
现在作为嵌入了 R 代码的 C++ 文件
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::LogicalVector is_equal_c(Rcpp::IntegerVector x, Rcpp::IntegerVector y) {
return x == y;
}
/*** R
library(microbenchmark)
set.seed(100)
x <- sample(0:1, 1000000, replace = TRUE)
y <- sample(0:1, 1000000, replace = TRUE)
is_equal_R <- function(x, y) {
return(x==y)
}
mbm <- microbenchmark(c = is_equal_c(x,y),
R = is_equal_R(x,y))
mbm
*/
输出
> Rcpp::sourceCpp("answer.cpp")
> library(microbenchmark)
> set.seed(100)
> x <- sample(0:1, 1000000, replace = TRUE)
> y <- sample(0:1, 1000000, replace = TRUE)
> is_equal_R <- function(x, y) {
+ > return(x==y)
+ >
}
> mbm <- microbenchmark(c = is_equal_c(x,y),
+ > R = is_equal_R(x,y))
> mbm
Unit: milliseconds
expr min lq mean median uq max neval cld
c 1.77923 1.82570 2.06075 1.87093 1.93911 4.31854 100 a
R 1.20529 2.03077 2.23089 2.06222 2.11870 10.89118 100 a
>
所以总而言之,您的结果是令人头疼的结果之一,有人说“这不可能是真的......”,这些都是非常好的学习经历:)
看下面简单的代码和操作:
library(Rcpp)
library(microbenchmark)
set.seed(100)
x <- sample(0:1, 1000000, replace = TRUE)
y <- sample(0:1, 1000000, replace = TRUE)
cppFunction('LogicalVector is_equal_c(NumericVector x, NumericVector y) {
return x == y;
}')
is_equal_R <- function(x, y) {
return(x==y)
}
mbm <- microbenchmark(c = is_equal_c(x,y),
R = is_equal_R(x,y)
)
mbm
执行速度表现如下:
Unit: milliseconds
expr min lq mean median uq max neval cld
c 6.4132 6.6896 10.961774 11.2421 12.63245 102.5480 100 b
R 1.2555 1.2994 1.766561 1.3327 1.38220 9.0022 100 a
简单的 R 相等运算符比 Rcpp 快 8 倍。为什么会这样,是否有办法使 Rcpp 代码至少与 R 简单向量相等运算符一样快?
不,不是。
只是因为它需要将您的整数向量复制到数值向量。尝试 + 0
.
library(Rcpp)
library(microbenchmark)
set.seed(100)
x <- sample(0:1, 1000000, replace = TRUE) + 0
y <- sample(0:1, 1000000, replace = TRUE) + 0
typeof(x)
cppFunction('LogicalVector is_equal_c(NumericVector x, NumericVector y) {
return x == y;
}')
is_equal_R <- function(x, y) {
return(x==y)
}
mbm <- microbenchmark(c = is_equal_c(x,y),
R = is_equal_R(x,y)
)
mbm
Unit: milliseconds
expr min lq mean median uq max neval
c 4.2476 4.3730 5.451743 4.60745 5.00635 12.3636 100
R 3.0767 3.1513 4.242035 3.25965 3.71425 14.5210 100
正如弗洛里安已经暗示的那样,错误是你的错误,因为你将昂贵的副本从 int
强行复制到 numeric
:
> class(1:3)
[1] "integer"
> class(1:3 + 0) # Florian's conversion
[1] "numeric"
>
因为整数值实际上 'lighter' 而不是数值(在 32 位和 64 位),我们不妨坚持使用整数 并相应地修改您的 C++ 函数签名 。
在我的电脑上,C++ 打败了 R,但两者都是虚拟代码,正如您在 R 中已经矢量化的实现中所期望的那样。
修改代码
现在作为嵌入了 R 代码的 C++ 文件
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::LogicalVector is_equal_c(Rcpp::IntegerVector x, Rcpp::IntegerVector y) {
return x == y;
}
/*** R
library(microbenchmark)
set.seed(100)
x <- sample(0:1, 1000000, replace = TRUE)
y <- sample(0:1, 1000000, replace = TRUE)
is_equal_R <- function(x, y) {
return(x==y)
}
mbm <- microbenchmark(c = is_equal_c(x,y),
R = is_equal_R(x,y))
mbm
*/
输出
> Rcpp::sourceCpp("answer.cpp")
> library(microbenchmark)
> set.seed(100)
> x <- sample(0:1, 1000000, replace = TRUE)
> y <- sample(0:1, 1000000, replace = TRUE)
> is_equal_R <- function(x, y) {
+ > return(x==y)
+ >
}
> mbm <- microbenchmark(c = is_equal_c(x,y),
+ > R = is_equal_R(x,y))
> mbm
Unit: milliseconds
expr min lq mean median uq max neval cld
c 1.77923 1.82570 2.06075 1.87093 1.93911 4.31854 100 a
R 1.20529 2.03077 2.23089 2.06222 2.11870 10.89118 100 a
>
所以总而言之,您的结果是令人头疼的结果之一,有人说“这不可能是真的......”,这些都是非常好的学习经历:)