推荐系统——电影评分预测算法(基于用户的协同过滤、基于物品的协同过滤)

一、协同过滤算法原理

协同过滤是一种常用的推荐系统方法,它根据用户或物品之间的相似度,为目标用户推荐他们可能感兴趣的物品。协同过滤有两种主要的类型:基于用户的协同过滤(UBCF)和基于物品的协同过滤(IBCF)

1、User-Based CF(基于用户的协同过滤)

UBCF是一种方法,它找到和目标用户兴趣相似的用户集合,并推荐这些相似用户喜欢的、目标用户没有接触过的物品。1例如,如果A和B都喜欢科幻电影和书籍,而A看过并喜欢一部新的科幻电影,那么UBCF就会把这部电影推荐给B
UBCF的核心是计算用户之间的相似度,通常使用皮尔逊相关系数或余弦相似度作为相似度度量。给定用户u和用户v,令N(u)表示用户u曾经有过正反馈的物品集合,令N(v)为用户v曾经有过正反馈的物品集合。2那么,皮尔逊相关系数可以定义为:
在这里插入图片描述
其中,rui​表示用户u对物品i的评分,rˉu​表示用户u对所有物品的平均评分。
根据用户之间的相似度,可以为目标用户预测他对某个物品的评分。预测公式如下:

在这里插入图片描述
其中,r^ui​表示预测评分,S(u,K)表示和用户u最相似的K个用户集合,N(i)表示对物品i有过评分的用户集合。

2、Item-Based CF(基于物品的协同过滤)

IBCF是一种方法,它找到和目标用户喜欢的物品相似的物品,并推荐这些相似物品给目标用户。例如,如果A喜欢某系列的书籍和电影,而有一本新的奇幻小说和某系列书籍很相似,那么IBCF就会把这本小说推荐给A。
IBCF的核心是计算物品之间的相似度,通常也使用皮尔逊相关系数或余弦相似度作为相似度度量。给定物品i和物品j,令U(i)表示对物品i有过正反馈的用户集合,令U(j)为对物品j有过正反馈的用户集合。2那么,皮尔逊相关系数可以定义为:
在这里插入图片描述
其中,rui​表示用户u对物品i的评分,rˉi​表示物品i的平均评分。
根据物品之间的相似度,可以为目标用户预测他对某个物品的评分。预测公式如下:
在这里插入图片描述
其中,r^ui​表示预测评分,S(i,K)表示和物品i最相似的K个物品集合,N(u)表示用户u有过评分的物品集合。

二、 数据集下载

MovieLens Latest Datasets Small
下载ml-latest-small.zip,数据量小,便于我们单机使用和运行
下载地址:https://files.grouplens.org/datasets/movielens/ml-latest-small.zip
目标:根据m1-latest-sma11/ratings.csv(用户-电影评分数据),分别实现User-Based CF和ltem-BasedCF,并进行电影评分的预测,然后为用户实现电影推荐

三、数据集加载

加载数据集中的rating.csv,并转化为用户-电影评分矩阵

import os

import pandas as pd
import numpy as np

DATA_PATH="./datasets/ml-latest-small/ratings.csv"
CACHE_DIR="./datasets/cache/"     

def load_data(data_path):
    '''
    加载数据
    :param  data_path:数据集路径
    :param  cache_path:数据集缓存路径
    :return  用户-物品评分矩阵
    '''
    #数据集缓存地址
    cache_path=os.path.join(CACHE_DIR, "ratings_matrix_cache")
    
    print("开始加载数据集...")
    if os.path.exists(cache_path):  #判断是否存在缓存文件
        print("加载缓存中...")
        ratings_matrix=pd.read_pickle(cache_path)
        print("从缓存加载数据集完毕")
    else:
        print("加载新数据中...")
        #设置要加载的数据字段的类型
        dtype={"userId": np.int32, "movieId": np.int32, "rating": np.float32}
        #加载数据,我们只用前三列数据,分别是用户ID、电影ID、以及用户对电影的对应评分
        ratings=pd.read_csv(DATA_PATH, dtype=dtype, usecols=range(3))
        #透视表,将电影ID转换为列名称,转换成为一个User-Movie的评分矩阵
        ratings_matrix = pd.pivot_table(data=ratings, index=["userId"], columns=["movieId"], values="rating")
        #存入缓存文件
        ratings_matrix.to_pickle(cache_path)
        print("数据集加载完毕")
    return ratings_matrix
ratings_matrix=load_data(DATA_PATH)

在这里插入图片描述

四、相似度计算

计算用户或物品两两相似度

