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

原理

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

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

Mm×n=Xm×mΣm×nVn×n

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

Am×nUm×kSk×kVn×k

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

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

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


举例:

设矩阵 A23

A=(4.05.02.06.03.01.0)

则矩阵A的转置:列变行 AT32

AT=4.02.03.05.06.01.0

AAT

AAT=(29.035.035.062.0)

AAT 的特征值和特征向量:由 (AAT)Vi=λiRi 求得。

AAT 的特征值:

84.1943148278917,6.805685172108291


AAT 每一特征值对应的特征向量(列向):

-0.5355281357229256 0.8445173863510019

-0.8445173863510022,-0.5355281357229257

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

S22=(9.1757460093385160.00.02.608770816324863)

右奇异向量:由 ui=Ri 求得右奇异矩阵U。 ui:Ui

U22=(0.53552813572292560.84451738635100220.84451738635100190.5355281357229257)

左奇异向量:由 vi=1siATui 求得左奇异矩阵V。 vi:Vi

V32=0.69364381579101130.66895493655827190.26712833932251350.268489996287262170.58423454912098840.7658871414947904

如:

1s1=19.175746009338516=0.10898296432598079

u1=DenseVector(0.5355281357229256,0.8445173863510022)

则由 v1=1s1ATu1 即可求得。

实战

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的现实意义

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

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

也达到了降维的目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值