近日在做一个影视网站时,考虑将推荐系统集成到网站中,所以从网上查阅了一些资料,最终得以实现,下面将自己的实现原理及过程写下来,以便作为记录。

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的影视推荐系统的实现相关推荐

  1. 基于Python的图书推荐系统的设计与实现

    基于Python的图书推荐系统的设计与实现 课题描述 在这个数据爆炸的年代,人们的需求逐渐增多,而所对应的资源更是海量. 一个人要从无数的选择中选中自己所感兴趣的无异于大海捞针. 本系统在实现个人信息 ...

  2. [精品毕设]基于Python的职业推荐系统求职招聘兼职爬虫

    目录 1.项目功能介绍 2.项目资料截图 3.项目运行截图 4.项目资料获取 1.项目功能介绍 <基于Python的职业推荐系统的设计和实现>该项目采用技术Python的django框架. ...

  3. 基于Python的美食推荐系统Django景点美食管理系统(源码调试+讲解+文档)

  4. 基于Python的毕业论文怎么写?

    目前越来越多的科学研究开始运用技术手段,其中应用较多的是模型建立和数据分析,这就离不开计算机语言的使用,Python以其简单易学的特性,配合高度的适用性,在科研领域发挥越来越重要的作用,基于Pytho ...

  5. 【毕业设计源码】基于Python的校园生活助手(二手+活动+论坛+新闻)信息系统

    目录 一.程序介绍: 三.文档目录: 四.运行截图: 五.数据库表: 六.代码展示: 七.更多学习目录: 八.互动留言 一.程序介绍: 文档:开发技术文档.参考LW.答辩PPT,部分项目另有其他文档 ...

  6. Python之GUI:基于Python的GUI界面设计的一套AI课程学习(机器学习、深度学习、大数据、云计算等)推荐系统(包括语音生成、识别等前沿黑科技)

    Python之GUI:基于Python的GUI界面设计的一套AI课程学习(机器学习.深度学习.大数据.云计算等)推荐系统(包括语音生成.识别等前沿黑科技) 导读 基于Python的GUI界面设计的一套 ...

  7. 基于Python + Django + mysql的协同推荐算法的电影推荐系统

    基于Python + Django + mysql的协同推荐算法的电影推荐系统 本系统一共分为前台系统功能和后台系统功能两个模块,两个模块之间虽然在表面上是相互独立的,但是在对数据库的访问上是紧密相连 ...

  8. 【基于python+Django的物品协同过滤音乐推荐系统-哔哩哔哩】 https://b23.tv/V2zN54R

    [基于python+Django的物品协同过滤音乐推荐系统-哔哩哔哩] https://b23.tv/V2zN54R https://b23.tv/V2zN54R

  9. 基于Python大数据的的新能源汽车推荐系统的设计与实现

    基于Python大数据的的新能源汽车推荐系统的设计与实现 源码仓库------https://www.bilibili.com/video/BV1Ne4y1g7dC/ python的各种推荐算法 图书 ...

最新文章

  1. RecyclerView 可以与CollapsingToolbarLayout一起使用
  2. Java设计模式(二十):中介者设计模式
  3. Spring OXM- 漫谈XML解析技术
  4. RESTful API 中的 Status code 是否要遵守规范
  5. Ubuntu下共享目录的设置
  6. T级图片数据Cache思路以及图片服务器搭建方法
  7. 算法与数据结构--空间复杂度O(1)遍历树
  8. 菜鸟Linux系列:[4]SSH免密码登陆远程服务器
  9. C++ static关键字作用讲解
  10. 互联网人必读 | 大数据思维的十大核心原理
  11. 用C#把文件转换为XML
  12. VBA学习笔记(6)--抽取第一列中叫“虹虹”的个人信息
  13. Spring IOC三种注入方式(接口注入、setter注入、构造器注入)
  14. wangEditor富文本编辑器的简单使用
  15. Chromium OS Autotest 客户端测试
  16. 酒店宾馆wifi无线上网认证,手机认证方式详解
  17. 如何使用robots.txt及其详解
  18. 【小程序】JAVA实现从10~50中随机生成50个数,统计出现的数字及次数,输出出现最多的次数及对应的数字,按数字升序排列。
  19. X61的intel wireless 3945abg 不再掉线了
  20. 68个dlib的landmarks

热门文章

  1. 计算机课为什么叫信息技术课,第1课信息与信息技术(课件解说)
  2. 安装和第一次使用Android Studio中的问题以及解决
  3. windows PowerShell内置的端口扫描器使用
  4. 100个网站Html模板总有一个适合你 100个网站Html模板总有一个适合你
  5. 机械设备行业ERP系统三大功能分享
  6. 巴菲特致股东的一封信:1994年
  7. vivo手机助手强势来袭!
  8. 【递推】 铺砖2!!!
  9. R语言rattle中package ‘arules’is not available (for R version 3.6.3)的解决办法
  10. 分层和分段用什么符号_作文阅读分段是有几个横线就分几段吗 中国古文分段标志也是空两格吗?...