簡體   English   中英

使用 R 和 Rcpp,如何將兩個稀疏 Matrix::csr/csc 格式的矩陣相乘?

[英]Using R and Rcpp, how to multiply two matrices that are sparse Matrix::csr/csc format?

以下代碼按預期工作:

矩陣.cpp

// [[Rcpp::depends(RcppEigen)]]

#include <RcppEigen.h>

// [[Rcpp::export]]
SEXP eigenMatTrans(Eigen::MatrixXd A){
    Eigen::MatrixXd C = A.transpose();

    return Rcpp::wrap(C);
}

// [[Rcpp::export]]
SEXP eigenMatMult(Eigen::MatrixXd A, Eigen::MatrixXd B){
    Eigen::MatrixXd C = A * B;

    return Rcpp::wrap(C);
}

// [[Rcpp::export]]
SEXP eigenMapMatMult(const Eigen::Map<Eigen::MatrixXd> A, Eigen::Map<Eigen::MatrixXd> B){
    Eigen::MatrixXd C = A * B;

    return Rcpp::wrap(C);
}

這是使用 C++ eigen class 作為矩陣,參見https://eigen.tuxfamily.org/dox

在 R 中,我可以訪問這些功能。

library(Rcpp);
Rcpp::sourceCpp('matrix.cpp');  

A <- matrix(rnorm(10000), 100, 100);
B <- matrix(rnorm(10000), 100, 100);
library(microbenchmark);

microbenchmark(eigenMatTrans(A), t(A), A%*%B, eigenMatMult(A, B), eigenMapMatMult(A, B))

這表明 R 在轉置(轉置)方面表現相當不錯。 乘法與本征有一些優點。

使用 Matrix 庫,我可以將普通矩陣轉換為稀疏矩陣。

示例來自https://cmdlinetips.com/2019/05/introduction-to-sparse-matrices-in-r/

library(Matrix);
data<- rnorm(1e6)
zero_index <- sample(1e6)[1:9e5]
data[zero_index] <- 0
A = matrix(data, ncol=1000)

A.csr = as(A, "dgRMatrix");
B.csr = t(A.csr);

A.csc = as(A, "dgCMatrix");
B.csc = t(A.csc);

因此,如果我想使用 eigen 將 A.csr 乘以 B.csr,如何在 C++ 中做到這一點? 如果不需要,我不想轉換類型。 是 memory 大小的東西。

A.csr %*% B.csr尚未實現。 A.csc %*% B.csc正在工作。

我想對不同的選項進行微基准測試,看看矩陣大小如何最有效。 最后,我將有一個大約 1% 稀疏的矩陣,並且有 500 萬行和列...

dgRMatrix 叉積函數尚未實現是有原因的,事實上,它們不應該被實現,否則它們會導致不好的做法。

使用稀疏矩陣時有一些性能注意事項:

  • 針對主要邊緣方向訪問邊緣觀點是非常低效的。 例如,dgRMatrix 中的列迭代器和 dgCMatrix 中的行迭代器需要遍歷矩陣的幾乎所有元素,才能僅在該列或行中找到元素。 請參閱此Rcpp 畫廊帖子以獲得更多啟發。
  • 矩陣叉積只是所有列組合之間的點積。 這意味着在 dgRMatrix 中使用列迭代器(相對於 dgCMatrix 中的列迭代器)的損失乘以列組合的數量。
  • R 中的叉積函數經過高度優化,並且(根據我的經驗)並不比 Eigen、Armadillo、等效的 STL 變體快得多。 它們是並行化的,Matrix package 充分利用了這些優化算法。 我已經使用 Rcpp 結構編寫了 C++ 並行化 STL 叉積變體,但我看不到性能有任何提高。
  • 如果您真的要走這條路,請查看我在 Rcpp 中的稀疏矩陣結構上的Rcpp 畫廊帖子。 This is to be preferred to Eigen and Armadillo Sparse Matrices if memory is a concern, as Eigen and Armadillo perform a deep copy rather than a reference to an R object already existing in memory.
  • 在 1% 的密度下,行迭代器的低效率將大於 5% 或 10% 的密度。 我以 5% 的密度進行大部分測試,通常二進制操作對於行迭代器比列迭代器花費的時間長 5-10 倍。

可能存在行優先排序大放異彩的應用程序(即參見 Dmitry Selivanov 在 CSR 矩陣和 irlba svd 上的工作),但這絕對不是其中之一,事實上,所以你最好進行就地轉換得到一個 CSC 矩陣。

tl; dr :行主要矩陣中的按列交叉積是低效率的最后通牒。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM