2016-11-14 122 views
1

從一前一後,Large SpMat object with RcppArmadillo,我決定用Rcpp計算大型矩陣定義

我已經安裝RcppRcppArmadillo

大矩陣(〜60萬行×11周的cols)
> sessionInfo() 
R version 3.3.1 (2016-06-21) 
Platform: x86_64-apple-darwin15.6.0 (64-bit) 
Running under: OS X 10.11.6 (El Capitan) 

locale: 
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] RcppArmadillo_0.7.500.0.0 Rcpp_0.12.7    cluster_2.0.4    skmeans_0.2-8    
[5] ggdendro_0.1-20   ggplot2_2.1.0    lsa_0.73.1    SnowballC_0.5.1   
[9] data.table_1.9.6   jsonlite_1.1    purrr_0.2.2    stringi_1.1.2    
[13] dplyr_0.5.0    plyr_1.8.4 

loaded via a namespace (and not attached): 
[1] assertthat_0.1 slam_0.1-38  MASS_7.3-45  chron_2.3-47  grid_3.3.1  R6_2.2.0   gtable_0.2.0  
[8] DBI_0.5-1  magrittr_1.5  scales_0.4.0  tools_3.3.1  munsell_0.4.3 clue_0.3-51  colorspace_1.2-7 
[15] tibble_1.2 

有了這樣一個例子mtcars這個完美的作品:

library(lsa)  
x <- as.matrix(mtcars) 
cosine(t(x)) 

這從lsacosine功能:

cosR <- function(x) { 
     co <- array(0, c(ncol(x), ncol(x))) 
     ## f <- colnames(x) 
     ## dimnames(co) <- list(f, f) 
     for (i in 2:ncol(x)) { 
     for (j in 1:(i - 1)) { 
      co[i,j] <- crossprod(x[,i], x[,j])/ 
       sqrt(crossprod(x[,i]) * crossprod(x[,j])) 
     } 
    } 
    co <- co + t(co) 
    diag(co) <- 1 
    return(as.matrix(co)) 
} 

而且在Rcpp相當於是這樣的:

library(Rcpp) 
library(RcppArmadillo) 
cppFunction(depends='RcppArmadillo', 
      code="NumericMatrix cosCpp(NumericMatrix Xr) { 
      int n = Xr.nrow(), k = Xr.ncol(); 
      arma::mat X(Xr.begin(), n, k, false); // reuses memory and avoids extra copy 
      arma::mat Y = arma::trans(X) * X; // matrix product 
      arma::mat res = Y/(arma::sqrt(arma::diagvec(Y)) * arma::trans(arma::sqrt(arma::diagvec(Y)))); 
      return Rcpp::wrap(res); 
      }") 

您可以檢查這兩個功能是等價的

all.equal(cosCpp(x),cosR(x)) 
[1] TRUE 

但是,當我跑我這加載後的數據Rcpp我獲得:

x <- as.matrix(my_data) 
x <- t(my_data) 
y <- cosCpp(x) 
error: Mat::init(): requested size is too large 
Error in eval(substitute(expr), envir, enclos) : 
    Mat::init(): requested size is too large 

更新解決方案後,@沒穿外衣,的建議+ @gvegayon後+小時的閱讀

我修改了功能,這一點:

sourceCpp("/myfolder/my_function.cpp") 

my_function.cpp內容

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

// [[Rcpp::export]] 
arma::sp_mat cosine_rcpp(
    const arma::mat & X 
) { 

    int k = X.n_cols; 

    arma::sp_mat ans(k,k); 

    for (int i=0;i<k;i++) 
    for (int j=i;j<k;j++) { 
     // X(i) x X(j)'/sqrt(sum(X^2) * sum(Y^2)) 
     ans.at(i,j) = arma::norm_dot(X.col(i), X.col(j)); 

    } 

    return ans; 
} 

然後我跑

cosine_rcpp(x) 
+2

以供將來參考,*「[...]說我應該讓' ARMA_64BIT_WORD',但我沒有運氣讓它「*沒有幫助;狀態(並可能證明)你在你的問題中嘗試了什麼。 – nrussell

+2

請自己做(和我們)一個忙,並使用'sourceCpp()'。任何兩三行以外的東西都可以通過'cppFunction()'來實現。 –

+2

您也無法理解編譯器選項是什麼,並且CPPFLAGS **的設置完全**在錯誤的地方。 –

回答

5
  1. RcppArmadilloRcpp - 只包由於/src目錄的內容。要啓用C++ 11,請使用// [[Rcpp::plugins(cpp11)]]
  2. ARMA_64BIT_WORD未定義。要定義它,請在#include <RcppArmadillo.h>之前添加#define ARMA_64BIT_WORD 1

使用sourceCpp()

#define ARMA_64BIT_WORD 1 
#include <RcppArmadillo.h> 
// [[Rcpp::depends(RcppArmadillo)]] 
// [[Rcpp::plugins(cpp11)]] 

// [[Rcpp::export]] 
arma::mat cosCpp(const arma::mat& X) { 

    arma::mat Y = arma::trans(X) * X; // matrix product 
    arma::mat res = Y/(arma::sqrt(arma::diagvec(Y)) * arma::trans(arma::sqrt(arma::diagvec(Y)))); 

    return res; 
} 

/src/Makevars{.win}中定義它套餐使用樣品執行:

PKG_CPPFLAGS = -DARMA_64BIT_WORD=1 
+1

@pachamaltese:上面的代碼使用'sourceCpp(code =「」)'或者把它放在一個外部文件'test.cpp'中,並通過'sourceCpp(file =「/ path/to/test.cpp「)' – coatless

+0

謝謝@Coatless。包括'cpp11'會產生另一個錯誤,我現在正在發佈更新。 – pachamaltese