目录

  • 基于近邻用户的协同过滤
  • 基于近邻物品的协同过滤
  • 相似度计算-Jaccard相似度
  • 实验:基于KNN的电影推荐系统
    • 简介
    • movielens 数据集
    • 模型实现

基于近邻用户的协同过滤

基于近邻用户的协同过滤即UserCF(User Collaborative Filtering),UserCF用于给用户 A 推荐和他有着相似观影兴趣的用户 B 喜欢观看的电影:

用户 A 的好友用户 B 喜欢看电影 2、3、4,恰好电影 3 和电影 4 用户 A 没有看过,所以就可以把电影 3 和电影 4 推荐给用户 A;
为什么说用户 A 和用户 B 的观影兴趣相似(或者说为什么A和B可以成为好友)?来自谚语:物以类聚人以群分。既然 A 和 B 能够成为好朋友,那么他们必然就有着某些共同的价值观和兴趣爱好,比如A和B都看过电影2;


协同过滤
协同过滤是一类算法的总称,这类算法是根据用户的行为数据给用户产生推荐结果的一类算法;
上面的背景中,根据用户的观影记录,即每个用户看过哪些电影,来进行电影推荐,所以它属于协同过滤的一种;
既然可以将用户 B 喜欢(看过)的电影推荐给用户 A,那么用户 A 喜欢的电影也可以推荐给用户 B。所以,基于近邻用户的协同过滤算法是在观影兴趣相似的用户间互相推荐电影:


梳理一下UserCF的流程:
比如需要给用户 A 推荐电影,那么首先要找到和用户 A 观影兴趣最相似的 K 个用户,然后再从这 K 个用户喜欢的电影中,找到用户 A 没有看过的电影,推荐给 A,

先不考虑相似度的计算方法,K=3 的情况下,和用户 A 最相似的 3 个用户依次是用户 B、C、D,从这 3 个用户喜欢的电影集合中过滤掉用户 A 看过的电影,然后计算 A 对剩下的电影感兴趣的程度,从中选取最感兴趣的 3 个电影推荐给用户 A 。这里的推荐数量可以根据产品需求来设定,不一定是 3;
感兴趣程度计算方法是将每个电影上有观看行为的用户相似度求和得到的,例如 A 对电影 2 的感兴趣程度为:
用户 B 的 0.8 + 用户 C 的 0.6 = 1.4

基于近邻物品的协同过滤

推荐系统根据用户过往看过的电影,从电影库中查找相似的电影推荐出来,这种方法叫做基于近邻物品的协同过滤算法(简称ItemCF);

图中,电影1和电影2是两部相似电影;

  • 用户 A 看过电影 1,那么就给他推荐相似的电影 2;用户 D 看过电影 2,那么就给他推荐相似的电影 1。
  • 电影 1 和电影 2 相似是因为他们有着共同的观影群体(比如B和C)。
  • 因为用户 B 看过电影 1 和电影 2,所以只能给用户 B 推荐和电影 1 或电影 2 相似的电影,而不是推荐电影 1 和电影 2 本身。

梳理一下ItemCF的流程:
比如我们要给用户 A 推荐电影,首先要在用户 A 喜欢的电影中分别找到 K 个最相似的电影,然后再从这些电影中找到用户 A 没看过的电影推荐给 A ,

感兴趣程度计算方法是将每个候选电影上的电影相似度求和得到的,例如 A 对电影 4 的感兴趣程度为:电影 4 和电影 1 的相似度 0.5 + 电影 4 和电影 2 的相似度 0.4 = 0.9


近邻用户

  • 兴趣相似的用户,比如两个用户都看过同一部电影

近邻物品

  • 用户群体相似的物品,比如两部电影存在同一个观影群体

相似度计算-Jaccard相似度

在前面两个算法中,发现:

  • UserCF需要计算用户的相似度
  • ItemCF需要计算物品的相似度

在推荐系统中,使用KNN寻求到前K个相似用户(或者电影)时,即所谓KNN电影推荐系统;

相似度计算在第三课中提到过欧氏距离,这次新增杰卡德(Jaccard)相似度,杰卡德相似度是指两个集合的交集元素个数在并集中所占的比例;
比如整理得到以下数据:

图中展现的是代表用户观影记录的行为矩阵,矩阵中的 1 表示用户看过对应的电影,0 表示没看过;
如果用Jaccard计算用户相似度,应该为:

