机器学习(六)推荐引擎之构建电影推荐引擎

构建电影推荐引擎

简介

推荐引擎是一个能预测用户兴趣点的模型。将推荐引擎应用于电影语境时,便成了一个电影 推荐引擎。我们通过预测当前用户可能会喜欢的内容,将相应的东西从数据库中筛选出来,这样的推荐引擎可以有助于将用户和数据集中的合适内容连接起来。
为什么推荐引擎这么重要?设想 你有一个很庞大的商品目录,而用户可能或者不可能查找所有的相关内容。通过推荐合适的内容, 可以增加用户消费。
推荐引擎通常用协同过滤(collaborative filtering)或基于内容的过滤(content-based filtering)来产生一组推荐。两种过滤方法的不同之处在于挖掘推荐的方式。协同过滤从当前用户过去的行 为和其他用户对当前用户的评分来构建模型,然后使用这个模型来预测这个用户可能感兴趣的内容;而基于内容的过滤用商品本身的特征来给用户推荐更多的商品,商品间的相似度是模型主要的关注点。本章将重点介绍协同过滤。

主要步骤

编写一个程序用来计算欧式距离分数

#  创建一个Python文件,导入以下程序包:
import json
import numpy as np


# 计算user1和user2的欧氏距离分数,第一步先判断用户是否在数据
# 库中出现:
def euclidean_score(dataset, user1, user2):
    if user1 not in dataset:
        raise TypeError('User ' + user1 + ' not present in the dataset')

    if user2 not in dataset:
        raise TypeError('User ' + user2 + ' not present in the dataset')

    # 提取两个用户均评过分的电影
    rated_by_both = {}

    for item in dataset[user1]:
        if item in dataset[user2]:
            rated_by_both[item] = 1

    # 如果两个用户都没评分过,得分为0,则说明这两个用户之间没有相似度
    if len(rated_by_both) == 0:
        return 0

    # 对于每个共同评分,只计算平方和的平方根,并将该值归一化,使得评分取值在0到1之间:
    squared_differences = []

    for item in dataset[user1]:
        if item in dataset[user2]:
            squared_differences.append(np.square(dataset[user1][item] - dataset[user2][item]))

    return 1 / (1 + np.sqrt(np.sum(squared_differences)))
# 如果评分相似,那么平方和的差别就会很小,因此评分就会变得很高,这也是我们希望指标
# 达到的效果。

# if __name__ == '__main__':
#     #  加载数据文件中的movie_ratings.json文件:
#     data_file = 'movie_ratings.json'
#
#     with open(data_file, 'r') as f:
#         data = json.loads(f.read())
#
#     # 假定两个随机用户,计算其欧氏距离分数:
#     user1 = 'John Carson'
#     user2 = 'Michelle Peterson'
#
#     # 运行该代码,可以看到欧氏距离分数显示在命令行工具中
#     print("\nEuclidean score:")
#     print(euclidean_score(data, user1, user2))


编写一个程序用来计算皮尔逊相关系数

import numpy as np


#  计算user1和user2的皮尔逊相关系数
def pearson_score(dataset, user1, user2):
    if user1 not in dataset:
        raise TypeError('User ' + user1 + ' not present in the dataset')

    if user2 not in dataset:
        raise TypeError('User ' + user2 + ' not present in the dataset')

    # 提取两个用户均评过分的电影
    rated_by_both = {}

    for item in dataset[user1]:
        if item in dataset[user2]:
            rated_by_both[item] = 1

    num_ratings = len(rated_by_both)

    # 如果两个用户都没有评分,得分为0
    if num_ratings == 0:
        return 0

    #  计算相同评分电影的平方值之和
    user1_sum = np.sum([dataset[user1][item] for item in rated_by_both])
    user2_sum = np.sum([dataset[user2][item] for item in rated_by_both])

    # 计算所有相同评分电影的评分的平方和
    user1_squared_sum = np.sum([np.square(dataset[user1][item]) for item in rated_by_both])
    user2_squared_sum = np.sum([np.square(dataset[user2][item]) for item in rated_by_both])

    #  计算数据集的乘积之和
    product_sum = np.sum([dataset[user1][item] * dataset[user2][item] for item in rated_by_both])

    #  计算皮尔逊相关度
    Sxy = product_sum - (user1_sum * user2_sum / num_ratings)
    Sxx = user1_squared_sum - np.square(user1_sum) / num_ratings
    Syy = user2_squared_sum - np.square(user2_sum) / num_ratings

    #  考虑分母为0的情况:
    if Sxx * Syy == 0:
        return 0
    # 如果一切正常,返回皮尔逊相关系数:
    return Sxy / np.sqrt(Sxx * Syy)

