C++ Rcpp:我的距离矩阵程序比软件包中的函数慢
我想计算两两欧几里德距离矩阵。我根据德克·埃德尔布埃特尔的建议编写了Rcpp程序,如下所示C++ Rcpp:我的距离矩阵程序比软件包中的函数慢,c++,r,rcpp,C++,R,Rcpp,我想计算两两欧几里德距离矩阵。我根据德克·埃德尔布埃特尔的建议编写了Rcpp程序,如下所示 NumericMatrix calcPWD1 (NumericMatrix x){ int outrows = x.nrow(); double d; NumericMatrix out(outrows,outrows); for (int i = 0 ; i < outrows - 1; i++){ for (int j = i + 1 ; j < outrows
NumericMatrix calcPWD1 (NumericMatrix x){
int outrows = x.nrow();
double d;
NumericMatrix out(outrows,outrows);
for (int i = 0 ; i < outrows - 1; i++){
for (int j = i + 1 ; j < outrows ; j ++){
NumericVector v1= x.row(i);
NumericVector v2= x.row(j);
NumericVector v3=v1-v2;
d = sqrt(sum(pow(v3,2)));
out(j,i)=d;
out(i,j)=d;
}
}
return (out) ;
}
你们有什么建议吗?我的矩阵很简单。没有列名称或行名称,只有普通的矩阵(例如b=matrix(c(rnorm(1000*10)),1000,10)
)。
这是dist
> dist
function (x, method = "euclidean", diag = FALSE, upper = FALSE,
p = 2)
{
if (!is.na(pmatch(method, "euclidian")))
method <- "euclidean"
METHODS <- c("euclidean", "maximum", "manhattan", "canberra",
"binary", "minkowski")
method <- pmatch(method, METHODS)
if (is.na(method))
stop("invalid distance method")
if (method == -1)
stop("ambiguous distance method")
x <- as.matrix(x)
N <- nrow(x)
attrs <- if (method == 6L)
list(Size = N, Labels = dimnames(x)[[1L]], Diag = diag,
Upper = upper, method = METHODS[method], p = p, call = match.call(),
class = "dist")
else list(Size = N, Labels = dimnames(x)[[1L]], Diag = diag,
Upper = upper, method = METHODS[method], call = match.call(),
class = "dist")
.Call(C_Cdist, x, method, attrs, p)
}
<bytecode: 0x56b0d40>
<environment: namespace:stats>
距离
函数(x,method=“euclidean”,diag=FALSE,upper=FALSE,
p=2)
{
如果(!is.na(pmatch(方法,“欧几里德”))
方法你就快到了。但是你的内部循环体试图在一行中完成太多的工作。模板编程已经够难了,有时最好将指令分散一点,让编译器有更好的机会。所以我只做了五条语句,并立即构建了
新代码:
#include <Rcpp.h>
using namespace Rcpp;
double dist1 (NumericVector x, NumericVector y){
int n = y.length();
double total = 0;
for (int i = 0; i < n ; ++i) {
total += pow(x(i)-y(i),2.0);
}
total = sqrt(total);
return total;
}
// [[Rcpp::export]]
NumericMatrix calcPWD (NumericMatrix x){
int outrows = x.nrow();
int outcols = x.nrow();
NumericMatrix out(outrows,outcols);
for (int i = 0 ; i < outrows - 1; i++){
for (int j = i + 1 ; j < outcols ; j ++) {
NumericVector v1 = x.row(i);
NumericVector v2 = x.row(j-1);
double d = dist1(v1, v2);
out(j-1,i) = d;
out(i,j-1)= d;
}
}
return (out) ;
}
/*** R
M <- matrix(log(1:9), 3, 3)
calcPWD(M)
*/
Rcpp与内部R函数(C/Fortran)
首先,仅仅因为使用Rcpp编写算法并不一定意味着它将击败R等价物,特别是当R函数调用C或Fortran例程来执行大部分计算时。在其他情况下,函数完全用R编写,在Rcpp中转换它很可能会l产生所需的速度增益
请记住,当重写内部函数时,一个对手是绝对疯狂的C程序员组成的R核心团队,他们很可能会胜出
dist()的基本实现
其次,R使用的距离计算在C中完成,如下所示:
.Call(C_Cdist, x, method, attrs, p)
,这是 Distor()的最后一行< /Cuth>函数的R源。这给它一个轻微的优势,而不是C++,因为它是更细粒度而不是模板化的。
此外,当可用于并行计算时,还可以使用
拟议的修改
第三,通过稍微更改子集顺序并避免创建附加变量,版本之间的计时减少
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::NumericMatrix calcPWD1 (const Rcpp::NumericMatrix & x){
unsigned int outrows = x.nrow(), i = 0, j = 0;
double d;
Rcpp::NumericMatrix out(outrows,outrows);
for (i = 0; i < outrows - 1; i++){
Rcpp::NumericVector v1 = x.row(i);
for (j = i + 1; j < outrows ; j ++){
d = sqrt(sum(pow(v1-x.row(j), 2.0)));
out(j,i)=d;
out(i,j)=d;
}
}
return out;
}
#包括
//[[Rcpp::导出]]
Rcpp::NumericMatrix calcPWD1(常量Rcpp::NumericMatrix&x){
无符号整数outrows=x.nrow(),i=0,j=0;
双d;
Rcpp::NumericMatrix out(outrows,outrows);
对于(i=0;i
非常感谢。但是我比较了R包中的dist
和我自己的calcPWD
之间的时间。我发现我的函数需要更多的时间。你有什么建议来改进我的函数吗?对于初学者来说,你不需要循环。查看Rcpp Sugar
小插曲。否则,profile…你为什么期望它是faster?在内部,dist()
也使用编译后的代码…@DirkEddelbuettel。我希望我的程序比dist
快,因为在dist
中,有太多的东西需要检查(比如method
,diag
)。这就是为什么你想分析不同的部分在不同的输入维度下花费不同的时间。猜测都是好的,但我们经常会弄错。如果更可取,则进行测量。R是否使用多个线程来加速计算?大矩阵运算通常可以并行化。此外,它是否可以矢量化计算,使用SIMD或AVX指令?@ChristopherRoicles。计算距离矩阵是子函数的一部分。我已经将不同的子函数放在不同的线程上进行并行计算。我不知道如果我在另一个并行计算中进行并行计算,它是否会加快速度。此外,我也找不到关于R的SIMD或AVX谷歌。你能提供一份参考资料吗?
// [[Rcpp::export]]
double dist2(NumericVector x, NumericVector y){
double d = sqrt( sum( pow(x - y, 2) ) );
return d;
}
.Call(C_Cdist, x, method, attrs, p)
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::NumericMatrix calcPWD1 (const Rcpp::NumericMatrix & x){
unsigned int outrows = x.nrow(), i = 0, j = 0;
double d;
Rcpp::NumericMatrix out(outrows,outrows);
for (i = 0; i < outrows - 1; i++){
Rcpp::NumericVector v1 = x.row(i);
for (j = i + 1; j < outrows ; j ++){
d = sqrt(sum(pow(v1-x.row(j), 2.0)));
out(j,i)=d;
out(i,j)=d;
}
}
return out;
}