利用SVD分解做协同过滤推荐

看了机器学习实战的SVD分解一章,自己用矩阵做了一个SVD分解的功能,速度很快,跟大家分享下,代码如下:

# coding=utf8
import sys
import numpy as np
import os

reload(sys)
sys.setdefaultencoding('utf-8')
os.chdir(r'D:\Study\ML\MLAction\Ch14')

#相似度计算函数
def cos_sim(x,y):
    """
    根据余弦计算x,y的相似度
    :param x: 1*n array
    :param y: 1*n array
    :return:
    """
    similarity=0.5+0.5*np.dot(x,y)/(np.sqrt(np.dot(x,x))*np.sqrt(np.dot(y,y)))
    return similarity

#协同过滤推荐算法
#注意:1.相似度计算结果规范到0-1之间,2.计算最终得分要加权计算,不是相似度和评分乘积
#3.np.sum如果不指定维度,会统计所有和
def recommend(user_index,grade_arr,topk=10):
    """
    基于商品相似度的协同推荐算法
    :param user_index:
    :param grade_arr: 用户对商品的评分矩阵
    :return: 推荐的top k商品
    """
    if user_index<0:
        raise Exception("user_index must more than 0")
    if grade_arr is None or grade_arr.shape[0]==0:
        raise Exception("there is no data in grade_arr")
    #利用svd降维去噪
    u,sigma,vt=np.linalg.svd(grade_arr)
    sigma_sum=np.sum(sigma)
    sigma_partsum=0
    # for k in range(len(sigma)):
    #     sigma_partsum+=sigma[k]
    #     if sigma_partsum*1.0/sigma_sum>0.9:
    #         break
    sigma=np.eye(4)*sigma[:4]
    product_arr=grade_arr.T.dot(u[:,:4]).dot(np.linalg.inv(sigma))

    #计算商品相似度
    product_dot=product_arr.dot(product_arr.T)
    prodcut_model=np.mat(np.sqrt(np.sum(product_arr**2,axis=1)))
    product_models=prodcut_model.T*prodcut_model
    prodcut_sim=product_dot/product_models.A*0.5+0.5#使求的相似度值在0-1范围内
    # print(prodcut_sim)

    #找出用户没有评分的商品
    nograde=grade_arr[user_index]==0
    if nograde.shape[0]==0:
        raise Exception("you rate everything")
    nograde_index=np.nonzero(nograde)[0]
    grade_index=np.nonzero(~nograde)[0]

    #计算无评分商品的推荐得分
    sel_prodcut_sim= prodcut_sim[nograde_index][:,grade_index]
    user_product_grade=grade_arr[user_index][grade_index]
    score=sel_prodcut_sim.dot(user_product_grade)/np.sum(sel_prodcut_sim[:,],axis=1)

    #推荐top k
    sort_index=np.argsort(-score)
    topk_index=sort_index[:topk]
    return zip(*(nograde_index[topk_index],score[topk_index]))

def loadExData():
    return [[0, 0, 0, 2, 2],
            [0, 0, 0, 3, 3],
            [0, 0, 0, 1, 1],
            [1, 1, 1, 0, 0],
            [2, 2, 2, 0, 0],
            [5, 5, 5, 0, 0],
            [1, 1, 1, 0, 0]]

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]]

grad_arr=np.array(loadExData2())
result=recommend(1,grad_arr,3)
print(result)



  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值