应用:能够快速实现的协同推荐

对于中小型的公司,用户的数据量及公司产品的个数都是较小规模的,需要提供给用户的推荐系统实现的重心也从人性化变成了实现成本,协同推荐就是非常常见、有效且可以快速实现的方法,也是本文想介绍的。

常规的快速简单推荐系统实现方法不排除以下几种:

  • 热门推荐 所有人打开浏览的内容都一致,惊喜性会有所缺失,但是实现特别简单,稍加逻辑带给用户的体验感满足了基本需求。
  • SVD+推荐 之前也讨论过实现方法了,附上链接:SVD及扩展的矩阵分解方法
  • 基于模型推荐 这个比较偏向业务场景,可以说是经典的场景化模型,之前写过一篇基于用户特征的偏好推荐,可以参考一下:苏宁易购的用户交叉推荐
  • 协同推荐 这个也是几乎每个公司都会用的,也是非常非常常见有效的算法之一

协同推荐介绍 首先,我们先来了解一下什么叫做协同推荐。 基于用户的协同过滤推荐算法是最早诞生的,1992年提出并用于邮件过滤系统,两年后1994年被 GroupLens 用于新闻过滤。一直到2000年左右,该算法都是推荐系统领域最著名的算法。算是非常古董级别的算法之一了,但是古董归古董,它的效果以及实现的成本却奠定了它在每个公司不可取代的地位。

基于用户的协同推荐

用户u1喜欢的电影是A,B,C
用户u2喜欢的电影是A, C, E, F
用户u3喜欢的电影是B,D

假设u1、u2、u3用户喜欢的电影分布如上,基于用户的协同推荐干了这么一件事情,它根据每个用户看的电影(A、B、C、...)相似程度,来计算用户之间的相似程度,将高相似的用户看过但是目标用户还没有看过的电影推荐给目标用户。

基于商品的协同推荐

电影A被u1,u2看过
电影B被u1,u3看过
电影C被u1,u2看过
电影D被u3看过
电影E被u2看过
电影F被u2看过

假设A~F电影被用户观影的分布如上,基于商品的协同推荐干了这么一件事情,它根据电影(A、B、C、...)被不同用户观看相似程度,来计算电影之间的相似程度,根据目标用户看过的电影的高相似度的电影推荐给目标用户。

看起来以上的逻辑是非常简单的,其实本来也是非常简单的,我看了下,网上关于以上的代码实现还是比较林散和有问题的,优化了python版本的code,并详细解释了每一步,希望,对初学者有所帮助。

#time  2017-09-17
#author:shataowei
#based-item

#所要的基础包比较简单
from collections import defaultdict
import math
import time
startTime = time.time()

#读取数据的过程
#/Users/slade/Desktop/machine learning/data/recommender/u1.base
def readdata(location):
    list2item = {}  #商品对应的用户列表(1:[[1,2],[2,3]]代表商品1对应用户1的行为程度为2,商品1对应的用户2的行为程度为3)
    list2user = {}  #用户对应的商品列表(1:[[1,2],[2,3]]代表用户1对应商品1的行为程度为2,用户1对应的商品2的行为程度为3)
    f = open(location,'r')
    data = f.readlines()
    data = [x.split('\t') for x in data] 
    f.close()

    for i in data:
        if int(i[1]) not in list2item.keys():
            list2item[int(i[1])] = [[int(i[0]),int(i[2])]]
        else:
            list2item[int(i[1])].append([int(i[0]),int(i[2])])

        if int(i[0]) not in list2user.keys():
            list2user[int(i[0])] = [[int(i[1]),int(i[2])]]
        else:
            list2user[int(i[0])].append([int(i[1]),int(i[2])])
    return list2item,list2user
#list2item,list2user=readdata('/Users/slade/Desktop/machine learning/data/recommender/u1.base')

#基于item的协同推荐
#0.将用户行为程度离散化:浏览:1,搜索:2,收藏:3,加车:4,下单未支付5
#1.计算item之间的相似度:item共同观看次数/单item次数连乘
#2.寻找目标用户观看过的item相关的其他item列表
#3.计算其他item的得分:相似度*用户行为程度,求和

#0 hive操作

#1.1统计各商品出现次数
def itemcf_itemall(userlist = list2user):
    I={}
    for key in userlist:
        for item in userlist[key]:
            if item[0] not in I.keys():
                I[item[0]] = 0
            I[item[0]] = I[item[0]] + 1
    return I

