# 【技术分享】特征值分解

这里lambda表示特征向量v所对应的特征值。并且一个矩阵的一组特征向量是一组正交向量。特征值分解是将一个矩阵分解为下面的形式：

其中Q是这个矩阵A的特征向量组成的矩阵。sigma是一个对角矩阵，每个对角线上的元素就是一个特征值。

特征值分解是一个提取矩阵特征很不错的方法，但是它只适合于方阵，对于非方阵，它不适合。这就需要用到奇异值分解。

# 1 源码分析

MLlib使用ARPACK来求解特征值分解。它的实现代码如下

def symmetricEigs(
mul: BDV[Double] => BDV[Double],
n: Int,
k: Int,
tol: Double,
maxIterations: Int): (BDV[Double], BDM[Double]) = {
val arpack = ARPACK.getInstance()
// tolerance used in stopping criterion
val tolW = new doubleW(tol)
// number of desired eigenvalues, 0 < nev < n
val nev = new intW(k)
// nev Lanczos vectors are generated in the first iteration
// ncv-nev Lanczos vectors are generated in each subsequent iteration
// ncv must be smaller than n
val ncv = math.min(2 * k, n)
// "I" for standard eigenvalue problem, "G" for generalized eigenvalue problem
val bmat = "I"
// "LM" : compute the NEV largest (in magnitude) eigenvalues
val which = "LM"
var iparam = new Array[Int](11)
// use exact shift in each iteration
iparam(0) = 1
// maximum number of Arnoldi update iterations, or the actual number of iterations on output
iparam(2) = maxIterations
// Mode 1: A*x = lambda*x, A symmetric
iparam(6) = 1

var ido = new intW(0)
var info = new intW(0)
var resid = new Array[Double](n)
var v = new Array[Double](n * ncv)
var workd = new Array[Double](n * 3)
var workl = new Array[Double](ncv * (ncv + 8))
var ipntr = new Array[Int](11)

// call ARPACK's reverse communication, first iteration with ido = 0
arpack.dsaupd(ido, bmat, n, which, nev.val, tolW, resid, ncv, v, n, iparam, ipntr, workd,
workl, workl.length, info)
val w = BDV(workd)
// ido = 99 : done flag in reverse communication
while (ido.val != 99) {
if (ido.val != -1 && ido.val != 1) {
throw new IllegalStateException("ARPACK returns ido = " + ido.val +
" This flag is not compatible with Mode 1: A*x = lambda*x, A symmetric.")
}
// multiply working vector with the matrix
val inputOffset = ipntr(0) - 1
val outputOffset = ipntr(1) - 1
val x = w.slice(inputOffset, inputOffset + n)
val y = w.slice(outputOffset, outputOffset + n)
y := mul(x)
// call ARPACK's reverse communication
arpack.dsaupd(ido, bmat, n, which, nev.val, tolW, resid, ncv, v, n, iparam, ipntr,
workd, workl, workl.length, info)
}

val d = new Array[Double](nev.val)
val select = new Array[Boolean](ncv)
// copy the Ritz vectors
val z = java.util.Arrays.copyOfRange(v, 0, nev.val * n)

// call ARPACK's post-processing for eigenvectors
arpack.dseupd(true, "A", select, d, z, n, 0.0, bmat, n, which, nev, tol, resid, ncv, v, n,
iparam, ipntr, workd, workl, workl.length, info)

// number of computed eigenvalues, might be smaller than k
val computed = iparam(4)

val eigenPairs = java.util.Arrays.copyOfRange(d, 0, computed).zipWithIndex.map { r =>
(r._1, java.util.Arrays.copyOfRange(z, r._2 * n, r._2 * n + n))
}

// sort the eigen-pairs in descending order
val sortedEigenPairs = eigenPairs.sortBy(- _._1)

// copy eigenvectors in descending order of eigenvalues
val sortedU = BDM.zeros[Double](n, computed)
sortedEigenPairs.zipWithIndex.foreach { r =>
val b = r._2 * n
var i = 0
while (i < n) {
sortedU.data(b + i) = r._1._2(i)
i += 1
}
}
(BDV[Double](sortedEigenPairs.map(_._1)), sortedU)
}

我们可以查看ARPACK的注释详细了解dsaupddseupd方法的作用。

0 条评论

• ### 【技术分享】随机森林分类

Bagging采用自助采样法(bootstrap sampling)采样数据。给定包含m个样本的数据集，我们先随机取出一个样本放入采样集中，再把该样本放回初始...

• ### 【技术分享】带权最小二乘

minimize_{x}\frac{1}{2} \sum_{i=1}^n \frac{w_i(a_i^T x -b_i)^2}{\sum_{k=1}^n w...

• ### 【技术分享】梯度提升树分类

Boosting是一类将弱学习器提升为强学习器的算法。这类算法的工作机制类似：先从初始训练集中训练出一个基学习器，再根据基学习器的表现对训练样本分布进行调整，使...

• ### 求一个数的临近的较大的2的整数次幂

在改进一下，就判断他是不是2的次方先。如果是的话，可以直接返回。就可以得到这种方法。面试官又说，不能用循环递归，函数库。这下麻烦了。

• ### golang 常见变成问题01

往 chan 中放数据时,如果缓冲区已经满那么将 block 以下方方式可以试探往 chan 放数据

• ### spark过节监控告警系统实现

马上要过年了，大部分公司这个时候都不会再去谋求开新业务，而大数据工匠们，想要过好年，就要保证过年期间自己对自己的应用了如执掌。一般公司都会有轮值人员，至少要有春...

• ### 在keras里面实现计算f1-score的代码

1：binary_accuracy（对二分类问题，计算在所有预测值上的平均正确率）

• ### spark基础练习（未完)

1、filter val rdd = sc.parallelize(List(1,2,3,4,5)) val mappedRDD = rdd.map(2*_) ...

• ### SparkCore 编程

2.创建一个数组，根据数据创建一个Bean对象，继承Order，实现序列化(Serializable).从而对数组进行排序。