# 定义main函数并计算两个用户之间的皮尔逊相关系数
# if __name__ == '__main__':
#     data_file = 'movie_ratings.json'
#
#     with open(data_file, 'r') as f:
#         data = json.loads(f.read())
#
#     user1 = 'John Carson'
#     user2 = 'Michelle Peterson'
#
#     print("\nPearson score:")
#     print(pearson_score(data, user1, user2))

编写一个程序用来寻找数据集中的相似用户

# import json
import numpy as np

from TestsOfPythonBook.Chapter05.movie_recomm.pearson_score import pearson_score

# 寻找特定数量的与输入用户相似的用户
def find_similar_users(dataset, user, num_users):
    if user not in dataset:
        raise TypeError('User ' + user + ' not present in the dataset')

    # 计算所有用户的皮尔逊相关度
    scores = np.array([[x, pearson_score(dataset, user, x)] for x in dataset if user != x])

    #  评分按照第二列排序
    scores_sorted = np.argsort(scores[:, 1])

    # 评分按照降序排列
    scored_sorted_dec = scores_sorted[::-1]

    # 提取出k个最高分
    top_k = scored_sorted_dec[0:num_users]

    return scores[top_k]

# if __name__=='__main__':
#     data_file = 'movie_ratings.json'
#
#     with open(data_file, 'r') as f:
#         data = json.loads(f.read())
#
#     user = 'John Carson'
#     print("\nUsers similar to " + user + ":\n")
#     similar_users = find_similar_users(data, user, 3)
#     print("User\t\t\tSimilarity score\n")
#     for item in similar_users:
#         print(item[0], '\t\t', round(float(item[1]), 2))

结合上述三个程序构建电影推荐引擎

import json
import numpy as np
from TestsOfPythonBook.Chapter05.movie_recomm.pearson_score import pearson_score

#  为给定用户生成电影推荐
def generate_recommendations(dataset, user):
    if user not in dataset:
        raise TypeError('User ' + user + ' not present in the dataset')

    # 计算该用户与数据库中其他用户的皮尔逊相关系数:
    total_scores = {}
    similarity_sums = {}

    for u in [x for x in dataset if x != user]:
        similarity_score = pearson_score(dataset, user, u)

        if similarity_score <= 0:
            continue
        # 找到还未被该用户评分的电影
        for item in [x for x in dataset[u] if x not in dataset[user] or dataset[user][x] == 0]:
            total_scores.update({item: dataset[u][item] * similarity_score})
            similarity_sums.update({item: similarity_score})

    # 如果该用户看过数据库中所有的电影,那就不能为用户推荐电影。对该条件做如下处理:
    if len(total_scores) == 0:
        return ['No recommendations possible']

    #  生成一个电影评分标准化列表
    movie_ranks = np.array([[total / similarity_sums[item], item]
                            for item, total in total_scores.items()])

    #  根据第一列对皮尔逊相关系数进行降序排列
    movie_ranks = movie_ranks[np.argsort(movie_ranks[:, 0])[::-1]]

    # 提取出推荐的电影
    recommendations = [movie for _, movie in movie_ranks]

    return recommendations


if __name__ == '__main__':
    data_file = 'movie_ratings.json'

    with open(data_file, 'r') as f:
        data = json.loads(f.read())

    user = 'Michael Henry'
    print("\nRecommendations for " + user + ":")
    movies = generate_recommendations(data, user)
    for i, movie in enumerate(movies):
        print(str(i + 1) + '. ' + movie)


    user = 'John Carson'
    print("\nRecommendations for " + user + ":")
    movies = generate_recommendations(data, user)
    for i, movie in enumerate(movies):
        print(str(i + 1) + '. ' + movie)


源代码+数据集

链接:https://pan.baidu.com/s/1rQRPW9zX4v7J3wBMwYE0Ug
提取码:na93
复制这段内容后打开百度网盘手机App,操作更方便哦

实验结果

机器学习(六)推荐引擎之构建电影推荐引擎

结果分析

在为Michael Henry生成推荐时,通过计算皮尔逊系数,根据相关性进行排序,最终返回3个相关性最高的电影。
用户John Carson看过所有电影,因此在为他推荐电影时,应该显示0推荐。

上一篇:MyBatis 笔记(7)缓存


下一篇:JavaScript 原型列prototype