以用户B和D的相似度(或者用户D和B):13\frac{1}{3}31​,解释一下计算流程;

用户B和D共同看过电影2,交集为1,看过电影的并集是电影2和3和4,即并集为3,所以杰卡德相似度为13\frac{1}{3}31​
现在计算的是用户相似度,对于其中的某个用户,后期便可以根据前K个与之相似的用户完成电影推荐;

实验:基于KNN的电影推荐系统

简介

实验基于 Surprise 库及其中的 movielens 数据集实现一个简单的电影推荐系统;
实验很简单,模型直接使用 surprise 中的 KNNBaseline 实现基于近邻电影(物品)的协同过滤算法:根据用户最近喜欢看的电影推荐相似的 K 部电影;
Surprise,地址:可以基于显式评分数据(如movielens数据)实现一些常见推荐算法;
安装 Surprise 库,命令行输入:

conda install scikit-surprise

movielens 数据集

实验使用的 movielens 1M 数据集(1M是指共计100万评分记录),包含了6040名用户对大约3900部电影的1000209条评分记录。Surprise 中已经内置了这个数据集,初次使用时会先提示下载(输入Y进行下载):

# 导入Dataset类
from surprise import Dataset
# 调用函数,加载内置的 movielens 1m 数据集
data = Dataset.load_builtin('ml-1m')

下载完成后,可以查看 Surprise 的内置数据集在机器上的存放路径:

# 导入相关函数
from surprise import get_dataset_dir# 获取数据集根目录,返回字符串
data_root = get_dataset_dir()
data_root"""
'C:\\Users\\baijingyi/.surprise_data/'
"""

查看 movielens 1M 数据集包含的文件:

import os
file_dir = data_root + '/ml-1m/ml-1m/'
os.listdir(file_dir)"""
['movies.dat', 'ratings.dat', 'README', 'users.dat']
"""

pandas.read_table查看三个*.dat文件:
1.评分数据

# 使用 pandas 进行数据展示和分析
import pandas as pd# 评分数据的文件路径
ratings_path = data_root + "/ml-1m/ml-1m/ratings.dat"# 评分数据表的列名
ratings_col = ['userid', 'movieid', 'rating', 'timestamp']# 读取数据表
ratings = pd.read_table(ratings_path,sep="::",engine='python',header=None,names=ratings_col)# 展示前5行数据
ratings.head()print('评分数量:',len(ratings))# 展示各列的取值情况:取值的个数、数据类型
ratings.nunique()
   userid  movieid  rating  timestamp
0       1     1193       5  978300760
1       1      661       3  978302109
2       1      914       3  978301968
3       1     3408       4  978300275
4       1     2355       5  978824291
评分数量: 1000209
userid         6040
movieid        3706
rating            5
timestamp    458455
dtype: int64

2.用户属性数据

# 用户属性数据的文件路径
user_path = data_root + "/ml-1m/ml-1m/users.dat"# 用户数据表的列名
user_col = ['userid', 'gender', 'age', 'occupation', 'zip-code']# 读取数据表
users = pd.read_table(user_path,sep="::",engine='python',header=None,names=user_col)# 展示前5行数据
users.head()print('用户数量:',len(users))# 展示各列的取值情况:取值的个数、数据类型
users.nunique()
   userid gender  age  occupation zip-code
0       1      F    1          10    48067
1       2      M   56          16    70072
2       3      M   25          15    55117
3       4      M   45           7    02460
4       5      M   25          20    55455
用户数量: 6040
userid        6040
gender           2
age              7
occupation      21
zip-code      3439
dtype: int64

3.电影属性数据

# 电影属性数据的文件路径
movies_path = data_root + "/ml-1m/ml-1m/movies.dat"# 电影数据表的列名
movies_col = ['movieid', 'title', 'genres']# 读取数据表
movies = pd.read_table(movies_path,sep="::",engine='python',header=None,names=movies_col)# 展示前5行数据
movies.head()print('电影数量:',len(movies))# 展示各列的取值情况:取值的个数、数据类型
movies.nunique()
   movieid                               title                        genres