#1.2计算相似矩阵
def itemcf_matrix(userlist = list2user):
    C=defaultdict(defaultdict) 
    W=defaultdict(defaultdict)   
#根据用户的已购商品来形成对应相似度矩阵 
    for key in userlist:
        for item1 in userlist[key]:
            for item2 in userlist[key]:
                if item1[0] == item2[0]:
                    continue
                if item2 not in C[item1[0]].keys():
                    C[item1[0]][item2[0]] = 0
                C[item1[0]][item2[0]] = C[item1[0]][item2[0]] + 1
#计算相似度,并填充上面对应的相似度矩阵
    for i , j in C.items():
        for z , k in j.items():
            W[i][z] = k/math.sqrt(I[i]*I[z])
#k/math.sqrt(I[i]*I[z])计算相似度,其中k为不同商品交集,sqrt(I[i]*I[z])用来压缩那些热门商品必然有高交集的问题
    return W        

#2.寻找用户观看的其他item
def recommendation(userid,k):
    score_final = defaultdict(int)
    useriditem = []
    for item,score in list2user[userid]: 
#3.计算用户的item得分,k来控制用多少个相似商品来计算最后的推荐商品        
        for i , smimilarity in sorted(W[item].items() , key = lambda x:x[1] ,reverse =True)[0:k]:
            for j in list2user[userid]:
                useriditem.append(j[0])
            if i not in useriditem:
                score_final[i] = score_final[i] + smimilarity * score
#累加每一个商品用户的评分与其它商品的相似度积的和作为衡量
#最后的10控制输出多少个推荐商品
    l = sorted(score_final.items() , key = lambda x : x[1] , reverse = True)[0:10]
    return l

#I = itemcf_itemall()
#W = itemcf_matrix()
#result_userid = recommendation(2,k=20)

endTime = time.time()
print endTime-startTime

python来实现基于item的协同推荐就完成了,核心的相似度计算可以根据实际问题进行修改,整体流程同上即可,当然数据量大的时候分布式去写也是可以的。


#time  2017-09-17
#author:shataowei
#based-user

from collections import defaultdict
import math
import time
startTime = time.time()

#读取数据
#/Users/slade/Desktop/machine learning/data/recommender/u1.base
def readdata(location):
    list2item = {}  #商品对应的用户列表
    list2user = {}  #用户对应的商品列表
    f = open(location,'r')
    data = f.readlines()
    data = [x.split('\t') for x in data] 
    f.close()

    for i in data:
        if int(i[1]) not in list2item.keys():
            list2item[int(i[1])] = [[int(i[0]),int(i[2])]]
        else:
            list2item[int(i[1])].append([int(i[0]),int(i[2])])

        if int(i[0]) not in list2user.keys():
            list2user[int(i[0])] = [[int(i[1]),int(i[2])]]
        else:
            list2user[int(i[0])].append([int(i[1]),int(i[2])])
    return list2item,list2user
#list2item,list2user=readdata('/Users/slade/Desktop/machine learning/data/recommender/u1.base')

#基于用户的协同推荐
#0.先通过hive求出近一段时间(根据业务频率定义),用户商品的对应表
#1.求出目标用户的邻居,并计算目标用户与邻居之间的相似度
#2.列出邻居所以购买的商品列表
#3.针对第二步求出了商品列表,累加所对应的用户相似度,并排序求top

#0.hive操作

#1.1求出目标用户的邻居,及对应的相关程度
def neighbour(userid,user_group = list2user,item_group = list2item):
    neighbours = {}
    for item in list2user[userid]:
        for user in list2item[item[0]]:
            if user[0] not in neighbours.keys():
                neighbours[user[0]] = 0
            neighbours[user[0]] = neighbours[user[0]] + 1
    return neighbors
#通常来说,基于item的推荐对于商品量较大的业务会构成一个巨大的商品矩阵,这时候如果用户人均购买量较低的时候,可以考虑使用基于user的推荐,它在每次计算的时候会只考虑相关用户,也就是这边的neighbours(有点支持向量基的意思),大大的降低了计算量。
#neighbours = neighbour(userid=2)

#1.2就算用户直接的相似程度,这边用的余弦相似度:点积/模的连乘
def similarity(user1,user2):
    x=0
    y=0
    z=0
    for item1 in list2user[user1]:
        for item2 in list2user[user2]:
            if item1[0]==item2[0]:
                x1 = item1[1]*item1[1]
                y1 = item2[1]*item2[1]
                z1 = item1[1]*item2[1]
                x = x + x1
                y = y + y1
                z = z + z1
