• 机器学习实战---SVD简化数据


    一:参考资料

    (一)机器学习实战

    (二)如何让奇异值分解(SVD)变得不“奇异”?(特别好理解SVD)

    http://redstonewill.com/1529/

    https://blog.csdn.net/yusisc/article/details/82216800

    (三)奇异值分解(SVD)原理与在降维中的应用

    (四)深入理解PCA与SVD的关系

    二:推荐系统协调过滤算法

    (一)文章回顾

    https://www.cnblogs.com/ssyfj/p/12951542.html

    (二)另一种实现方法

    import numpy as np
    
    #一:相似度计算,传入的都是列向量
    def eulidSim(inA,inB):  #相似度=1/(1+距离) 物品对越相似,它们的相似度值就越大。
        return 1/(1+np.linalg.norm(inA-inB))    #距离按照第二范式计算
    
    def pearsSim(inA,inB):  #皮尔逊相关系数 相似度=0.5+0.5*corrcoef
        if len(inA) < 3:    #为啥小于3???书上说小于3的两个向量完全相关(不应该是2吗?)
            return 1
        return 0.5 + 0.5*np.corrcoef(inA,inB,rowvar=0)[0][1]
    
    def cosSim(inA,inB):    #余弦相似度
        num = inA.T@inB
        denom = np.linalg.norm(inA)*np.linalg.norm(inB)
        return 0.5+0.5*(num/denom)
    
    #二:数据加载
    def loadDataSet():
        return np.array([[4,4,0,2,3],
                         [4,0,0,3,3],
                         [4,0,0,1,1],
                         [1,1,1,2,0],
                         [2,2,2,0,0],
                         [1,1,1,0,0],
                         [5,5,5,0,0]])
    
    #三:实现基于物品相似度的推荐引擎
    #1.根据某个用户编号和其对应的多个未评价的物品中的一个,进行估计评分值(是直接对该物品评分)
    def standEst(dataArr,userId,itemId,simMeas):
        n = dataArr.shape[1]    #所有物品数目
        simTotal = 0    #计算整体相似度
        ratSimTotal = 0 #计算相似度作为权重,对现有另一个用户评分加权后的评分
        #循环所有物品
        for j in range(n):
            userScore = dataArr[userId,j]   #获取本用户对物品的评分
            if userScore == 0:
                continue    #如果用户没有评分,则不进行相似度评价
    
            #找到一个物品,同我们指定的物品。都同时给予了评价的用户(有无重合,有重合,才可以进行相似度计算)
            overLap = np.where(np.logical_and(dataArr[:,itemId],dataArr[:,j]))[0]   #获取用户索引
    
            if len(overLap) == 0:   #无相似度
                similarity = 0
            else:
                similarity = simMeas(dataArr[overLap,itemId],dataArr[overLap,j])   #计算重合部分的相似度
            simTotal += similarity
            ratSimTotal += similarity*userScore
    
        #进行返回
        if simTotal == 0:
            return 0    #如果没有找到相似物品,返回评分0即可
        else:
            return ratSimTotal/simTotal #通过除以所有的相似度和,对上述相似度评分的乘积进行归一化,使得最后评分在0~5之间,这些评分用来对预测值进行排序
    
    #2.使用上面估分,进行辅助。推荐物品
    def recommend(dataArr,userId,N=3,simMeas=cosSim,estMethod=standEst):    #N是想要获取的最符合的物品(估计评分最高)
        #操作该用户没有评价的物品
        unratedItems = np.where(dataArr[userId] == 0)[0]
    
        if len(unratedItems) == 0:  #全部评价了
            print("you rated everything")
            return
    
        #获取全部未评价的物品评分值
        itemsScore = []
    
        for i in unratedItems:
            estimatedScore = estMethod(dataArr,userId,i,simMeas)
            itemsScore.append((i,estimatedScore))   #传入物品编号和评分
    
        #返回我们想要的物品数
        return sorted(itemsScore,key=lambda p:p[1],reverse=True)[:N]    #获取前N个最高评分的物品
    
    data = loadDataSet()
    print(recommend(data,2))
    

    三:使用SVD提高推荐效果

    (一)不变代码

    import numpy as np
    
    #一:相似度计算,传入的都是列向量
    def eulidSim(inA,inB):  #相似度=1/(1+距离) 物品对越相似,它们的相似度值就越大。
        return 1/(1+np.linalg.norm(inA-inB))    #距离按照第二范式计算
    
    def pearsSim(inA,inB):  #皮尔逊相关系数 相似度=0.5+0.5*corrcoef
        if len(inA) < 3:    #为啥小于3???书上说小于3的两个向量完全相关(不应该是2吗?)
            return 1
        return 0.5 + 0.5*np.corrcoef(inA,inB,rowvar=0)[0][1]
    
    def cosSim(inA,inB):    #余弦相似度
        num = float(inA.T@inB)
        denom = np.linalg.norm(inA)*np.linalg.norm(inB)
        return 0.5+0.5*(num/denom)
    
    
    #二:数据加载
    def loadDataSet():
        return np.array([[4,4,0,2,3],
                         [4,0,0,3,3],
                         [4,0,0,1,1],
                         [1,1,1,2,0],
                         [2,2,2,0,0],
                         [1,1,1,0,0],
                         [5,5,5,0,0]])
    
    #三:实现基于物品相似度的推荐引擎
    #1.根据某个用户编号和其对应的多个未评价的物品中的一个,进行估计评分值(是直接对该物品评分)
    def standEst(dataArr,userId,itemId,simMeas):
        n = dataArr.shape[1]    #所有物品数目
        simTotal = 0    #计算整体相似度
        ratSimTotal = 0 #计算相似度作为权重,对现有另一个用户评分加权后的评分
        #循环所有物品
        for j in range(n):
            userScore = dataArr[userId,j]   #获取本用户对物品的评分
            if userScore == 0:
                continue    #如果用户没有评分,则不进行相似度评价
    
            #找到一个物品,同我们指定的物品。都同时给予了评价的用户(有无重合,有重合,才可以进行相似度计算)
            overLap = np.where(np.logical_and(dataArr[:,itemId],dataArr[:,j]))[0]   #获取用户索引
    
            if len(overLap) == 0:   #无相似度
                similarity = 0
            else:
                similarity = simMeas(dataArr[overLap,itemId],dataArr[overLap,j])   #计算重合部分的相似度
            simTotal += similarity
            ratSimTotal += similarity*userScore
    
        #进行返回
        if simTotal == 0:
            return 0    #如果没有找到相似物品,返回评分0即可
        else:
            return ratSimTotal/simTotal #通过除以所有的相似度和,对上述相似度评分的乘积进行归一化,使得最后评分在0~5之间,这些评分用来对预测值进行排序
    
    #2.使用上面估分,进行辅助。推荐物品
    def recommend(dataArr,userId,N=3,simMeas=cosSim,estMethod=standEst):    #N是想要获取的最符合的物品(估计评分最高)
        #操作该用户没有评价的物品
        unratedItems = np.where(dataArr[userId] == 0)[0]
    
        if len(unratedItems) == 0:  #全部评价了
            print("you rated everything")
            return
    
        #获取全部未评价的物品评分值
        itemsScore = []
    
        for i in unratedItems:
            estimatedScore = estMethod(dataArr,userId,i,simMeas)
            itemsScore.append((i,estimatedScore))   #传入物品编号和评分
    
        #返回我们想要的物品数
        return sorted(itemsScore,key=lambda p:p[1],reverse=True)[:N]    #获取前N个最高评分的物品

    (二)SVD代码实现

    def loadExData2():
        return  np.array([[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]])
    
    def svdEst(dataArr,userId,itemId,simMeas):  #https://zhuanlan.zhihu.com/p/58064462
        n = dataArr.shape[1]    #获取全部物品数量
        simTotal = 0
        ratSimTotal = 0
        #使用SVD进行分解
        #注意:python返回的sigma只有数值,不是矩阵
        U,Sigma,VT = np.linalg.svd(dataArr) #注意行为用户,列为物品
        #建立对角矩阵
        Sig4 = np.eye(4)*Sigma[:4]  #建立对角矩阵 注意:我们选取4个最大特征值,保持这四个特征值的总能量>90%全部特征总能量,使用前,先测试
        #建立低维空间,使用U特征矩阵,降低冗余样本
        xformedItems = dataArr.T@U[:,:4]@np.linalg.inv(Sig4)    #现在是n,4但是后面进行转置,变为4,n达到降低冗余
        for j in range(n):
            userRating = dataArr[userId,j]  #获取评分
            if userRating == 0 or j == itemId:
                continue    #用户没有评分,或者物品就是本身,不处理
            similarity = simMeas(np.array([xformedItems[itemId,:]]).T,np.array([xformedItems[j,:]]).T)
            print(np.array([xformedItems[itemId,:]]).T, np.array([xformedItems[j,:]]).T)
            print('the %d and %d similarity is: %f' % (itemId, j, similarity))
            #[-0.01591788 -0.39205093  0.55707516  0.04356321] [-0.0552444  -0.52034959 -0.36330956 -0.19023805]
            simTotal += similarity
            ratSimTotal += similarity*userRating #加权评分
        if simTotal == 0:
            return 0
        else:
            return ratSimTotal/simTotal
    
    data = loadExData2()
    print(recommend(data,1,estMethod=svdEst))

    四:机器学习就先这样吧,以后在使用统计学习方法回顾.....

  • 相关阅读:
    2017.11.22 mysql数据库实现关联表更新sql语句
    2017.11.21 基于JSP+Servlet+JavaBean实现复数运算(二)
    2017.11.20 基于JSP+Servlet+JavaBean实现复数运算(一)
    2017.11.19 如何设计好的数据库
    [专项]链表面试题汇总
    java 的三种代理模式
    我们为什么要使用AOP?
    十张图让你了解阿里公司架构设计的发展变化史(yet)
    Java程序员从阿里、京东、美团面试回来,这些面试题你会吗?(yet)
    [专项]jvm面试题(yet)
  • 原文地址:https://www.cnblogs.com/ssyfj/p/13417726.html
Copyright © 2020-2023  润新知