SVD

《机器学习实战》一书中的svd部分可以用来辅助阅读

有位网友的《机器学习实战》算法理解,还不错

https://github.com/haidawyl/MLinAction

 

github文字介绍地址:

https://github.com/apachecn/AiLearning/blob/dev/blog/ml/14.%E5%88%A9%E7%94%A8SVD%E7%AE%80%E5%8C%96%E6%95%B0%E6%8D%AE.md#%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F-%E5%8E%9F%E7%90%86

github完整代码地址:

https://github.com/apachecn/AiLearning/blob/master/src/py3.x/ml/14.SVD/svdRecommend.py

数据附件:

https://github.com/apachecn/AiLearning/blob/master/db/14.SVD/0_5.txt

 

SVD相关知识:

https://www.cnblogs.com/pinard/p/6251584.html

https://www.cnblogs.com/lzllovesyl/p/5243370.html

 

函数解析:

概述:

数据是一个m x n的矩阵、行代表的是样本即用户、列代表的是维度即菜品、值就为用户的打分,现在想要给user推荐他没有打过分的菜品,基于菜品之间的相似性来推荐,基于的是物品的相似性、即利用user已打过分的菜品来计算未打过分的菜品的分数,计算的时候需要基于其他用户对于该菜品的打分情况(对这二者都打分才能得到两个菜品的向量)然后计算二者的相似性,然后得到user对于该菜品的评分

# recommend()函数,就是推荐引擎,它默认调用standEst()函数,产生了最高的N个推荐结果。
# 如果不指定N的大小,则默认值为3。该函数另外的参数还包括相似度计算方法和估计方法
def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):
    """svdEst( )
    Args:
        dataMat         训练数据集
        user            用户编号
        simMeas         相似度计算方法
        estMethod       使用的推荐算法
    Returns:
        返回最终 N 个推荐结果
    """
    # 寻找未评级的物品
    # 对给定的用户建立一个未评分的物品列表
    unratedItems = nonzero(dataMat[user, :].A == 0)[1]
    print(unratedItems)
    # 如果不存在未评分物品,那么就退出函数
    if len(unratedItems) == 0:
        return 'you rated everything'
    # 物品的编号和评分值
    itemScores = []
    # 在未评分物品上进行循环
    for item in unratedItems:
        # 获取 item 该物品的评分
        estimatedScore = estMethod(dataMat, user, simMeas, item)
        print('estimatedScore: ', estimatedScore)
        itemScores.append((item, estimatedScore))
    # 按照评分得分 进行逆排序,获取前N个未评级物品进行推荐
    return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[: N]
# 基于物品相似度的推荐引擎
def standEst(dataMat, user, simMeas, item):
    """standEst(计算某用户未评分物品中,以对该物品和其他物品评分的用户的物品相似度,然后进行综合评分)

    Args:
        dataMat         训练数据集
        user            用户编号
        simMeas         相似度计算方法
        item            未评分的物品编号
    Returns:
        ratSimTotal/simTotal     评分(0~5之间的值)
    """
    # 得到数据集中的物品数目、即维度
    n = shape(dataMat)[1]
    # 初始化两个评分值
    simTotal = 0.0
    ratSimTotal = 0.0
    # 遍历行中的每个物品(对用户评过分的物品进行遍历,并将它与其他物品进行比较)
    for j in range(n):
        #item确定的情况下,取出用户user对于j菜品的评分
        userRating = dataMat[user, j]
        # 如果某个物品的评分值为0,则跳过这个物品
        if userRating == 0:
            continue
        # 寻找两个用户都评级的物品,这里是要用已打分的菜品去找出相似用户(即某用户既对item菜品打分又对j菜品打分)
        # 前提是user用户对j菜品打过分,不然即使算出了相似度也得不到user对item的分数
        # 变量 overLap 给出的是两个物品当中已经被评分的那个元素的索引ID
        # logical_and 计算x1和x2元素的真值。
        overLap = nonzero(logical_and(dataMat[:, item].A > 0, dataMat[:, j].A > 0))[0]
        # 如果相似度为0,则两着没有任何重合元素,终止本次循环,即没有用户同时对item和j菜品都打过分
        if len(overLap) == 0:
            similarity = 0
        # 如果存在重合的物品,则基于这些重合物重新计算相似度。即有用户同时对item和j菜品都打过分
        else:
        # 计算这两个向量的相似度,即item菜品和j菜品的相似度
            similarity = simMeas(dataMat[overLap, item], dataMat[overLap, j])
        # print 'the %d and %d similarity is : %f'(iten,j,similarity)
        # 相似度会不断累加,每次计算时还考虑相似度和当前用户评分的乘积
        # similarity  用户相似度,   userRating 用户评分
        simTotal += similarity
        ratSimTotal += similarity * userRating
    if simTotal == 0:
        return 0
    # 通过除以所有的评分总和,对上述相似度评分的乘积进行归一化,使得最后评分在0~5之间,这些评分用来对预测值进行排序
    else:
        #返回item最后的得分
        return ratSimTotal/simTotal

