zoukankan      html  css  js  c++  java
  • 机器学习实战 11- SVD

    1 SVD 相关理论

    1.1 奇异值分解定义

    SVD,即奇异值分解,矩阵论中学过内容,公式为:

    用一张图来形象表达一下:

    其中的奇异值矩阵,奇异值从大到小排列,而且减少的特别快,我们可以用前面最大的k个奇异值来表示这个原有矩阵,且保留大部分信息。如图:

    1.2 与PCA有何勾结

    之前我们解释过 PCA ,PCA 的本质就是将原数据投影到低维坐标系中,获取主要信息值,起到降维作用。

    究竟 SVD 与其有何关系呢?我们看一下下面的公式推导,就明白了。

    由上图可以比较出,PCA 中得到的 P 就是奇异值分解中的 V。

    如果需要给列降维到 k ,则:

    如果需要给行降维到 k ,则:

    左奇异矩阵负责给行降维,一般用来减小无效样本。

       右奇异矩阵负责给列降维,一般用来缩减特征。

    1.3 优点与用途

    优点:

    当我们使用PCA的时候,用到协方差矩阵,但是当样本数量m大特征n也大的时候,协方差就不好计算,特征值和特征向量就不易求出。此时如果使用SVD,速度快很多,有人会说,奇异值分解时不也是利用了协方差矩阵么?其实不然这只是求取分解的一种方法,一般会使用迭代的办法,这里不赘述,只需明白它的计算速度远远加快,有兴趣可以看看这两篇文章:

    并行计算奇异值:https://www.cnblogs.com/zhangchaoyang/articles/2575948.html

    一篇关于奇异值计算的论文:http://www.cs.utexas.edu/users/inderjit/public_papers/HLA_SVD.pdf

      用途:

      1. 特征降维

      2. 去除噪声

      3. 推荐系统

      4. 信息搜索(潜在语义分析,LSA)

    2 Python 实例

    2.1 基于 SVD 的图像压缩

     1 from numpy import *
     2 from numpy import linalg as la
     3 
     4 def printMat(inMat,thresh=0.8):
     5     for i in range(32):
     6         for k in range(32):
     7             if float(inMat[i,k])>thresh:
     8                 # pycharm中会自动换行,此处加上 end=‘’ ,以达到效果
     9                 print('1',end='')
    10             else:
    11                 print('0',end='')
    12         print('')
    13 
    14 def imgCompress(numSV=3,thresh=0.8):
    15     my1=[]
    16     for line in open('0_5.txt').readlines():
    17         newRow=[]
    18         for i in range(32):
    19             newRow.append(int(line[i]))
    20         my1.append(newRow)
    21     myMat=mat(my1)
    22     print(myMat)
    23     print("***** original matrix *****")
    24     printMat(myMat,thresh)
    25     U,Sigma,VT=la.svd(myMat)
    26     SigRecon=mat(zeros((numSV,numSV)))
    27     for k in range(numSV):
    28         SigRecon[k,k]=Sigma[k]
    29     reconMat=U[:,:numSV]*SigRecon*VT[:numSV,:]
    30     print("***** reconstructed matrix using %d singular values *****")
    31     printMat(reconMat,thresh)
    32 
    33 imgCompress(2)

    分析:

      1. 左边原始矩阵,右边是奇异值分解后处理矩阵,得到的图像基本一致,可以看到只需要两个奇异值就能相对准确地对图像重建。
      2. 内存使用:原始图像:32*32=1024,奇异值分解后:2*32+2+2*32=130,缩小了将近10倍。

    2.2 餐馆菜肴推荐引擎

    过程:

      1. 寻找用户没有评级的菜肴,即在用户-物品矩阵中的 0 值。
      2. 在用户没有评级的所有物品中,对每个物品预计一个可能的评级的分数。(利用相似度进行计算)
      3. 对这些物品的评分从高到低排序,返回前 N 个物品。

    程序:

      1 from numpy import *
      2 from numpy import linalg as la
      3 import matplotlib.pyplot as plt
      4 
      5 # 1. 输入数据,用户-物品评级矩阵
      6 def loadExData2():
      7     return [[2, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0],
      8             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5],
      9             [0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 0],
     10             [3, 3, 4, 0, 3, 0, 0, 2, 2, 0, 0],
     11             [5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0],
     12             [0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0],
     13             [4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5],
     14             [0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4],
     15             [0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0],
     16             [0, 0, 0, 3, 0, 0, 0, 0, 4, 5, 0],
     17             [1, 1, 2, 1, 1, 2, 1, 0, 4, 5, 0]]
     18 
     19 # 2. 几种计算相似度的方法,
     20 # 欧式距离
     21 def ecludSim(inA,inB):
     22     return 1.0/(1.0+la.norm(inA-inB))
     23 # 皮尔逊距离
     24 def pearsSim(inA,inB):
     25     if len(inA)<3:
     26         return 1.0
     27     return 0.5+0.5*corrcoef(inA,inB,rowvar=0)[0][1]
     28 # 余弦距离
     29 def cosSim(inA,inB):
     30     num =float(inA.T*inB)
     31     denom=la.norm(inA)*la.norm(inB)
     32     return 0.5+0.5*(num/denom)
     33 
     34 # 3. 计算给定相似度计算方法下的估计评分值
     35 # 指定用户 user 给未评定物品 item 评分
     36 def standEst(dataMat,user,simMeas,item):
     37     n=shape(dataMat)[1]
     38     simTotal=0.0
     39     ratSimTotal=0.0
     40     # 遍历每一个物品,根每一个有过评分的物品比较,计算相似度,推测出评分
     41     for j in range(n):
     42         userRating=dataMat[user,j]
     43         # 如果某个用户没有对这个物品评分,跳过这个值
     44         if userRating==0:
     45             continue
     46         # 比较目标物品和已被评分过的物品重合程度
     47         overLap=nonzero(logical_and(dataMat[:,item].A>0,dataMat[:,j].A>0))[0]
     48         # 如果重合为0,则相似度为0
     49         if len(overLap)==0:
     50             similarity=0
     51         else:
     52             # 如果有重合,基于这些特征重合计算相似度
     53             similarity=simMeas(dataMat[overLap,item],dataMat[overLap,j])
     54             # print("the %d and %d similarity is: %f "%(item,j,similarity))
     55         # 累加相似度
     56         simTotal+=similarity
     57         # 累加相似度和评分的乘积,可以得到评分总和,(归一化的)
     58         ratSimTotal+=similarity*userRating
     59     if simTotal==0:
     60         return 0
     61     else:
     62         return ratSimTotal/simTotal
     63 
     64 # 4. 使用 SVD 降维后进行相似度计算
     65 def svdEst(dataMat,user,simMeas,item):
     66     n=shape(dataMat)[1]
     67     simTotal=0.0
     68     ratSimTotal=0.0
     69     U, Sigma, VT = la.svd(dataMat)
     70     # 取 sigma 前4的值,构建对角矩阵
     71     Sig4=mat(eye(4)*Sigma[:4])
     72     # 将原数据投影到左奇异矩阵上,使其行降维,即减少无效用户
     73     xformedItems=dataMat.T*U[:,:4]*Sig4.I
     74     for j in range(n):
     75         userRating=dataMat[user,j]
     76         if userRating==0 or j==item:
     77             continue
     78         similarity=simMeas(xformedItems[item,:].T,xformedItems[j,:].T)
     79         # print("the %d and %d similarity is: %f "%(item,j,similarity))
     80         simTotal += similarity
     81         # 累加相似度和评分的乘积,可以得到评分总和,(归一化的)
     82         ratSimTotal += similarity * userRating
     83     if simTotal == 0:
     84         return 0
     85     else:
     86         return ratSimTotal / simTotal
     87 
     88 # 5. 推荐引擎,返回得分较高的前 N 个物品
     89 def recommend(dataMat,user,N=3,simMeas=cosSim,estMethod=standEst):
     90     # 寻找未评级的物品
     91     unratedItems=nonzero(dataMat[user,:].A==0)[1]
     92     if len(unratedItems)==0:
     93         return print("you rated everything")
     94     itemScores=[]
     95     for item in unratedItems:
     96         estimatedScore=estMethod(dataMat,user,simMeas,item)
     97         itemScores.append((item,estimatedScore))
     98     return sorted(itemScores,key=lambda jj:jj[1],reverse=True)[:N]
     99 
    100 myMat=mat(loadExData2())
    101 print(recommend(myMat,1,estMethod=svdEst))
    102 print(recommend(myMat,1))
    103 U,Sigma,VT=linalg.svd(myMat)
    104 Sig2=Sigma**2
    105 fig=plt.figure()
    106 ax=fig.add_subplot(111)
    107 ax.pie(Sig2,autopct='%1.1f')
    108 plt.show()
    View Code

    结果:

     

    分析:

    1. 对奇异值分析可知,前五个值占了绝大部分信息(注意这里与书里有些不一致)
    2. 使用SVD分解后的数据推荐引擎更准确

    提高构建推荐引擎时的效率:

    1. SVD 大量数据分解速度慢,尽量运行一次或者离线运行。
    2. 零元素太多,通过储存非零元素节省资源。
    3. 每次需要推荐一个得分时,都需要计算多个物品的相似度,离线计算并保存相似度。
    4. 冷启动问题:如何在缺乏数据时给出好的推荐。将推荐看成搜索问题。

    参考文献:

    1. 奇异值分解与在降维中的应用    https://www.cnblogs.com/pinard/p/6251584.html
  • 相关阅读:
    Java开发系列-电子邮箱
    Java开发系列-文件上传
    iOS开发系列-常见离线存储方式
    Java开发系列-注解
    Java开发系列-JSP
    Java开发系列-Cookie与Session会话技术
    Java开发系列-JDBC
    Java开发系列-MySQL
    Java开发系列-时间转换
    java开发系列-服务器tomcat
  • 原文地址:https://www.cnblogs.com/Ray-0808/p/11000591.html
Copyright © 2011-2022 走看看