def compute_persion_similarity(ratings_matrix, based="user"):
    '''
    计算皮尔逊相关系数
    :param  ratings_matrix:用户物品评分矩阵
    :param  based: "user" or "item"
    :return: 相似度矩阵
    '''
    user_similarity_cache_path=os.path.join(CACHE_DIR, "user_similarity_cache")
    item_similarity_cache_path=os.path.join(CACHE_DIR, "item_similarity_cache")
    #基于皮尔逊相关系数计算相似度
    #用户相似度
    if based=="user":
        if os.path.exists(user_similarity_cache_path):
            print("正从缓存加载用户相似度矩阵")
            similarity=pd.read_pickle(user_similarity_cache_path)
        else:
            print("开始计算用户相似度矩阵")
            similarity=ratings_matrix.T.corr()
            similarity.to_pickle(user_similarity_cache_path)
    elif based=="item":
        if os.path.exists(item_similarity_cache_path):
            print("正从缓存加载物品相似度矩阵")
            similarity=pd.read_pickle(item_similarity_cache_path)
        else:
            print("开始计算物品相似度矩阵")
            similarity=ratings_matrix.corr()
            similarity.to_pickle(item_similarity_cache_path)
    else:
        raise Exception("Unhandled 'based' value: %s"%based)
    print("相似度矩阵计算/加载完毕")
    return similarity
user_similar=compute_persion_similarity(ratings_matrix, based="user")

在这里插入图片描述

item_similar=compute_persion_similarity(ratings_matrix, based="item")

在这里插入图片描述

五、User-Based CF 和Item-Based CF预测评分(基于用户的协同过滤和基于物品的协同过滤)

评分预测公式:
在这里插入图片描述

1、User-Based CF 算法

def predict_userBasedCF(uid, iid, ratings_matrix, user_similar):
    '''
    预测给定用户对给定物品的评分值
    :param uid:用户id
    :param iid:物品id
    :param ratings_matrix:用户-物品评分矩阵
    :param user_similar:用户两两相似度矩阵
    :return:预测的评分值
    '''
    #1.找出uid用户的相似用户
    similar_users=user_similar[uid].drop([uid]).dropna()
    #相似用户筛选规则:正相关的用户
    similar_users=similar_users.where(similar_users>0).dropna()
    if similar_users.empty is True:
        raise Exception("用户{}没有相似的用户".format(uid))
    
    #2.从uid用户的相邻用户中筛选出对iid物品有评分记录的近邻用户
    ids=set(ratings_matrix[iid].dropna().index)&set(similar_users.index)
    finally_similar_users=similar_users.loc[list(ids)]
    
    #3.结合uid用户与其近邻用户的相似度预测uid用户对iid用户的评分
    sum_up=0    #评分预测部分的分子部分的值
    sum_down=0   #评分预测部分的分母部分的值
    for sim_uid, similarity in finally_similar_users.iteritems():
        #近邻用户的评分数据
        sim_user_rated_movies=ratings_matrix.loc[sim_uid].dropna()
        #近邻用户对iid物品的评分
        sim_user_rating_for_item=sim_user_rated_movies[iid]
        #计算分子的值
        sum_up+=similarity * sim_user_rating_for_item
        #计算分母的值
        sum_down+=similarity
    
    #计算预测的评分并返回
    predict_rating=sum_up/sum_down
    print("预测出用户{0}对电影{1}的评分为:{2:.2f}".format(uid, iid, predict_rating))
    return round(predict_rating, 2)

2、Item-Based CF 算法

def predict_itemBasedCF(uid, iid, ratings_matrix, item_similar):
    '''
    预测给定用户对给定物品的评分值
    : param uid:用户ID
    : par am iid:物品ID
    : param ratings_matrix:用户-物品评分矩阵
    : param item_similar:物品两两相似度矩阵
    : return:预测的评分值
    '''
    print("开始预测用户{0}对电影{1}的评分...".format(uid, iid))
    #1.找出iid物品的相似物品
    similar_items = item_similar[iid]. drop([iid]).dropnh()#相似物品筛选规则:正相关的物品
    similar_items = similar_items.where(simi1ar_items>0).dropna()
    if similar_items.empty is True:
        raise Exception("物品{}没有相似的物品".format(iid))
    # 2.从iid物品的近邻相似物品中筛选出uid用户评分过的物品
    ids = set(ratings_matrix.loc[uid].dropna().index)&set(similar_items.index)
    finally_similar_items = similar_items.loc[list(ids)]
    # 3.结合iid物品与其相似物品的相似度和uid用户对其相似物品的评分,预测uid对iid的评分sum_up = 0#评分预测公式的分子部分的值

    sum_down = 0#评分预测公式的分母部分的值
    for sim_iid, simi1arity in finally_similar_items.iteritems() :
        #近邻物品的评分数据
        sim_item_rated_movies = ratings_matrix[sim_iid].dropna()
        # uid用户对相似物品物品的评分
        sim_item_rating_from_user = sim_item_rated_movies[uid]
        #计算分子的值
        sum_up += sim1lar1ty * s1m_1tem_rating_from_user
        #计算分母的值
        sum_down += simi1arity
                        
    #计算预测的评分值并返回
    predict_rating = sum_up/sum_down
    print("预测出用户{0}对电影{1}的评分:{2:.2f}".format(uid, iid, predict_rating))
    return round(predict_rating, 2)

