基于surprise的两种推荐算法的实现

surprise是scikit系列中的一个,简单易用,同时支持多种推荐算法:基础算法、协同过滤算法、矩阵分解(隐语义模型)。
surprise文档: https://surprise.readthedocs.io/en/stable/getting_started.html
数据集:movielens-100k数据集
数据集下载地址:http://files.grouplens.org/datasets/movielens

1.基于邻域的方法(协同过滤)(collaborative filtering): user-based, item-based。

import os, io, collections
import pandas as pd
from surprise import Dataset, KNNBaseline, SVD, accuracy, Reader
from surprise.model_selection import cross_validate, train_test_split

# 协同过滤方法

# 载入movielens-100k数据集,一个经典的公开推荐系统数据集,有选项提示是否下载。
data = Dataset.load_builtin('ml-100k')

# 或载入本地数据集# 数据集路径path to dataset filefile_path = os.path.expanduser('~/.surprise_data/ml-100k/ml-100k/u.data')# 使用Reader指定文本格式,参数line_format指定特征(列名),参数sep指定分隔符reader = Reader(line_format='user item rating timestamp', sep='\t')# 加载数据集data = Dataset.load_from_file(file_path, reader=reader)

data_df = pd.read_csv(file_path, sep='\t', header=None, names=['user','item','rating','timestamp'])
item_df = pd.read_csv(os.path.expanduser('~/.surprise_data/ml-100k/ml-100k/u.item'), sep='|', encoding='ISO-8859-1', header=None, names=['mid','mtitle']+[x for x in range(22)])
# 每列都转换为字符串类型
data_df = data_df.astype(str)
item_df = item_df.astype(str)
# 电影id到电影标题的映射
item_dict = { item_df.loc[x, 'mid']: item_df.loc[x, 'mtitle'] for x in range(len(item_df)) }
1.1基于用户的协同过滤算法:
# 使用协同过滤算法时的相似性度量配置
# user-based
user_based_sim_option = {'name': 'pearson_baseline', 'user_based': True}
# item-based
item_based_sim_option = {'name': 'pearson_baseline', 'user_based': False}

# 为用户推荐n部电影,基于用户的协同过滤算法,先获取10个相似度最高的用户,把这些用户评分高的电影加入推荐列表。
def get_similar_users_recommendations(uid, n=10):
    # 获取训练集,这里取数据集全部数据
    trainset = data.build_full_trainset()
    # 考虑基线评级的协同过滤算法
    algo = KNNBaseline(sim_option = user_based_sim_option)
    # 拟合训练集
    algo.fit(trainset)
    # 将原始id转换为内部id
    inner_id = algo.trainset.to_inner_uid(uid)
    # 使用get_neighbors方法得到10个最相似的用户
    neighbors = algo.get_neighbors(inner_id, k=10)
    neighbors_uid = ( algo.trainset.to_raw_uid(x) for x in neighbors )
    recommendations = set()
    #把评分为5的电影加入推荐列表
    for user in neighbors_uid:
        if len(recommendations) > n:
            break
        item = data_df[data_df['user']==user]
        item = item[item['rating']=='5']['item']
        for i in item:
            recommendations.add(item_dict[i])
    print('\nrecommendations for user %s:')
    for i, j in enumerate(list(recommendations)):
        if i >= 10:
            break
        print(j)

测试,给id为1的用户推荐10部电影:

get_similar_users_recommendations('1', 10)

输出结果如下:


基于surprise的两种推荐算法的实现_第1张图片
推荐列表
1.2基于物品的协同过滤算法:
# 与某电影相似度最高的n部电影,基于物品的协同过滤算法。
def get_similar_items(iid, n = 10):
    trainset = data.build_full_trainset()
    algo = KNNBaseline(sim_option = item_based_sim_option)
    algo.fit(trainset)
    inner_id = algo.trainset.to_inner_iid(iid)
    # 使用get_neighbors方法得到n个最相似的电影
    neighbors = algo.get_neighbors(inner_id, k=n)
    neighbors_iid = ( algo.trainset.to_raw_iid(x) for x in neighbors )
    recommendations = [ item_dict[x] for x in neighbors_iid ]
    print('\nten movies most similar to the %s:' % item_dict[iid])
    for i in recommendations:
        print(i)

给id为2的电影(GoldenEye (1995))相似度最高的十部电影:

get_similar_items('2')

推荐结果如下:


基于surprise的两种推荐算法的实现_第2张图片
推荐列表

2.基于隐语义的方法(矩阵分解):SVD。

# SVD算法,预测所有用户的电影的评分,把每个用户评分最高的n部电影加入字典。
def get_recommendations_dict(n = 10):
    trainset = data.build_full_trainset()
    # 测试集,所有未评分的值
    testset = trainset.build_anti_testset()
    # 使用SVD算法
    algo = SVD()
    algo.fit(trainset)
    # 预测
    predictions = algo.test(testset)
    # 均方根误差
    print("RMSE: %s" % accuracy.rmse(predictions))

    # 字典保存每个用户评分最高的十部电影
    user_recommendations = collections.defaultdict(list)
    for uid, iid, r_ui, est, details in predictions:
        user_recommendations[uid].append((iid, est))
    for uid, user_ratings in user_recommendations.items():
        user_ratings.sort(key = lambda x: x[1], reverse=True)
        user_recommendations[uid] = user_ratings[:n]
    return user_recommendations

# 获取每个用户评分最高的10部电影
user_recommendations = get_recommendations_dict(10)

# 显示为用户推荐的电影名
def rec_for_user(uid):
    print("recommendations for user %s:" % uid)
    #[ item_dict[x[0]] for x in user_recommendations[uid] ]
    for i in user_recommendations[uid]:
        print(item_dict[i[0]])

给id为1的用户推荐10部电影:

rec_for_user('1') 

输出结果如下:


基于surprise的两种推荐算法的实现_第3张图片
在这里插入图片描述

你可能感兴趣的:(基于surprise的两种推荐算法的实现)