celestialgod

Combine the power of Rcpp and doSNOW

Apr 14th, 2015
421
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
R 3.58 KB | None | 0 0
  1. library(data.table)
  2. library(plyr)
  3. library(dplyr)
  4. library(magrittr)
  5. library(foreach)
  6. library(doSNOW)
  7. library(snowfall)
  8.  
  9. library(Rcpp)
  10. library(RcppArmadillo)
  11. RcppCode = '
  12. // [[Rcpp::depends(RcppArmadillo)]]
  13. #include <RcppArmadillo.h>
  14. using namespace Rcpp;
  15. using namespace arma;
  16.  
  17. // [[Rcpp::export]]
  18. List fastRidgeLM_Arma(NumericVector yr, NumericMatrix Xr, double lambda) {
  19.  int n = Xr.nrow(), k = Xr.ncol();
  20.  mat X(Xr.begin(), n, k, false);
  21.  mat X2 = join_rows(ones<mat>(n, 1), X);
  22.  colvec y(yr.begin(), n, false);
  23.  colvec coef = solve(join_cols(X2, lambda*eye<mat>(k,k+1)),
  24.    join_cols(y, zeros<colvec>(k)));
  25.  colvec resid = y - X2*coef;
  26.  double sig2 = sum(square(resid)) / (n-k);
  27.  colvec stderrest = sqrt(sig2 * diagvec(inv((trans(X2) * X2))));
  28.  return List::create(Named("coefficients") = coef,
  29.                      Named("stderr") = stderrest);
  30. }'
  31.  
  32. sourceCpp(code = RcppCode)
  33.  
  34. n = 5000
  35. p = 500
  36. X = matrix(rnorm(n*p), n)
  37. tmp_B = matrix(0, p, p)
  38. tmp_B[sample(1:p, 2*p, replace = TRUE), sample(1:p, 2*p, replace = TRUE)] = runif(2*p)*2-1
  39. diag(tmp_B) = 1
  40. X = X %*% tmp_B
  41. Y = X %*% sample(seq(-5, 5, length=p*3), p) + rnorm(n, 0, 10)
  42. X.N = scale(X)
  43. Y.N = scale(Y)
  44. lambda = seq(0, 1, length = 21)[-1]
  45.  
  46. # Example by selecting regularizer in the ridge regression
  47. cv_index_f = function(n, fold = 10){
  48.   fold_n = floor(n / fold)
  49.   rem = n - fold_n * fold
  50.   size = rep(fold_n, fold)
  51.   if(rem > 0)
  52.     size[1:rem] = fold_n + 1
  53.   cv_index = 1:fold %>% sapply(function(i) rep(i, size[i])) %>%
  54.     sample(length(.))
  55.   return(cv_index)
  56. }
  57.  
  58. sfInit(TRUE, 4)
  59. sfExport("Y.N", "X.N", "lambda", "RcppCode")
  60. sfLibrary("Rcpp", character.only=TRUE)
  61. sfLibrary("RcppArmadillo", character.only=TRUE)
  62. sfClusterEval(sourceCpp(code = RcppCode))
  63.  
  64. cl = makeCluster(4, type = "SOCK")
  65. registerDoSNOW(cl)
  66. clusterExport(cl, c("Y.N", "X.N", "lambda", "RcppCode"))
  67. clusterEvalQ(cl, library(Rcpp))
  68. clusterEvalQ(cl, library(RcppArmadillo))
  69. clusterEvalQ(cl, sourceCpp(code = RcppCode))
  70.  
  71. CV_f = function(X, Y, lambda, n_fold, parallel, parPackage = "foreach"){
  72.   cvIndex = cv_index_f(nrow(X), n_fold)
  73.   if ((parPackage == "foreach" && parallel) || !parallel)
  74.   {
  75.     if (parallel)
  76.       clusterExport(cl, "cvIndex", environment())
  77.     CVScores = aaply(1:n_fold, 1, function(i){
  78.       aaply(lambda, 1, function(l){
  79.         tmp = fastRidgeLM_Arma(Y.N[cvIndex != i], X.N[cvIndex != i,], l)
  80.         mean((Y.N[cvIndex == i] - cbind(1, X.N[cvIndex == i,]) %*%
  81.           tmp$coefficients)^2)
  82.       }, .parallel = parallel)
  83.     })
  84.     if (parallel)
  85.       clusterEvalQ(cl, rm(cvIndex))
  86.   }
  87.   else if(parPackage == "snowfall")
  88.   {
  89.     if (parallel)
  90.       sfExport("cvIndex")
  91.     CVScores = aaply(1:n_fold, 1, function(i){
  92.       sfSapply(lambda, function(l){
  93.         tmp = fastRidgeLM_Arma(Y.N[cvIndex != i], X.N[cvIndex != i,], l)
  94.         mean((Y.N[cvIndex == i] - cbind(1, X.N[cvIndex == i,]) %*%
  95.           tmp$coefficients)^2)
  96.       })
  97.     })
  98.     if (parallel)
  99.       sfRemove("cvIndex")
  100.   }
  101.   aaply(CVScores, 2, mean)
  102. }
  103. library(microbenchmark)
  104. microbenchmark(
  105.   CV_f(X, Y, lambda, 10, FALSE)            ,
  106.   CV_f(X, Y, lambda, 10, TRUE, "foreach")  ,
  107.   CV_f(X, Y, lambda, 10, TRUE, "snowfall") ,
  108.   times = 10L)
  109. stopCluster(cl)
  110. sfStop()
  111. #                                     expr      min     mean   median      max neval
  112. #            CV_f(X, Y, lambda, 10, FALSE) 76.13370 83.94225 83.29660 96.79141    10
  113. #  CV_f(X, Y, lambda, 10, TRUE, "foreach") 68.88599 83.31350 84.63615 91.45722    10
  114. # CV_f(X, Y, lambda, 10, TRUE, "snowfall") 56.44479 61.64659 61.78237 69.33333    10
Advertisement
Add Comment
Please, Sign In to add comment