3、预测全部评分

def _predict_a11(uid, item_ids, ratings_matrix, user_similar ):
    '''
    预测全部评分
    : par am uid:用户id
    : param item_ids:要预测的物品id列表
    : par am ratings_matrix:用户-物品打分矩阵: par am user_similar :用户两两间的相似度: return:生成器,逐个返回预测评分
    '''
    #逐个预测
    for iid in item_ids :
        try:
            rating = predict_userBasedCF(uid, iid,ratings_matrix, user_similar)
        except Exception as e:
            print(e)
        else:
            yield uid, iid, rating
def predict_all(uid, ratings_matrix, user_similar, filter_rule=None):
    '''
    预测全部评分,并可根据条件进行前置过滤
    : par am uid:用户ID
    : par am ratings_matrix:用户-物品打分矩阵: par am user_simi1ar :用户两两间的相似度
    : param filter_rule:过滤规则,只能是四选一,否则将抛异常: "unhot" , "rated",[ "unhot" , "rated"], None
    : return:生成器,逐个返回预测评分.
    '''
    if not filter_rule:
        item_ids = ratings_matrix.columns
    elif isinstance(filter_rule, str) and filter_rule == "unhot" :
        '''过滤非热门电影'''
        #统计每部电影的评分数
        count = ratings_matrix.count()
        #过滤出评分数高于10的电影,作为热门电影
        item_ids = count.where(count>10).dropna().index
    elif isinstance(filter_rule, str) and filter_rule == "rated":
        '''过滤用户评分过的电影'''
        #获取用户对所有电影的评分记录
        user_ratings = ratings_matrix.loc[uid]
        #评分范围是1-5,小于6的都是评分过的,除此以外的都是没有评分的_ = user_ratings<6
        item_ids = _.where(_==False). dropna().index
    elif isinstance(filter_rule, list) and set(filter_rule) == set(["unhot", "rated"]):
        '''过滤非热门和用户已经评分过的电影'''
        count = ratings_matrix.count()
        ids1 = count. where(count >10).dropna().index
        
        user_ratings = ratings_matrix.loc[uid]
        _= user_ratings < 6
        ids2 = _.where(_ == False).dropna() .index
        #取二者交集
        item_ids = set(ids1)&set(ids2)
    else:
        raise Exception("无效的过滤参数")
    yield from _predict_a11(uid, item_ids, ratings_matrix, user_similar)

六、电影评分预测

1、基于用户的协同过滤的评分预测(以用户1对所有电影的评分预测为例)

#基于用户的协同过滤的评分预测——用户1对所有电影的评分预测
#根据预测评分为指定用户进行TOP-N推荐
def top_k_rs_result(k):
    results = predict_all(1, ratings_matrix, user_similar, filter_rule=[ "unhot" ,"rated"])
    return sorted(results, key=lambda x: x[2], reverse=True)[:k]

from pprint import pprint
result = top_k_rs_result(20)
pprint(result)

在这里插入图片描述
……
在这里插入图片描述

2、基于物品的协同过滤的评分预测(以用户1对所有电影的评分预测为例)

#基于物品的协同过滤的评分预测——用户1对所有电影的评分预测
#根据预测评分为指定用户进行TOP-N推荐
def top_k_rs_result(k):
    results = predict_all(1, ratings_matrix, item_similar, filter_rule=[ "unhot" ,"rated"])
    return sorted(results, key=lambda x: x[2], reverse=True)[:k]

from pprint import pprint
result = top_k_rs_result(20)
pprint(result)

在这里插入图片描述
……
在这里插入图片描述

  • 3
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这个Python期末大作业是一个基于协同过滤算法电影推荐系统,采用了neo4j数据库来存储和查询电影数据。协同过滤算法是一种利用用户的历史行为和兴趣来进行推荐的方法,它可以根据用户的喜好和其他用户的相似度来推荐用户可能感兴趣的电影。 这个电影推荐系统的实现包括以下几个步骤:首先,通过爬虫从网上获取电影的相关信息,比如电影的名字、导演、演员、类型等等,并将这些信息存储到neo4j数据库中。然后,根据用户的历史行为和评分数据,计算用户之间的相似度,并将相似度的结果也存储到数据库中。接下来,当用户登录系统并选择了一个电影,系统会根据用户喜欢的电影类型和其他用户的相似度,从数据库中查找可能感兴趣的电影,并进行推荐。 通过采用neo4j数据库,这个电影推荐系统可以更高效地存储和查询大数据量的电影信息和用户数据。neo4j是一个图数据库,它的存储结构和图的结构相似,可以更好地支持复杂的关系型数据的存储和查询。同时,neo4j也提供了丰富的查询语言和API,方便我们实现各种复杂的查询和推荐算法。 总而言之,这个基于协同过滤算法电影推荐系统使用了neo4j数据库来存储和查询电影数据,通过分析用户的历史行为和其他用户的相似度来进行推荐,可以更好地满足用户的个性化需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值