机器学习实战---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))

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

posted @ 2020-08-02 09:25  山上有风景  阅读(282)  评论(0编辑  收藏  举报