您的位置:首页 > 其它

Spark MLlib特征处理:SVD 奇异值分解 ---原理及实战

2016-11-16 20:00 411 查看

原理

工业应用上的奇异值分解是近似的奇异值分解,而严格数学意义上的奇异值分解并非这样定义。

严格数学意义上的奇异值分解:

Mm×n=Xm×m∗Σm×n∗V′n×n

工业应用上的奇异值分解SVD就是把一个矩阵A做如下转换:

Am×n≈Um×k∗Sk×k∗V′n×k

Um×k:在MLlib中叫右奇异矩阵(很疑惑,但在MLlib里确实如此),里边包含右奇异向量。由Spark源码:U, the matrix storing the right singular vectors.可知。

Sk×k:奇异值对角方阵,MLlib中奇异值按降序排序,取top k,除奇异值所在的对角线,其他位置全为0。

V′n×k:在MLlib中叫左奇异矩阵,里边包含左奇异向量。

举例:

设矩阵A2∗3

A=(4.05.02.06.03.01.0)

则矩阵A的转置:列变行 AT3∗2

AT=⎛⎝⎜4.02.03.05.06.01.0⎞⎠⎟

则A∗AT

A∗AT=(29.035.035.062.0)

则A∗AT的特征值和特征向量:由(A∗AT)Vi=λiRi求得。

A∗AT的特征值:

84.1943148278917,6.805685172108291

A∗AT每一特征值对应的特征向量(列向):

-0.5355281357229256 0.8445173863510019

-0.8445173863510022,-0.5355281357229257

奇异值s:由si=λi−−√求得奇异值对角方阵

S2∗2=(9.1757460093385160.00.02.608770816324863)

右奇异向量:由ui=Ri求得右奇异矩阵U。ui:U矩阵的第i列

U2∗2=(−0.5355281357229256−0.84451738635100220.8445173863510019−0.5355281357229257)

左奇异向量:由vi=1si∗AT∗ui求得左奇异矩阵V。vi:V矩阵的第i列

V3∗2=⎛⎝⎜−0.6936438157910113−0.6689549365582719−0.26712833932251350.26848999628726217−0.58423454912098840.7658871414947904⎞⎠⎟

如:

1s1=19.175746009338516=0.10898296432598079

u1=DenseVector(−0.5355281357229256,−0.8445173863510022)

则由v1=1s1∗AT∗u1即可求得。

实战

import org.apache.spark.mllib.linalg.distributed.RowMatrix
import org.apache.spark.mllib.linalg.{Matrix, SingularValueDecomposition, Vector, Vectors}
import org.apache.spark.sql.{Row, SQLContext}
import org.apache.spark.{SparkContext, SparkConf}

/**
*  A ~= U * S * V'
*  降低A的储存和运算空间,提高效率
*/
object SVDExample {
def main(args: Array[String]) {
val conf = new SparkConf().setAppName("PCAExample").setMaster("local[8]")
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)

val data =Array(
Vectors.dense(4.0 , 2.0 , 3.0),
Vectors.dense(5.0 , 6.0 , 1.0))

// Array[Vector]转换成DataFrame
val df = sqlContext.createDataFrame(data.map(Tuple1.apply)).toDF("features")

// DataFrame转换成RDD
val df_To_rdd=df.select("features").map { case Row(v: Vector) => v}

// RDD转换成矩阵
// 矩阵的每一行分布式存储
val mat: RowMatrix = new RowMatrix(df_To_rdd)

// 奇异值分解
// def computeSVD(k: Int,computeU: Boolean = false,rCond: Double = 1e-9)
//k:取top k个奇异值
//computeU:是否计算矩阵U
//rCond:小于1.0E-9d的奇异值会被抛弃
val svd: SingularValueDecomposition[RowMatrix, Matrix] = mat.computeSVD(2,true)
// s奇异值向量
println(svd.s)
//[9.175746009338516,2.608770816324863]
// U右奇异矩阵
svd.U.rows.foreach(println)
// [-0.5355281357229256,0.8445173863510019]
// [-0.8445173863510022,-0.5355281357229257]
// V左奇异矩阵
println(svd.V)
// -0.6936438157910113  0.26848999628726217
// -0.6689549365582719  -0.5842345491209884
// -0.2671283393225135  0.7658871414947904

}

}


SVD的现实意义

以下部分来自吴军老师的数学之美。

如矩阵A100万∗50万100万篇文章,每篇文章50万个特征,该矩阵的总元素有5000亿个,储存量和计算量非常大。如果用SVD做矩阵分解,A100万∗50万≈U100万∗100∗S100∗100∗V′50万×100,既把A近似的表示为3个矩阵U、S、V′,总元素不超过1.5亿,大大减少了储存量和计算量。

也达到了降维的目的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: