• 机器学习:推荐算法之基于用户、基于物品和Slope One


       

    引言

       

    之前有段时间研究过推荐算法,倒不是科研需要,是觉得很想弄明白每天淘宝的时候那些猜你喜欢的东西是怎么冒出来的,还有最近很火的网易云音乐以及虾米音乐的推荐算法,这里很高兴的就是网易云音乐已经被我调教的很棒了,真开心

       

    后来了解到那些企业做的推荐算法多是混合推荐,而我只了解了基础的三种,不过相信万变不离其宗,很多基础的东西还是很重要的,所以对这三种推荐算法进行了整理,最后因为之前自己用Python参照着github上一个人的代码自己也尝试着实现了一下该推荐系统,主要是基于用户的推荐,这里贴出来供大家一起学习

       

    三种推荐算法

       

    推荐算法主要有:User-based Recommender, Item-based RecommenderSlope-One Recommender

      1. User-based Recommender

        该算法的主要思想是:与用户u最相似的用户喜欢的商品有很大可能也是用户u喜欢的商品。

    1 对于用户u每一个没有preference的商品i
    2
    对于每一个对商品ipreference的用户v
    3
    计算用户uv的相似性s//实际上无需在线计算,可以事先计算好存储起来
    4
    用户v对于商品ipreference,乘以s,加到用户u对商品i的预测preference的平均值
    5
    返回用户u的平均值最高的几个商品作为推荐商品。

       

      上述算法需要穷举每个商品i,导致计算非常非常。可以实现计算好某个用户u的所有的邻居(记为集合n),然后,再为用户u做推荐时,只需要考虑用户u的邻居的所有有preference的商品即可,而无需考虑所有商品,算法如下:

       

    1 对于每个其他的用户w
    2
    计算用户u与用户w之间的相似度s
    3
    返回用户u相似度最高的几个用户,记为用户u的邻居n
    4 //
    上述步骤可以离线完成,类似于索引
    5
    对于用户u的每个u本身没有preference,但是u的邻居n中某个用户有preference的商品i
    6
    对于每个对商品ipreference的用户u的邻居v
    7
    计算用户uv的相似度//其实无需在线计算,可以提前计算好,存储起来
    8
    用户v对于商品ipreference,乘以s,加到用户u对商品i的预测preference的平均值

       

      2. Item-based Recommender

        该算法的主要思想是:喜欢商品i的用户u,有很大可能性会喜欢和商品i很相似的其他商品

    1 对于用户u的每个没有preference的商品i
    2
    对于每个用户upreference的商品j
    3
    计算商品ij的相似度s
    4
    把用户u对商品jpreference,乘以s,加到用户u对商品ipreference的平均值
    5
    返回用户u的平均值最高的几个商品作为推荐商品

      3. Slope-One Recommender

       

    首先Slope one是一种基于项目的协同过滤算法(Item-based Recommendation)   

    首先计算每两个商品之间preference差值的平均值

    1 对于某个商品i
    2
    对于某个商品j
    3
    对于每个对商品ij都有preference的用户u
    4
    将用户u对商品i和商品jpreference的差值加到所有用户对商品i和商品j的差值的平均值当中去

        推荐

    1 对于用户u的每个没有preference的商品i
    2
    对于用户u的每个有preference的商品j
    3
    取得商品i和商品jpreference差值的平均值diff
    4
    diff加上u对商品jpreference的和加入用户u对商品ipreference的平均值当中去
    5
    返回用户u的预测preference最高的几个商品作为推荐

       

    推荐算法实战

       

    __author__ = 'Hadoop'

    # -*- coding=utf-8 -*-

       

    import math

    import sys

    from texttable import Texttable

       

       

    #

    # 使用 |A&B|/sqrt(|A || B |)计算余弦距离

    #

    #

    #

    def calcCosDistSpe(user1,user2):

    avg_x=0.0

    avg_y=0.0

    for key in user1:

    avg_x+=key[1]

    avg_x=avg_x/len(user1)

       

    for key in user2:

    avg_y+=key[1]

    avg_y=avg_y/len(user2)

       

    u1_u2=0.0

    for key1 in user1:

    for key2 in user2:

    if key1[1] > avg_x and key2[1]>avg_y and key1[0]==key2[0]:

    u1_u2+=1

    u1u2=len(user1)*len(user2)*1.0

    sx_sy=u1_u2/math.sqrt(u1u2)

    return sx_sy

       

       

    #

    # 计算余弦距离

    #

    #

    def calcCosDist(user1,user2):

    sum_x=0.0

    sum_y=0.0

    sum_xy=0.0

    for key1 in user1:

    for key2 in user2:

    if key1[0]==key2[0] :

    sum_xy+=key1[1]*key2[1]

    sum_y+=key2[1]*key2[1]

    sum_x+=key1[1]*key1[1]

       

    if sum_xy == 0.0 :

    return 0

    sx_sy=math.sqrt(sum_x*sum_y)

    return sum_xy/sx_sy

       

       

    #

    #

    # 相似余弦距离

    #

    #

    #

    def calcSimlaryCosDist(user1,user2):

    sum_x=0.0

    sum_y=0.0

    sum_xy=0.0

    avg_x=0.0

    avg_y=0.0

    for key in user1:

    avg_x+=key[1]

    avg_x=avg_x/len(user1)

       

    for key in user2:

    avg_y+=key[1]

    avg_y=avg_y/len(user2)

       

    for key1 in user1:

    for key2 in user2:

    if key1[0]==key2[0] :

    sum_xy+=(key1[1]-avg_x)*(key2[1]-avg_y)

    sum_y+=(key2[1]-avg_y)*(key2[1]-avg_y)

    sum_x+=(key1[1]-avg_x)*(key1[1]-avg_x)

       

    if sum_xy == 0.0 :

    return 0

    sx_sy=math.sqrt(sum_x*sum_y)

    return sum_xy/sx_sy

       

    #

    # 读取文件

    #

    #

    def readFile(file_name):

    contents_lines=[]

    f=open(file_name,"r")

    contents_lines=f.readlines()

    f.close()

    return contents_lines

       

       

       

    #

    # 解压rating信息,格式:用户id 硬盘id 用户rating 时间

    # 输入:数据集合 u.data

    # 输出:已经解压的排名信息 user item rating

    #

    def getRatingInformation(ratings):

    rates=[]

    for line in ratings:

    rate=line.split(" ")

    rates.append([int(rate[0]),int(rate[1]),int(rate[2])])

    #print(rates)

    return rates

       

       

    #

    # 生成用户评分的数据结构

    #

    # 输入:所以数据 [[2,1,5],[2,4,2]...]

    # 输出:1.用户打分字典 2.电影字典

    # 使用字典,key是用户id,value是用户对电影的评价,

    # rate_dic[2]=[(1,5),(4,2)].... 表示用户2对电影1的评分是5,对电影4的评分是2

    #

    def createUserRankDic(rates):

    user_rate_dic={}

    item_to_user={}

    for i in rates:

    user_rank=(i[1],i[2])

    if i[0] in user_rate_dic:

    user_rate_dic[i[0]].append(user_rank)

    else:

    user_rate_dic[i[0]]=[user_rank]

       

    if i[1] in item_to_user:

    item_to_user[i[1]].append(i[0])

    else:

    item_to_user[i[1]]=[i[0]]

       

    return user_rate_dic,item_to_user

       

       

    #

    # 计算与指定用户最相近的邻居

    # 输入:指定用户ID,所以用户数据,所以物品数据

    # 输出:与指定用户最相邻的邻居列表

    #

    def calcNearestNeighbor(userid,users_dic,item_dic):

    neighbors=[]

    #neighbors.append(userid)

    for item in users_dic[userid]:

    for neighbor in item_dic[item[0]]:

    if neighbor != userid and neighbor not in neighbors:

    neighbors.append(neighbor)

       

    neighbors_dist=[]

    for neighbor in neighbors:

    dist=calcSimlaryCosDist(users_dic[userid],users_dic[neighbor]) #calcSimlaryCosDist calcCosDist calcCosDistSpe

    neighbors_dist.append([dist,neighbor])

    neighbors_dist.sort(reverse=True)

    #print neighbors_dist

    return neighbors_dist

       

       

    #

    # 使用UserFC进行推荐

    # 输入:用户文件名,用户ID,邻居数量

    # 输出:推荐的电影ID,输入用户的电影列表,电影对应用户的反序表,邻居列表

    #

    def recommendByUserFC(file_name,userid,k=5):

       

    #读取文件数据

    test_contents=readFile(file_name)

       

    #文件数据格式化成二维数组 List[[用户id,电影id,电影评分]...]

    test_rates=getRatingInformation(test_contents)

       

    #格式化成字典数据

    # 1.用户字典:dic[用户id]=[(电影id,电影评分)...]

    # 2.电影字典:dic[电影id]=[用户id1,用户id2...]

    test_dic,test_item_to_user=createUserRankDic(test_rates)

       

    #寻找邻居

    neighbors=calcNearestNeighbor(userid,test_dic,test_item_to_user)[:k]

       

    recommend_dic={}

    for neighbor in neighbors:

    neighbor_user_id=neighbor[1]

    movies=test_dic[neighbor_user_id]

    for movie in movies:

    #print movie

    if movie[0] not in recommend_dic:

    recommend_dic[movie[0]]=neighbor[0]

    else:

    recommend_dic[movie[0]]+=neighbor[0]

    #print len(recommend_dic)

       

    #建立推荐列表

    recommend_list=[]

    for key in recommend_dic:

    #print key

    recommend_list.append([recommend_dic[key],key])

       

       

    recommend_list.sort(reverse=True)

    #print recommend_list

    user_movies = [ i[0] for i in test_dic[userid]]

       

    return [i[1] for i in recommend_list],user_movies,test_item_to_user,neighbors

       

       

       

    #

    # 获取电影的列表

    #

       

    def getMoviesList(file_name):

    #print sys.getdefaultencoding()

    movies_contents=readFile(file_name)

    movies_info={}

    for movie in movies_contents:

    movie_info=movie.split("|")

    movies_info[int(movie_info[0])]=movie_info[1:]

    return movies_info

       

       

       

    #主程序

    #输入 : 测试数据集合

    if __name__ == '__main__':

    reload(sys)

    sys.setdefaultencoding('utf-8')

    movies=getMoviesList("T:/work/reco/ml-100k/u.item")

    recommend_list,user_movie,items_movie,neighbors=recommendByUserFC("T:/work/reco/ml-100k/u.data",179,80)

    neighbors_id=[ i[1] for i in neighbors]

    table = Texttable()

    table.set_deco(Texttable.HEADER)

    table.set_cols_dtype(['t', # text

    't', # float (decimal)

    't']) # automatic

    table.set_cols_align(["l", "l", "l"])

    rows=[]

    rows.append([u"movie name",u"release", u"from userid"])

    for movie_id in recommend_list[:20]:

    from_user=[]

    for user_id in items_movie[movie_id]:

    if user_id in neighbors_id:

    from_user.append(user_id)

    rows.append([movies[movie_id][0],movies[movie_id][2],""])

    table.add_rows(rows)

    print table.draw()

  • 相关阅读:
    appfuse的一些资源
    实战: SOLR的分布式部署(复制)CollectionDistribute 快照分发 (精简版)
    在SOLR环境变量的配置 过程中,遇到的 A pseudo attribute name is expected 异常
    Solr应用开发——Solr home目录结构简介1
    升级 Solr 1.4 后性能有所提升
    Solr 删除数据的几种方式
    如何使SOLR系统自动AUTO COMMIT
    Solr应用开发——Solr home目录结构简介2
    升级到 solr 1.4 的注意事项
    SOLR环境变量的配置
  • 原文地址:https://www.cnblogs.com/keedor/p/4464020.html
Copyright © 2020-2023  润新知