目的是在 R 中实现正交投影非负矩阵分解 (opnmf) 的快速版本。我正在翻译此处提供的 matlab 代码。
我实现了一个香草 R 版本,但它比我的数据(~225000 x 150)的 20 因子解决方案的 matlab 实现慢得多(慢约 5.5 倍)。
所以我认为使用 c++ 可能会加快速度,但它的速度与 R 相似。我认为这可以优化但不知道如何作为 c++ 的新手。这是一个讨论类似问题的线程。
这是我的 RcppArmadillo 实现。
// [[Rcpp::export]]
Rcpp::List arma_opnmf(const arma::mat & X, const arma::mat & W0, double tol=0.00001, int maxiter=10000, double eps=1e-16) {
arma::mat W = W0;
arma::mat Wold = W;
arma::mat XXW = X * (X.t()*W);
double diffW = 9999999999.9;
Rcout << "The value of maxiter : " << maxiter << "\n";
Rcout << "The value of tol : " << tol << "\n";
int i;
for (i = 0; i < maxiter; i++) {
XXW = X * (X.t()*W);
W = W % XXW / (W * (W.t() * XXW));
//W = W % (X*(X.t()*W)) / (W*((W.t()*X)*(X.t()*W)));
arma::uvec idx = find(W < eps);
W.elem(idx).fill(eps);
W = W / norm(W,2);
diffW = norm(Wold-W, "fro") / norm(Wold, "fro");
if(diffW < tol) {
break;
} else {
Wold = W;
}
if(i % 10 == 0) {
Rcpp::checkUserInterrupt();
}
}
return Rcpp::List::create(Rcpp::Named("W")=W,
Rcpp::Named("iter")=i,
Rcpp::Named("diffW")=diffW);
}
这个建议的问题证实了matlab相当快,那么使用R/c++时没有希望了吗?
测试是在 Windows 10 和 Ubuntu 16 以及 R 版本 4.0.0 上进行的。
编辑
在下面的答案中有趣的评论之后。我正在发布其他详细信息。我在带有 R 3.5.3(微软提供的)的 Windows 10 机器上进行了测试,比较表明带有微软 R 的 RcppArmadillo 是最快的。
R
user system elapsed
213.76 7.36 221.42
R 与 RcppArmadillo
user system elapsed
179.88 3.44 183.43
微软的开放 R
user system elapsed
167.33 9.96 45.94
微软与 RcppArmadillo 合作
user system elapsed
85.47 4.66 23.56