0        1                    Toy Story (1995)   Animation|Children's|Comedy
1        2                      Jumanji (1995)  Adventure|Children's|Fantasy
2        3             Grumpier Old Men (1995)                Comedy|Romance
3        4            Waiting to Exhale (1995)                  Comedy|Drama
4        5  Father of the Bride Part II (1995)                        Comedy
电影数量: 3883
movieid    3883
title      3883
genres      301
dtype: int64

定义映射函数read_item_names,返回 “电影ID”<-->“电影名称” 的字典:

{ID("string"):name("string")}
{name("string"):ID(int)}

注意pandas的结果:movies.dat 中的 movieid 和 title 这两列分别对应了电影ID和电影名称:

def read_item_names():# 电影属性数据的路径file_name = data_root+"/ml-1m/ml-1m/movies.dat"# 电影ID为key的字典rid_to_name = {}# 电影名称为key的字典name_to_rid = {}# ToDo# 电影数据表的列名movies_col = ['movieid', 'title', 'genres']# 读取数据表movies = pd.read_table(file_name, sep="::", engine='python', header=None, names=movies_col)movieid=movies["movieid"].valuesmoviename=movies["title"].valuesfor i in range(len(movies)):rid_to_name.update({str(movieid[i]):moviename[i]})name_to_rid.update({moviename[i]:movieid[i]})return rid_to_name, name_to_rid# 返回映射字典
rid_to_name, name_to_rid = read_item_names()print(rid_to_name['101']) # Bottle Rocket (1996)print(name_to_rid['Kids of the Round Table (1995)']) # 56

模型实现

构建训练数据:

trainset = data.build_full_trainset()

使用 surprise 中的 KNNBaseline 实现基于近邻电影的协同过滤算法:

from surprise import KNNBaseline# 使用皮尔逊系数计算 item 相似度
sim_options = {'name': 'pearson_baseline', 'user_based': False}# 实例化 KNNBaseline
algo = KNNBaseline(sim_options=sim_options)

计算物品(电影)相似度:

# 计算相似度矩阵
algo.fit(trainset)# 查看相似度矩阵
algo.sim"""
array([[ 1.        ,  0.01532195,  0.00496607, ...,  0.        ,0.        ,  0.        ],[ 0.01532195,  1.        , -0.06201139, ...,  0.        ,0.        ,  0.        ],[ 0.00496607, -0.06201139,  1.        , ...,  0.        ,0.        ,  0.        ],...,[ 0.        ,  0.        ,  0.        , ...,  1.        ,0.        ,  0.        ],[ 0.        ,  0.        ,  0.        , ...,  0.        ,1.        ,  0.        ],[ 0.        ,  0.        ,  0.        , ...,  0.        ,0.        ,  1.        ]])
"""

获取近邻电影的名称:

# 看过的电影名称
seen_movie = 'Heat (1995)'# 转换为movieid
movieid = str(name_to_rid[seen_movie])
print(movieid)# 转换为训练集内部id
inner_id = algo.trainset.to_inner_iid(movieid)# 获取近邻电影的训练集内部id,近邻电影数 K = 10
neighbors_inner_id = algo.get_neighbors(inner_id, k=10)# 获取近邻电影的movieid
neighbors_movie_id = [str(algo.trainset.to_raw_iid(i)) for i in neighbors_inner_id]
print(neighbors_movie_id)# 获取近邻电影的名称
neighbors_movie_name = [rid_to_name[name] for name in neighbors_movie_id]
print(neighbors_movie_name)

即推荐结果为:

看过电影的ID:
6近邻电影的ID:
['2231', '16', '431', '2952', '3006', '2023', '1892', '574', '3863', '1600']近邻电影的名称:
['Rounders (1998)', 'Casino (1995)', "Carlito's Way (1993)", 'Hard 8 (a.k.a. Sydney, a.k.a. Hard Eight) (1996)', 'Insider, The (1999)', 'Godfather: Part III, The (1990)', 'Perfect Murder, A (1998)', 'Spanking the Monkey (1994)', 'Cell, The (2000)', "She's So Lovely (1997)"]