#避免分母为0
    if x * y == 0 :
        simi = 0
    else:
        simi = z / math.sqrt(x * y)
    return simi
    
#1.3计算目标用户与邻居之间的相似度:
def N_neighbour(userid,neighbours,k):
    neighbour = neighbours.keys()
    M = []
    for user in neighbour:
        simi = similarity(userid,user)
        M.append((user,simi))        
    M = sorted(M,key = lambda x:x[1] ,reverse = True)[0:k]
    return M

#M = N_neighbour(userid,neighbours,k=200)

#2.列出邻居所购买过的商品并计算商品对应的推荐指数
def neighbour_item(M=M):
    R = {}
    M1 = dict(M)
    for neighbour in M1:
        for item in list2user[neighbour]:
            if item[0] not in R.keys():
                R[item[0]] = M1[neighbour] * item[1]
            else:    
                R[item[0]] = R[item[0]] + M1[neighbour] * item[1]
#根据邻居买过什么及与邻居的相似度,计算邻居买过商品的推荐度
    return R      
# R = neighbour_item(M)    

#3.排序得到推荐商品
Rank = sorted(R.items(),key=lambda x:x[1],reverse = True)[0:50]

endTime = time.time()
print endTime-startTime

python来实现基于user的协同推荐就完成了,核心的相似度计算可以根据实际问题进行修改,基于user的实现过程中,用了邻居这个概念,大大降低了计算量,我用了大概20万用户,2千的商品数,基于user的推荐实现速度大概为基于商品的10分之一,效果差异却相差不大。

协同推荐是非常简单的推荐入门算法之一,也是必须要手动快速代码实现的算法之一,希望能给大家一些帮助。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏镁客网

这款由记忆电阻设计的新型硬件计算系统,加速神经网络训练的同时还可预测下一步输出 | 黑科技

11900
来自专栏ATYUN订阅号

用生成式对抗网络来改善椅子的设计

开发者Philipp Schmitt和Steffen Weiss最近推出了一个新系统,该系统使用生成式对抗网络(GAN)来生成经典的20世纪风格椅子设计。

9610
来自专栏机器学习算法工程师

【干货收藏】不要担心没数据!史上最全数据集网站汇总

本文将为您提供一个网站/资源列表,从中你可以使用数据来完成你自己的数据项目,甚至创造你自己的产品。

1.1K50
来自专栏吉浦迅科技

用NVIDIA Jetson开发智能安全系统

JETSONAR智能安全系统旨在在有噪音的地方产生广泛的影响。而且我们身边到处都是噪音。

12620
来自专栏ATYUN订阅号

谷歌推出开源强化学习框架Dopamine

强化学习研究在过去几年取得了许多重大进展。这些进步使得智能体以超越人类的级别玩游戏,值得注意的例子包括DeepMind的DQN玩Atari游戏,AlphaGo,...

21930
来自专栏新智元

做底层 AI 框架和做上层 AI 应用,哪个对自己的学术水平(或综合能力)促进更大?

新智元获得了解浚源和微调两位用户的授权,将他们对此问题的深度解析做了整理,与读者共享。

33720
来自专栏技术翻译

学习R编程的前5门课程

越来越多的程序员正在学习R编程语言以成为一名数据科学家,这是全球最热门,最高薪的技术工作之一。

15330
来自专栏雪胖纸的玩蛇日常

5.6.7.8.高等数学-两个重要的极限定理

第 5、6、7 讲除了没有有价值的知识点,基本都是概念的介绍和科普,就不浪费时间做笔记了。

12430
来自专栏AI研习社

PyTorch 团队发表周年感言:感谢日益壮大的社群,这一年迎来六大核心突破

2017 年 1 月,Facebook 开源 PyTorch,短短一年时间,PyTorch 便发展成一线开发者争相使用的工具。这一年间,有哪些研究人员对 PyT...

30480
来自专栏新智元

【重磅】Facebook首次公开内部机器学习平台,启动AI帝国

【新智元导读】Tensorflow凭“谷歌”“开源”两个标签自2015年底发布以来便名震深度学习圈。而前年底Facebook就打造其专属ML平台FBLearne...

66880

扫码关注云+社区

领取腾讯云代金券