svd给数据降维,取出数据中最重要的特征来进行计算、加快计算速度、较少噪音带来的影响

# 基于SVD的评分估计
# 在recommend() 中,这个函数用于替换对standEst()的调用,该函数对给定用户给定物品构建了一个评分估计值
def svdEst(dataMat, user, simMeas, item):
    """svdEst( )
    Args:
        dataMat         训练数据集
        user            用户编号
        simMeas         相似度计算方法
        item            未评分的物品编号
    Returns:
        ratSimTotal/simTotal     评分(0~5之间的值)
    """
    # 物品数目
    n = shape(dataMat)[1]
    # 对数据集进行SVD分解
    simTotal = 0.0
    ratSimTotal = 0.0
    # 奇异值分解
    # 在SVD分解之后,我们只利用包含了90%能量值的奇异值,这些奇异值会以NumPy数组的形式得以保存
    U, Sigma, VT = la.svd(dataMat)

    # # 分析 Sigma 的长度取值
    # analyse_data(Sigma, 20)

    # dataMat: mxn, 行对应用户, 列对应物品
    # dataMat.T: nxm, dataMat转置之后, 行对应物品, 列对应用户
    # U: mxm, 则U[:, :4]: mx4
    # Sig4: 4x4
    # U矩阵会将物品映射到低维空间中, VT矩阵会将用户映射到低维空间中
    # 计算得到的矩阵, nx4, 行仍对应物品, 列仍对应用户, 物品总数未变, 减少的是用户
    # 如果要进行矩阵运算,就必须要用这些奇异值构建出一个对角矩阵
    # 这里经过计算取前4个奇异值就能获取90%的能量
    Sig4 = mat(eye(4) * Sigma[: 4])

    # 利用U矩阵将物品转换到低维空间中,构建转换后的物品(物品+4个主要的特征)、即减少了用户
    xformedItems = dataMat.T * U[:, :4] * Sig4.I
    print('dataMat', shape(dataMat))
    print('U[:, :4]', shape(U[:, :4]))
    print('Sig4.I', shape(Sig4.I))
    print('VT[:4, :]', shape(VT[:4, :]))
    print('xformedItems', shape(xformedItems))

    # 对于给定的用户,for循环在用户对应行的元素上进行遍历
    # 这和standEst()函数中的for循环的目的一样,只不过这里的相似度计算时在低维空间下进行的。
    for j in range(n):
        userRating = dataMat[user, j]
        if userRating == 0 or j == item:
            continue

        # 在低维空间下, 使用指定的相似度计算方法计算这2个物品的相似度(基于用户评分的相似度计算方法)
        # 矩阵xformedItems的行对应物品, 列对应用户, 相似度计算方法的参数为列向量, 所以
        # xformedItems[item, :].T 是物品item的列向量,
        # xformedItems[j, :].T 是物品j的列向量.
        # 相似度的计算方法也会作为一个参数传递给该函数
        similarity = simMeas(xformedItems[item, :].T, xformedItems[j, :].T)
        # for 循环中加入了一条print语句,以便了解相似度计算的进展情况。如果觉得累赘,可以去掉
        print('the %d and %d similarity is: %f' % (item, j, similarity))
        # 物品item和物品j的相似度不断累加求和
        simTotal += similarity
        # 物品item和物品j的相似度乘以用户对物品j的评分, 再做累加
        ratSimTotal += similarity * userRating
    if simTotal == 0:
        return 0
    else:
        # 计算估计评分
        return ratSimTotal/simTotal

xformedItems = dataMat.T * U[:, :4] * Sig4.I

这一句我无法理解、为啥要这样转换呢?VT直接左乘不行么?后面为啥又要乘以Sig4.I?

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值