基于Python的影视推荐系统的实现
近日在做一个影视网站时,考虑将推荐系统集成到网站中,所以从网上查阅了一些资料,最终得以实现,下面将自己的实现原理及过程写下来,以便作为记录。
1、影视相似度计算
这个推荐系统的主要是根据用户的观看记录,然后为其推荐相似的影视,所以最后采用了基于内容的协同过滤算法来实现,算法中采用欧几里德距离作为影视相似度的衡量标准。代码如下:
# 计算两个物品的相似度(欧几里德距离)
def calculate_euclidean(movie1,movie2, types, weight_types_dic):#如果两数据集数目不同,计算两者之间都对应有的数#计算欧几里德距离,并将其标准化sum = 0for i in range(len(types)):tmp_type = types[i]weight = weight_types_dic[tmp_type]tmp_type_content1 = movie1[tmp_type]tmp_type_content2 = movie2[tmp_type]if (type(tmp_type_content1).__name__ == 'list' and type(tmp_type_content2).__name__ == 'list'):tmp_type_content1 = '|'.join(tmp_type_content1)tmp_type_content2 = '|'.join(tmp_type_content2)similarity = weight * get_equal_rate_1(tmp_type_content1, tmp_type_content2)sum += similarity# print(tmp_type + ' ' + tmp_type_content1 + ' ' + tmp_type_content2 + ' ' + (str)(similarity))euclidean = sum / 10print(movie1['name'] + ' 和 ' + movie2['name'] + ' 相似度为 ' + (str)(euclidean) + '\n')return euclidean
2、影视相似度矩阵计算
由于服务器资源的限制,所以没有采用消息队列的方式来实现计算影视相似度,这里影视相似度的计算主要分为两种类型:
1、总量
这种情况主要用于推荐系统的初始化阶段,计算当前服务器中所有影视之间的相似度,总量计算只进行一次,以后只进行增量计算。
2、增量
每天计算前一天通过爬重新爬取到的影视与其他影视之间的相似度,同时计算其他影视与前一天新爬取到的影视之间的相似度,然后对影视相似度矩阵进行更新。
代码如下:
# 对字典列表根据指定的key去重
def distinct(items,key):key = itemgetter(key)items = sorted(items, key=key)return [next(v) for _, v in groupby(items, key=key)]
# 获取昨天的日期
def get_yesterday():today=datetime.date.today()oneday=datetime.timedelta(days=1)yesterday=today-onedayreturn (str)(yesterday)
# 计算两个字符串的相似度
def get_equal_rate_1(str1, str2):if (str2 == None):str2 = ''if (type(str1).__name__ == 'list' or type(str2).__name__ == 'list'):str1 = '|'.join(str1)str2 = '|'.join(str2)return difflib.SequenceMatcher(None, str1.lower(), str2.lower()).quick_ratio()
# 计算影视的相似度
# 比较的项目:name、type、type2、region、language、release_date
def get_recommendations(movie_type, type):if (movie_type == 'movie'):types = ['name', 'type', 'type2', 'region', 'language', 'release_date', 'directors', 'actors']weight_types_dic = {'name': 2.5, 'type': 0.5, 'type2': 0.5, 'region': 0.5, 'language': 0.5, 'release_date': 0.5,'directors': 2.5, 'actors': 2.5}collection = 'movie'elif (movie_type == 'drama'):types = ['name', 'type']weight_types_dic = {'name': 6, 'type': 4}collection = 'drama'elif (movie_type == 'piece'):types = ['name', 'type', 'type2', 'description']weight_types_dic = {'name': 4, 'type': 2, 'type2': 2, 'description': 2}collection = 'piece'# 计算所有影视之间的相似度db_utils = MongoDbUtils(collection)db_utils2 = MongoDbUtils(collection)if (type == 'all'):# 计算所有影视之间的相似度dic = {}dic2 = {}elif (type == 'latest'):# 计算最近更新的影视与其它影视之间的相似度dic = {'acquisition_time': {'$regex': '.*' +get_yesterday() + '.*'}}dic2 = {}# 计算当前影视与其它影视之间的相似度movies = db_utils.find(dic)total = movies.count() + 1for i, movie1 in enumerate(movies):collection = 'recommendations'db_utils3 = MongoDbUtils(collection)db_utils5 = MongoDbUtils(collection)tmp_dic = [{'$project': {"_id": 0, "euclidean": 0}}, {'$match': {"temp_id": movie1['_id']}}]movies2 = db_utils2.find(dic2)dic3 = {'temp_id': movie1['_id']}sort_movies = (list)(db_utils5.find(dic3).sort([('euclidean', -1)]))if (len(sort_movies) < 20):min_euclidean = 0else:min_euclidean = sort_movies[len(sort_movies) - 1]['euclidean']total2 = movies2.count() + 1recommendations = []for j, movie2 in enumerate(movies2):# 如果两个影视的_id相同(同一个影视),则跳过if (movie2['_id'] == movie1['_id']):continue# 如果两个影视的相似度已获取,则跳过print('正在计算 ' + (str)(i + 1) + '/' + (str)(total) + ' ' + (str)(j + 1) + '/' + (str)(total2) + ' ' +movie1['name'] + ' ' + movie2['name'])euclidean = calculate_euclidean(movie1, movie2, types, weight_types_dic)if (euclidean < min_euclidean):print('跳过 ' + (str)(i + 1) + '/' + (str)(total) + ' ' + (str)(j + 1) + '/' + (str)(total2) + ' ' +movie1['name'] + ' ' + movie2['name'])continuerecommendation = {'temp_id': movie1['_id'], 'temp_id2': movie2['_id'], 'euclidean': euclidean}recommendations.append(recommendation)recommendations = distinct(recommendations, 'temp_id2')recommendations = sorted(recommendations, key=lambda x: x['euclidean'], reverse=True)[:20]if (len(sort_movies) > 0 and recommendations[len(recommendations) - 1]['euclidean'] == sort_movies[len(sort_movies) - 1]['euclidean']):print(movie1['name'] + ' 推荐数据不用更新')continue# 删除当前影视的原有推荐数据,然后插入新的推荐数据try:db_utils5.delete(dic3)db_utils5.insert(recommendations)except:continue# 计算其他影视与当前影视的相似度,以便更新其他影视的推荐数据if (type == 'latest'):# 昨日有更新数据if (total > 1):movies = db_utils.find(dic2)total = movies.count() + 1for i, movie1 in enumerate(movies):collection = 'recommendations'db_utils5 = MongoDbUtils(collection)db_utils6 = MongoDbUtils(collection)tmp_dic = [{'$project': {"_id": 0, "euclidean": 0}}, {'$match': {"temp_id": movie1['_id']}}]movies2 = db_utils2.find(dic)dic3 = {'temp_id': movie1['_id']}sort_movies = (list)(db_utils5.find(dic3).sort([('euclidean', -1)]))if (len(sort_movies) < 20):min_euclidean = 0else:min_euclidean = sort_movies[len(sort_movies) - 1]['euclidean']total2 = movies2.count() + 1recommendations = (list)(db_utils6.find(dic3).sort([('euclidean', -1)]))for j, movie2 in enumerate(movies2):# 如果两个影视的_id相同(同一个影视),则跳过if (movie2['_id'] == movie1['_id']):continue# 如果两个影视的相似度已获取,则跳过print('正在计算 ' + (str)(i + 1) + '/' + (str)(total) + ' ' + (str)(j + 1) + '/' + (str)(total2) + ' ' +movie1['name'] + ' ' + movie2['name'])euclidean = calculate_euclidean(movie1, movie2, types, weight_types_dic)if (euclidean < min_euclidean):print('跳过 ' + (str)(i + 1) + '/' + (str)(total) + ' ' + (str)(j + 1) + '/' + (str)(total2) + ' ' +movie1['name'] + ' ' + movie2['name'])continuerecommendation = {'temp_id': movie1['_id'], 'temp_id2': movie2['_id'], 'euclidean': euclidean}recommendations.append(recommendation)recommendations = distinct(recommendations, 'temp_id2')recommendations = sorted(recommendations, key=lambda x: x['euclidean'], reverse=True)[:20]if (len(sort_movies) > 0 and recommendations[len(recommendations) - 1]['euclidean'] ==sort_movies[len(sort_movies) - 1]['euclidean']):print(movie1['name'] + ' 推荐数据不用更新')continue# 删除当前影视的原有推荐数据,然后插入新的推荐数据print((str)(movie1['_id']) + ' ' + (str)(min_euclidean) + ' ' + (str)(recommendations[len(recommendations) - 1]['euclidean']))db_utils5.delete(dic3)try:db_utils5.insert(recommendations)except:continue
3、测试示例及结果
公共部分:
types = ['name', 'type', 'type2', 'region', 'language', 'release_date', 'directors', 'actors']
weight_types_dic = {'name': 2.5, 'type': 0.5, 'type2': 0.5, 'region': 0.5, 'language': 0.5, 'release_date': 0.5,'directors': 2.5, 'actors': 2.5}
collection = 'movie'
db_utils = MongoDbUtils(collection)
drama1 = db_utils.find({'name': '匆匆那年'}).__getitem__(0)
drama2 = db_utils.find({'name': '匆匆那年(国剧)'}).__getitem__(0)
calculate_euclidean(drama1, drama2, types, weight_types_dic)
结果:
1、匆匆那年
和匆匆那年(国剧)
name 匆匆那年 匆匆那年(国剧) 1.6666666666666665
type 电影 电视剧 0.2
type2 爱情片 国产剧 0.0
region 大陆 大陆 0.5
language 国语 国语 0.5
release_date 2014 2014 0.5
directors 张一白 姚婷婷 0.0
actors 彭于晏|倪妮|郑恺|魏晨|张子萱 杨�W|何泓姗|白敬亭|杜维瀚|蔡文静 0.5714285714285714
匆匆那年 和 匆匆那年(国剧) 相似度为 0.3938095238095237
2、匆匆那年
和泰版匆匆那年
name 匆匆那年 泰版匆匆那年 2.0
type 电影 电视剧 0.2
type2 爱情片 海外剧 0.0
region 大陆 泰国 0.0
language 国语 其它 0.0
release_date 2014 2019 0.375
directors 张一白 Sakon Tiacharoen 0.0
actors 彭于晏|倪妮|郑恺|魏晨|张子萱 提顶·玛哈由踏纳|安苏玛琳·瑟拉帕萨默莎|查澈威·德查拉朋 0.22222222222222224
匆匆那年 和 泰版匆匆那年 相似度为 0.27972222222222226
3、匆匆那年
和匆匆那年好久不见
name 匆匆那年 匆匆那年好久不见 1.6666666666666665
type 电影 电视剧 0.2
type2 爱情片 国产剧 0.0
region 大陆 大陆 0.5
language 国语 国语 0.5
release_date 2014 2017 0.375
directors 张一白 李远/韩天 0.0
actors 彭于晏|倪妮|郑恺|魏晨|张子萱 张彬彬/王萌黎/金泽灏 0.18518518518518517
匆匆那年 和 匆匆那年好久不见 相似度为 0.34268518518518515
4、匆匆那年(国剧)
和泰版匆匆那年
name 匆匆那年(国剧) 泰版匆匆那年 1.4285714285714284
type 电视剧 电视剧 0.5
type2 国产剧 海外剧 0.16666666666666666
region 大陆 泰国 0.0
language 国语 其它 0.0
release_date 2014 2019 0.375
directors 姚婷婷 Sakon Tiacharoen 0.0
actors 杨�W|何泓姗|白敬亭|杜维瀚|蔡文静 提顶·玛哈由踏纳|安苏玛琳·瑟拉帕萨默莎|查澈威·德查拉朋 0.20833333333333331
匆匆那年(国剧) 和 泰版匆匆那年 相似度为 0.26785714285714285
5、匆匆那年(国剧)
和匆匆那年好久不见
name 匆匆那年(国剧) 匆匆那年好久不见 1.25
type 电视剧 电视剧 0.5
type2 国产剧 国产剧 0.5
region 大陆 大陆 0.5
language 国语 国语 0.5
release_date 2014 2017 0.375
directors 姚婷婷 李远/韩天 0.0
actors 杨�W|何泓姗|白敬亭|杜维瀚|蔡文静 张彬彬/王萌黎/金泽灏 0.0
匆匆那年(国剧) 和 匆匆那年好久不见 相似度为 0.3625
6、泰版匆匆那年
和匆匆那年好久不见
name 泰版匆匆那年 匆匆那年好久不见 1.4285714285714284
type 电视剧 电视剧 0.5
type2 海外剧 国产剧 0.16666666666666666
region 泰国 大陆 0.0
language 其它 国语 0.0
release_date 2019 2017 0.375
directors Sakon Tiacharoen 李远/韩天 0.0
actors 提顶·玛哈由踏纳|安苏玛琳·瑟拉帕萨默莎|查澈威·德查拉朋 张彬彬/王萌黎/金泽灏 0.0
泰版匆匆那年 和 匆匆那年好久不见 相似度为 0.24702380952380948
完整代码地址:https://github.com/wpwbb510582246/PocketFilm/tree/master/Recommender
父项目地址:https://github.com/wpwbb510582246/PocketFilm
基于Python的影视推荐系统的实现相关推荐
- 基于Python的图书推荐系统的设计与实现
基于Python的图书推荐系统的设计与实现 课题描述 在这个数据爆炸的年代,人们的需求逐渐增多,而所对应的资源更是海量. 一个人要从无数的选择中选中自己所感兴趣的无异于大海捞针. 本系统在实现个人信息 ...
- [精品毕设]基于Python的职业推荐系统求职招聘兼职爬虫
目录 1.项目功能介绍 2.项目资料截图 3.项目运行截图 4.项目资料获取 1.项目功能介绍 <基于Python的职业推荐系统的设计和实现>该项目采用技术Python的django框架. ...
- 基于Python的美食推荐系统Django景点美食管理系统(源码调试+讲解+文档)
- 基于Python的毕业论文怎么写?
目前越来越多的科学研究开始运用技术手段,其中应用较多的是模型建立和数据分析,这就离不开计算机语言的使用,Python以其简单易学的特性,配合高度的适用性,在科研领域发挥越来越重要的作用,基于Pytho ...
- 【毕业设计源码】基于Python的校园生活助手(二手+活动+论坛+新闻)信息系统
目录 一.程序介绍: 三.文档目录: 四.运行截图: 五.数据库表: 六.代码展示: 七.更多学习目录: 八.互动留言 一.程序介绍: 文档:开发技术文档.参考LW.答辩PPT,部分项目另有其他文档 ...
- Python之GUI:基于Python的GUI界面设计的一套AI课程学习(机器学习、深度学习、大数据、云计算等)推荐系统(包括语音生成、识别等前沿黑科技)
Python之GUI:基于Python的GUI界面设计的一套AI课程学习(机器学习.深度学习.大数据.云计算等)推荐系统(包括语音生成.识别等前沿黑科技) 导读 基于Python的GUI界面设计的一套 ...
- 基于Python + Django + mysql的协同推荐算法的电影推荐系统
基于Python + Django + mysql的协同推荐算法的电影推荐系统 本系统一共分为前台系统功能和后台系统功能两个模块,两个模块之间虽然在表面上是相互独立的,但是在对数据库的访问上是紧密相连 ...
- 【基于python+Django的物品协同过滤音乐推荐系统-哔哩哔哩】 https://b23.tv/V2zN54R
[基于python+Django的物品协同过滤音乐推荐系统-哔哩哔哩] https://b23.tv/V2zN54R https://b23.tv/V2zN54R
- 基于Python大数据的的新能源汽车推荐系统的设计与实现
基于Python大数据的的新能源汽车推荐系统的设计与实现 源码仓库------https://www.bilibili.com/video/BV1Ne4y1g7dC/ python的各种推荐算法 图书 ...
最新文章
- RecyclerView 可以与CollapsingToolbarLayout一起使用
- Java设计模式(二十):中介者设计模式
- Spring OXM- 漫谈XML解析技术
- RESTful API 中的 Status code 是否要遵守规范
- Ubuntu下共享目录的设置
- T级图片数据Cache思路以及图片服务器搭建方法
- 算法与数据结构--空间复杂度O(1)遍历树
- 菜鸟Linux系列:[4]SSH免密码登陆远程服务器
- C++ static关键字作用讲解
- 互联网人必读 | 大数据思维的十大核心原理
- 用C#把文件转换为XML
- VBA学习笔记(6)--抽取第一列中叫“虹虹”的个人信息
- Spring IOC三种注入方式(接口注入、setter注入、构造器注入)
- wangEditor富文本编辑器的简单使用
- Chromium OS Autotest 客户端测试
- 酒店宾馆wifi无线上网认证,手机认证方式详解
- 如何使用robots.txt及其详解
- 【小程序】JAVA实现从10~50中随机生成50个数,统计出现的数字及次数,输出出现最多的次数及对应的数字,按数字升序排列。
- X61的intel wireless 3945abg 不再掉线了
- 68个dlib的landmarks
热门文章
- 计算机课为什么叫信息技术课,第1课信息与信息技术(课件解说)
- 安装和第一次使用Android Studio中的问题以及解决
- windows PowerShell内置的端口扫描器使用
- 100个网站Html模板总有一个适合你 100个网站Html模板总有一个适合你
- 机械设备行业ERP系统三大功能分享
- 巴菲特致股东的一封信:1994年
- vivo手机助手强势来袭!
- 【递推】 铺砖2!!!
- R语言rattle中package ‘arules’is not available (for R version 3.6.3)的解决办法
- 分层和分段用什么符号_作文阅读分段是有几个横线就分几段吗 中国古文分段标志也是空两格吗?...