第四课.KNN电影推荐相关推荐

  1. Python基于用户协同过滤算法电影推荐的一个小改进

    之前曾经推送过这个问题的一个实现,详见:Python基于用户协同过滤算法的电影推荐代码demo 在当时的代码中没有考虑一种情况,如果选出来的最相似用户和待测用户完全一样,就没法推荐电影了.所以,在实际 ...

  2. python电影推荐算法_基于Python的电影推荐算法

    原标题:基于Python的电影推荐算法 第一步:收集和清洗数据 数据链接:https://grouplens.org/datasets/movielens/ 下载文件:ml-latest-small ...

  3. 孙鑫mfc学习笔记第十四课

    第十四课 网络的相关知识,网络程序的编写,Socket是连接应用程序与网络驱动程序的桥梁,Socket在应用程序中创建,通过bind与驱动程序建立关系.此后,应用程序送给Socket的数据,由Sock ...

  4. 第四课.LinuxShell编程

    第四课目录 什么是Shell Shell编程 创建脚本 注释 Shell变量 基本运算 字符串,数组,分支循环,函数 应用实例 猜数字 获取CPU使用情况 探测本地网络 什么是Shell 有人说Lin ...

  5. 斯坦福大学机器学习第四课“逻辑回归(Logistic Regression)”

    斯坦福大学机器学习第四课"逻辑回归(Logistic Regression)" 本次课程主要包括7部分: 1) Classification(分类) 2) Hypothesis R ...

  6. python dataframe 新列_Python第二十四课:Pandas库(四)

    Python第二十四课:Pandas库(四)点击上方"蓝字",关注我们. 不知不觉,我们已经跨越了千难万险,从零开始,一步步揭开了Python神秘的面纱.学到至今,回过头,才晓得自 ...

  7. 【C++探索之旅】第一部分第四课:内存,变量和引用

    内容简介 1.第一部分第四课:内存,变量和引用 2.第一部分第五课预告:简易计算器 内存,变量和引用 上一课<[C++探索之旅]第一部分第三课:第一个C++程序>中,我们已经学习了如何创建 ...

  8. java毕业设计电影推荐网站mybatis+源码+调试部署+系统+数据库+lw

    java毕业设计电影推荐网站mybatis+源码+调试部署+系统+数据库+lw java毕业设计电影推荐网站mybatis+源码+调试部署+系统+数据库+lw 本源码技术栈: 项目架构:B/S架构 开 ...

  9. 基于微信云开发实现电影推荐小程序

    一.项目背景 项目名称为柚子电影,此小程序的目的是为了给大家推荐电影,与其他的售票等小程序不同. 二.性能需求 我的影单的增加.删除和查询.电影详情页面的完整实现.对小程序的各个方面:电影推荐.电影详 ...

最新文章

  1. java string.indexof(string)_Java StringBuffer indexOf()方法
  2. C++实现有哨兵的双向循环链表
  3. mysql默认join是什么类型_MySQL:join语句类型
  4. C++基础学习(02)--(数据类型,变量类型,变量作用域,常量,修饰符类型)
  5. SQL Server 2008R2安装详细教程(附安装包)
  6. wordpresd免登录发布接口php_屏蔽修改wp-login.php登录入口确保WordPress网站后台安全...
  7. CUDA学习(三)之使用GPU进行两个数相加
  8. sql server 缓存_搜索SQL Server查询计划缓存
  9. 关于数字签名简要原理
  10. 无线通信基础知识10:数字通信之双工技术
  11. Spring的两种定时器
  12. RANSAC算法拟合平面实现
  13. 让你的PPT更出彩的时间轴这样画!
  14. ae软件安装计算机丢失,Win10系统AE软件安装失败怎么办
  15. c语言实现字符串倒过来输出
  16. python json dump时,中文乱码问题
  17. 【JavaSE】Java方法练习题
  18. 阿里云普通硬盘与NAS盘的读写速度测试
  19. Keil报错:Undefined symbol GPIO_Init
  20. 思科前员工为报复恶意删除400多台虚拟机,公司损失超1600万

热门文章

  1. JVM:对象的实例化、内存布局与访问定位
  2. 自定义注解妙用,一行代码搞定用户操作日志记录,你学会了吗?
  3. “官宣”:程序员被正式纳入新生代农民工!
  4. 前端开发进阶手册.pdf
  5. 《我想进大厂》之JVM夺命连环10问
  6. 不称职Leader的10个特征,看看你中几条?
  7. 真香!20张图揭开「队列」的迷雾,一目了然
  8. 企业级自动化运维方案设计及Saltstack、Ansible等5种工具比较分析--云平台技术栈08...
  9. 在Data Collector中使用TensorFlow进行实时机器学习
  10. 如果有一天程序员再也不忙了