• 机器学习实战-SVD


    14.1 SVD的应用

    特点:

    利用SVD能够用小得多的数据集来表示原始数据集。

    优点:简化数据,去除噪声,提高算法的结果。

    缺点:数据的转换可能难以理解。

    隐性语义索引(LSI)

    利用SVD的方法为隐性语义索引(Latent Semantic Indexing, LSI)或隐性语义分析(Latent Semantic Analysis, LSA)。在LSI中,一个矩阵是由文档和词语组成的,应用SVD时,会构建出多个奇异值,其代表了文档中的概念或主题。

    推荐系统

    上述矩阵由餐馆的菜和品菜师对这些菜的意见构成的。品菜师采用1到5之间的任意一个整数来对菜评级,如果品菜师没有尝过某道菜,则评级为0。对上述矩阵进行SVD分解,会得到两个奇异值(注意其特征值位2),也即仿佛有两个概念或主题与此数据集相关联。

     

    14.2 矩阵分解

    在很多情况下,数据中的一小段携带了数据集中的大部分信息,其他信息则要么是噪声,要么就是毫不相关的信息。在线性代数中还有很多矩阵分解技术。 矩阵分解可以将原始矩阵表示成新的易于处理的形式。

    SVD将原始数据集矩阵Data分解成三个矩阵U,sigma,V.T。(分解为多个矩阵的乘积)


    Figure 14-1: SVD矩阵分解公式

    分解出来的sigma矩阵为对角阵,对角元素从大到小排列,称之为奇异值(Singular Value),奇异值和特征值是有关系的,这些奇异值为Data*Data.T特征值的平方根。且若是Data的秩为r,则奇异值的个数为r个,也即数据集中仅有r个重要特征

    sigma矩阵只有从大到小排列的元素,在科学和工程中的一个事实:在某个奇异值的特征数目(N个)之后,其他的奇异值置为0

    14.3 利用python实现SVD

    python numpy包里有linalg的线性代数工具箱,其有包括处理svd分解函数。

         奇异值分解代码:

    #!/usr/bin/env python
    # coding=utf-8
    from numpy import *
    from numpy import linalg as la
    def loadExData():
        return [[1,1,1,0,0],
               [2,2,2,0,0],
               [5,5,5,0,0],
               [1,1,0,2,2],
               [0,0,0,3,3],
               [0,0,0,1,1]]
    Data = loadExData()
    U,Sigma,VT = la.svd(Data)
    Sig3 = mat([[Sigma[0],0,0],[0,Sigma[1],0],[0,0,Sigma[2]]])#由于Sigma是以向量的形式存储,故需要将其转为矩阵,
    #利用numpy的diag函数,直接Sig3 = np.diag(Sigma)[:3,:3]即可,diag将行向量转为矩阵,值放在对角线上,并取前面3行3列
    print Sigma
    print U[:,:3]*Sig3*VT[:3,:]#重构原始矩阵

    保留奇异值的数目:

    1. 保留矩阵中90%的能量信息。将所有的奇异值求平方和,将奇异值平方和累加到总值的90%为止。(如何累加)
    2. 保留上万奇异值中的前面2000到3000个。

    14.4 基于协同过滤的推荐引擎

    协同过滤通过将用户和其他用户的数据进行对比来实现推荐的。

    当知道了两个用户或者两个物品之间的相似度,我们就可以利用已有的数据来预测未知的用户喜好。

    唯一所需要的数学方法就是相似度的计算。

    相似度计算:


    Figure 14-4: 用于展示相似度计算的简单矩阵

    手撕猪肉与鳗鱼饭的欧式距离


    相似度化为0到1之间:相似度=1/(1+距离)。

    皮尔逊相关系数(Pearson correlation):

    由numpy包中corrcoef()函数计算,化为0到1之间:0.5+0.5*corrcoef()。

    余弦相似度(cosine similarity):

       相似度计算代码:

    #利用欧氏距离计算相似度
    #linalg.norm(inA - inB)计算范数,及平方和再开方
    def ecludSim(inA,inB):
        return 1.0/(1.0 + la.norm(inA - inB))
    #皮尔逊相关系数计算相似度 优点是对用户评价的量级不敏感
    #corrcoef(a)是用来计算相关系数矩阵
    #corrcoef(a,b)是用来计算相关系数矩阵
    def pearsSim(inA,inB):
        if len(inA) < 3 : return 1.0
        #计算系数并把范围从-1--+1转换为0--1
        return 0.5+0.5*corrcoef(inA, inB, rowvar = 0)[0][1]
    #计算余弦相似度
    def cosSim(inA,inB):
        num = float(inA.T*inB)
        denom = la.norm(inA)*la.norm(inB)
        #计算系数并把范围从-1--+1转换为0--1
        return 0.5+0.5*(num/denom)

    基于物品的相似度还是基于用户的相似度

    行与行之间比较的是基于用户的相似度,列与列之间比较的则是基于物品的相似度。基于物品相似度计算的时间会随物品数量的增加而增加,基于用户的相似度计算的时间则会随用户数量的增加而增加。如果用户的数目很多,那么我们可能倾向于使用基于物品相似度的计算方法。对于大部分产品导向的推荐系统而言,用户的数量往往大于物品的数量,即购买商品的用户数会多于出售的商品种类。

    推荐系统的评价

    我们将某些已知的评分值去掉,然后对它们进行预测,最后计算预测值与真实值之间的差异。通常使用的指标为最小均方根误差(Root Mean Squared Error, RMSE)。

    14.5 示例:餐馆菜肴推荐引擎

    推荐未尝过的菜肴

    过程:给定一个用户,系统会为此用户返回N个最好的推荐菜。需要:

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

       代码如下:

      

    #用户对物品的评分估计值(数据集,用户编号,相似度计算方法,物品编号)
    def standEst(dataMat, user, simMeas, item):
        #矩阵的列数 也就是物品数量
        n = shape(dataMat)[1]
        #估计评分值初始化
        simTotal = 0.0; ratSimTotal = 0.0
        #对给定用户
        for j in range(n):
            #某个用户对某个物品的评分
            userRating = dataMat[user,j]
            #如果某个物品的评分值为0,没有评分 跳过这个物品
            if userRating == 0: continue
            #nonzeros(a)返回数组a中值不为零的元素的下标
            #logical_and (逻辑与)
            #给出两个物品中已经被评分的那个元素,有没有重合
            overLap = nonzero(logical_and(dataMat[:,item].A>0,dataMat[:,j].A>0))[0]
            if len(overLap) == 0: #如果没有重叠 相似度为零并且终止本次循环
                similarity = 0
            else:                 #如果有重叠 计算相似度
                similarity = simMeas(dataMat[overLap,item],dataMat[overLap,j])
            print ('the %d and %d similarity is: %f' % (item, j, similarity))
            #相似度的累加
            simTotal += similarity  
            #相似度和当前用户评分的乘积
            ratSimTotal += similarity * userRating 
        if simTotal == 0: 
            return 0
        else: 
            return ratSimTotal/simTotal #对相似度评分的乘积进行归一化 评分值在0--5之间
    
    #推荐引擎 产生推荐最高的N个结果
    #(数据矩阵,用户,推荐个数,相似度计算方法,评分估计值)
    def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):
        #建立一个未评分的物品列表
        unratedItems = nonzero(dataMat[user,:].A==0)[1]
        #如果不存在未评分物品 则退出
        if len(unratedItems) == 0: 
            return 'you rated everything'
        itemScores = []
        #否则 在所有未评分物品上循环,对每个物品评分
        for item in unratedItems:
            #对未评分物品评分
            estimatedScore = estMethod(dataMat, user, simMeas, item)
            itemScores.append((item, estimatedScore))
        #返回排序后的列表 反转以后的 从大到小
        return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[:N]

      利用SVD进提高推荐的效果

      计算在奇异值的总能量,了解其到底需要多少维特征。

      代码:

    def loadExData2():
            return [[0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 5],
                             [0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 3],
                             [0, 0, 0, 0, 4, 0, 0, 1, 0, 4, 0],
                             [3, 3, 4, 0, 0, 0, 0, 2, 2, 0, 0],
                             [5, 4, 5, 0, 0, 0, 0, 5, 5, 0, 0],
                             [0, 0, 0, 0, 5, 0, 1, 0, 0, 5, 0],
                             [4, 3, 4, 0, 0, 0, 0, 5, 5, 0, 1],
                             [0, 0, 0, 4, 0, 4, 0, 0, 0, 0, 4],
                             [0, 0, 0, 2, 0, 2, 5, 0, 0, 1, 2],
                             [0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0],
                             [1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0]]
    
    U,Sigma,VT = la.svd(mat(loadExData2()))
    print Sigma
    Sig2 =  Sigma**2
    print Sig2
    print sum(Sig2)*0.9
    print sum(Sig2[:2])
    print sum(Sig2[:3])

    计算得到需要3个特征

    前3个元素所包含的能量超过总能量的90%,故可以将这个11维的矩阵转换为3维矩阵。
    对转换后的三维空间构造出一个相似度计算函数。利用SVD将所有的菜肴映射到一个低维空间。

     代码:

    #基于svd的评分估计值
    #(数据集,用户编号,相似度计算方法,物品编号)
    def svdEst(dataMat, user, simMeas, item):
        #矩阵的列数 也就是物品数量
        n = shape(dataMat)[1]
        #估计评分值初始化
        simTotal = 0.0; ratSimTotal = 0.0
        #奇异值分解 只利用包含90%能量的奇异值
        U,Sigma,VT = la.svd(dataMat)
        #用奇异值构建出一个对角矩阵
        Sig4 = mat(eye(4)*Sigma[:4])
        #用U矩阵将物品转换到低维空间中
        xformedItems = dataMat.T * U[:,:4] * Sig4.I  #create transformed items
        #对给定用户
        for j in range(n):
            #某个用户对某个物品的评分
            userRating = dataMat[user,j]
            #如果某个物品的评分值为0,没有评分 跳过这个物品
            if userRating == 0 or j==item: 
                continue
            similarity = simMeas(xformedItems[item,:].T, xformedItems[j,:].T)
            print ('the %d and %d similarity is: %f' % (item, j, similarity))
            #相似度的累加
            simTotal += similarity
            #相似度和当前用户评分的乘积
            ratSimTotal += similarity * userRating
        if simTotal == 0: 
            return 0
        else: 
            return ratSimTotal/simTotal #对相似度评分的乘积进行归一化 评分值在0--5之间

    14.7小结

    SVD是一种强大的降维工具,可以利用SVD来逼近矩阵并从中提取重要特征,保留矩阵80%-90%的能量,得到重要的特征去掉噪音。推荐系统为SVD的一个成功的应用,协同过滤则是一种基于用户喜好或行为数据的推荐的实现方法。协同过滤的核心是相似度计算方法。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    SSM框架--详细整合教程
    ssh--整合注意事项
    SSH--三大框架整合原理
    springMVC的流程
    java框架问题整理
    集合的体系
    java异常机制
    java知识点
    Java编程思想【Thinking in java】
    实验三 指令实验(一)
  • 原文地址:https://www.cnblogs.com/Aaron12/p/9079521.html
Copyright © 2020-2023  润新知