C++ C++;特征值/向量分解,只需前n个向量即可快速分解
我有一个~3000x3000的类似协方差矩阵,在这个矩阵上我计算特征值特征向量分解(这是一个OpenCV矩阵,我使用C++ C++;特征值/向量分解,只需前n个向量即可快速分解,c++,eigenvector,C++,Eigenvector,我有一个~3000x3000的类似协方差矩阵,在这个矩阵上我计算特征值特征向量分解(这是一个OpenCV矩阵,我使用cv::eigen()来完成这项工作) 然而,我实际上只需要,比如说,前30个特征值/向量,我不关心其余的。理论上,这应该可以大大加快计算速度,对吗?我的意思是,这意味着它有2970个需要计算的特征向量
cv::eigen()
来完成这项工作)
然而,我实际上只需要,比如说,前30个特征值/向量,我不关心其余的。理论上,这应该可以大大加快计算速度,对吗?我的意思是,这意味着它有2970个需要计算的特征向量 <哪个C++库允许我这么做?请注意,OpenCV的
eigen()
方法确实有用于此的参数,但是文档中说它们被忽略了,我自己测试过,它们确实被忽略了:D
更新:
我设法用ARPACK做到了。我设法为windows编译了它,甚至使用了它。结果看起来很有希望,在这个玩具示例中可以看到一个例子:
#include "ardsmat.h"
#include "ardssym.h"
int n = 3; // Dimension of the problem.
double* EigVal = NULL; // Eigenvalues.
double* EigVec = NULL; // Eigenvectors stored sequentially.
int lowerHalfElementCount = (n*n+n) / 2;
//whole matrix:
/*
2 3 8
3 9 -7
8 -7 19
*/
double* lower = new double[lowerHalfElementCount]; //lower half of the matrix
//to be filled with COLUMN major (i.e. one column after the other, always starting from the diagonal element)
lower[0] = 2; lower[1] = 3; lower[2] = 8; lower[3] = 9; lower[4] = -7; lower[5] = 19;
//params: dimensions (i.e. width/height), array with values of the lower or upper half (sequentially, row major), 'L' or 'U' for upper or lower
ARdsSymMatrix<double> mat(n, lower, 'L');
// Defining the eigenvalue problem.
int noOfEigVecValues = 2;
//int maxIterations = 50000000;
//ARluSymStdEig<double> dprob(noOfEigVecValues, mat, "LM", 0, 0.5, maxIterations);
ARluSymStdEig<double> dprob(noOfEigVecValues, mat);
// Finding eigenvalues and eigenvectors.
int converged = dprob.EigenValVectors(EigVec, EigVal);
for (int eigValIdx = 0; eigValIdx < noOfEigVecValues; eigValIdx++) {
std::cout << "Eigenvalue: " << EigVal[eigValIdx] << "\nEigenvector: ";
for (int i = 0; i < n; i++) {
int idx = n*eigValIdx+i;
std::cout << EigVec[idx] << " ";
}
std::cout << std::endl;
}
对于特征值,以及
-0.523207, -0.83446237, -0.17299346
0.273269, -0.356554, 0.893416
分别针对2个特征向量(每行一个特征向量)
代码无法找到3个特征向量(在这种情况下,它只能找到1-2,assert()可以确保这一点,但这不是问题)。在文章中,Simon Funk展示了一种简单有效的方法来估计非常大矩阵的奇异值分解(SVD)。在他的例子中,矩阵是稀疏的,维数为:17000 x 500000
现在,我们来看一下,描述了特征值分解如何与奇异值分解密切相关。因此,您可能会从Simon Funk方法的修改版本中获益,特别是当您的矩阵稀疏时。此外,您的矩阵不仅是平方的,而且是对称的(如果这就是您所说的协方差的意思),这可能会导致额外的简化
。。。只是一个想法:)看来这将以良好的表现完成这项工作
以下是他们文档中的一个示例,用于计算密集对称矩阵M(同样是协方差矩阵)的3个第一特征值:
#包括
#包括
//是隐式包含的
#包括
使用名称空间谱;
int main()
{
//我们要计算M的特征值
本征::矩阵XXD A=本征::矩阵XXD::随机(10,10);
本征::矩阵M=A+A.转置();
//使用包装类DenseSymMatProd构造矩阵运算对象
密度SymmatProd op(M);
//构造特征解算器对象,请求最大的三个特征值
符号解算器eigs(&op,3,6);
//初始化并计算
eigs.init();
int nconv=eigs.compute();
//检索结果
本征::向量xd求值;
如果(eigs.info()==成功)
evalues=eigs.特征值();
std::cout通过“前30个特征值/向量”,你是指具有最大模、最大实部的特征值,还是其他什么?谷歌搜索后,它看起来可能有你想要的。我会使用ARPACK。你会立即得到你的30个特征向量。“从理论上讲,这应该可以大大加快计算速度,对吗?"这取决于所使用的算法,至少不是很简单。但是,是的,有一些算法只允许在某些特征值范围内快速计算特征向量。Arnoldi/Lanczos是最突出的,所以ARPACK是一种标准的。它太旧并不意味着它不好,如果你真的想要性能,它当然是很棒的;但我同意这些Fortran库的使用非常糟糕。啊,我想你的意思是,Egeng不做你想做的事,而不是ARPACK。对不起。无论如何,我能说的是,我以前使用的是直接算法,可能需要很多分钟,而且经常消耗所有系统内存来产生任何结果。有了ARPACK,我可以得到最初的几个结果一两秒钟内就有一百对本征对,而不需要大量的系统资源。@NameZero912,如果您有答案,但没有人提供,请自己回答并接受。这将使此问题从未回答的问题列表中删除。:)
-0.523207, -0.83446237, -0.17299346
0.273269, -0.356554, 0.893416
#include <Eigen/Core>
#include <Spectra/SymEigsSolver.h>
// <Spectra/MatOp/DenseSymMatProd.h> is implicitly included
#include <iostream>
using namespace Spectra;
int main()
{
// We are going to calculate the eigenvalues of M
Eigen::MatrixXd A = Eigen::MatrixXd::Random(10, 10);
Eigen::MatrixXd M = A + A.transpose();
// Construct matrix operation object using the wrapper class DenseSymMatProd
DenseSymMatProd<double> op(M);
// Construct eigen solver object, requesting the largest three eigenvalues
SymEigsSolver< double, LARGEST_ALGE, DenseSymMatProd<double> > eigs(&op, 3, 6);
// Initialize and compute
eigs.init();
int nconv = eigs.compute();
// Retrieve results
Eigen::VectorXd evalues;
if(eigs.info() == SUCCESSFUL)
evalues = eigs.eigenvalues();
std::cout << "Eigenvalues found:\n" << evalues << std::endl;
return 0;
}