MongoDB 实战(一)基于PyMongo的电影影评分析 | 对数据结果进行可视化展示以及分析 | 评论词云 | 分时间段分析
文章目录
- 一、运行环境
- 二、实战介绍
- 三、获取数据
- 四、PyMongo 实战
- 4.1 连接MongoDB、创建集合
- 4.2 向 MongoDB 插入文档
- 4.3 查询MongoDB的数据
- 4.4 同样的操作插入影评
- 4.5 插入影评信息到MongoDB
- 五、基于 PyMongo的数据分析
- 5.1 计算豆瓣 Top 10 影视的平均评分
- 5.2 统计Top10电影影评的[赞同 / 不赞同]的平均比率
- 5.3 统计Top10电影从2021年到今日的评论情况
Gitee 仓库地址: https://gitee.com/ccuni/pymongo-douban-comment-analysis
一、运行环境
- Windows10
- python 3.9
- Anaconda3 + jupyter
- mongodb 5.0.6
- PyMongo 3.5.1
- wordcloud-1.8.1
anaconda 安装 wordcloud的命令
conda install -c conda-forge wordcloud
二、实战介绍
数据来源基于Python的第三方库,即requests库
,bs4库
,re库
爬取豆瓣网TOP10的电影信息,以及它们的部分影评信息(100个左右)。
将爬取的信息进行预处理,封装成dict字典,借助 pymongo库
连接本机的 MongoDB,向数据库插入之前爬取的真实数据,然后分别使用MongoDB提供的map_reduce机制以及agreegate机制来聚合、分组、汇总计算数据,以MongoDB为基础,存储影视信息和评论信息,同时分析电影的综合价值。
三、获取数据
这一部分可参考Gitee仓库:https://gitee.com/ccuni/pymongo-douban-comment-analysis
四、PyMongo 实战
4.1 连接MongoDB、创建集合
from pymongo import MongoClient
from random import randint
client = MongoClient('localhost', 27017)db = client.mv
# 创建电影信息集合
ct_mv_info = db.dc_mv_info
# 创建影评集合
ct_mv_review = db.dc_mv_review# 查看创建结果
ct_mv_review
4.2 向 MongoDB 插入文档
这里先将DataFrame的影视信息转化为dict字典格式
dc_mv = []
index = 0
for x in mv_data.values.tolist():dict_info = {}# 指定文档的_id为电影IDdict_info['_id'] = mv_data['mv_id'][index]index += 1# i 用于循环遍历取DF列表数据i = 0for key, v in mv_data.items():dict_info[key] = x[i]i += 1# 指定文档的dc_mv.append(dict_info)
dc_mv
# 插入前 先清空
ct_mv_info.delete_many({})
# 插入文档
ct_mv_info.insert_many(dc_mv)
4.3 查询MongoDB的数据
ct_mv_info.find_one()
4.4 同样的操作插入影评
先处理信息,将原先的DataFrame的影评信息转化为可插入到MongoDB的dict字典
# list_mv[1] 输出结果 dict_keys(['reviews', 'star'])
# 查询保存的列表数据
# for x in list_mv[1].values.to_list():
# print(x)
'''根据之前的存储信息获取所有电影的影评, 封装成可插入MongoDB的 dict
'''
def getAllReviews() -> list[list]:index = 0reviews = []for i in range(len(list_mv)):# 获取每一列rv_cols = list_mv[0]['reviews'].columns# 表示当前的评论标号i = 0# 记录当前电影的所有影评信息dc_reviews = []for k, rows in list_mv[index]['reviews'].iterrows():# 根据电影ID和当前的评论序号定义_iddict_info = {'_id' : mv_data['mv_id'][index] + str(i)}i += 1for col in rv_cols:dict_info[col] = rows[col]dc_reviews.append(dict_info)index += 1reviews.append(dc_reviews)return reviews# 获取Top10电影的爬取到的所有影评
dc_reviews = getAllReviews()
count = 0
for i in range(len(dc_reviews)):count += len(dc_reviews[i])
print(f'[INFO] >> 共获取到 {len(dc_reviews)} 个电影 {count} 个的影评')print(f'[INFO] >> 查看其中的一个影评: {dc_reviews[0][:1]}')
处理结果:
4.5 插入影评信息到MongoDB
ct_mv_review.delete_many({})
for rv in dc_reviews:ct_mv_review.insert_many(rv)
# 查看插入结果
ct_mv_review.find_one()
五、基于 PyMongo的数据分析
5.1 计算豆瓣 Top 10 影视的平均评分
ct_mv_info.find_one()
from bson.code import Codemapper = Code("""function(){emit('', {count:1, mv_star: eval(this.mv_star)});}
""")
reducer = Code("""function(k, v) {reducedVal = {count: 0, mv_star: 0};for (var idx = 0; idx < v.length; idx++) {reducedVal.count += v[idx].count;reducedVal.mv_star += v[idx].mv_star;}return reducedVal;};
""")finalizer = Code("""reducedVal.mv_star_avg = reducedVal.mv_star/reducedVal.count;return reducedVal;
""")
res = ct_mv_info.map_reduce(map = mapper,reduce=reducer,out='mv_star_avg', finalize = finalizer)
res
ct_mv_star_avg = db.mv_star_avg
for x in ct_mv_star_avg.find():print(x)
根据结果得出,10部电影里的平均评分为9.5分,还是处于相当高的水平,当然这个案例并没有实际意义,主要是为了熟悉MongoDB的MapReduce的基本使用
5.2 统计Top10电影影评的[赞同 / 不赞同]的平均比率
ct_mv_review.find_one()
from bson.code import Codemapper = Code("""function(){var a = eval(this.rv_action_agree);var b = eval(this.rv_action_disagree);var rate = 0;if(a > 0 && b > 0){rate = b / (a + b);emit(this.rv_mv_id, {count: 1, rate: rate});} }
""")
reducer = Code("""function(k, v) {reducedVal = {count: 0, rate: 0};for (var i = 0; i < v.length; i++) {reducedVal.count += v[i].count;reducedVal.rate += v[i].rate;}return reducedVal;};
""")finalizer = Code("""reducedVal.rate = reducedVal.rate/reducedVal.count;return reducedVal;
""")
res = ct_mv_review.map_reduce(map = mapper,reduce=reducer,out='mv_agree_divide_disagree_rate', finalize = finalizer)
res
ct_mv_agree_divide_disagree_rate = db.mv_agree_divide_disagree_rate# 查询mongodb文档数据并持久化
temp1 = []
for x in ct_mv_agree_divide_disagree_rate.find():print(x)temp1.append(x)
len(temp1)
# 准备电影ID到电影名的映射字典
dict_rv_name = {}
for mv in ct_mv_info.find():dict_rv_name[mv['mv_id']] = mv['mv_name']
# 条件查询, 根据电影 ID 获取到对应的电影名
for i in range(len(temp1)):id = temp1[i]['_id']name = ''for x in ct_mv_info.find({'_id': id}):name = x['mv_name']temp1[i]['mv_name'] = name
temp1
可视化
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['font.family']='sans-serif'# 柱形的宽度
bar_width = 0.6
plt.xticks(rotation=35)
x1 = [x['mv_name'] for x in temp1]y1 = [x['value']['rate'] for x in temp1]
# 绘制柱形图
plt.bar(x=x1, height=y1, width=bar_width, color=['skyblue', 'pink'],linewidth=1.5,)# 26 # 为每个条形图添加数值标签
for x,y in enumerate(y1):plt.text(x,y+0.003,'%.3f' % y,ha='center')
plt.xlabel('电影名称',fontsize=14, color='blue')
plt.ylabel('评论分歧(反对)平均占比',fontsize=14, color='red')
plt.title('豆瓣Top10影视评论分歧占比统计图',fontsize=15, color='green')
plt.show()
分析过程:
通过PyMongoDB的MapReduce过程,最终得出的豆瓣Top10部分影评分歧占比统计图如上图所示。
从整体来看,Top10影视的评论分歧都相对较低,处于
[6.1%, 11.1%]
范围。其中占比最多电影的为《盗梦空间》,分歧率为
11.1%
,这意味着有100人评论,那么就有将近11人的观点不被赞同,这跟电影的题材、类型、剧情、演员等多个因素都有关。占比最少的为《千与千寻》,仅为
6.1%
,这说明观众们的观点大多是一致的,100人里面只有6人左右的观点不一致。
综上,对于Top10的电影,除了评分、观看数等指标,评论分歧率直观体现了影视的影响力,这意味着观众可以选择这个分歧率较小的电影作为参考,达到更好的观看体验,同时对于同行,能更放心地借鉴其中的一些高深的拍摄手法、剧情演绎方法等。
5.3 统计Top10电影从2021年到今日的评论情况
ct_mv_review.find_one()
for x in ct_mv_review.aggregate([{'$group': {'_id':'$rv_mv_id', 'counter':{'$sum':1}}}]):print(x)
from datetime import datetimelist_rv= []
year, month, day = 2021,1,1
for x in ct_mv_review.aggregate([{# 转化类型'$project':{'rv_time': '$rv_time','rv_info': '$rv_info','rv_name': '$rv_name','rv_time_stand': {'$convert':{'input':'$rv_time','to': 'date','onNull': 'missing rv_time'}},},},{'$match': {'rv_time_stand':{'$gte': datetime(year,month,day)},}}, ]):list_rv.append(x)dict_rv_info = {}
'''处理 MongoDB 聚合后的结果 汇总评论
'''
for rv in list_rv:# 前 7 位是电影的IDmv_id = rv['_id'][:7]dict_rv_info[dict_rv_name[mv_id]] = {}dict_rv_info[dict_rv_name[mv_id]][rv['rv_name']] = {'rv_time': rv['rv_time'],'rv_info': rv['rv_info']}
print(f'[INFO] >> 已统计完 [{len(dict_rv_info)}] 个电影在{year}年{month}月{day}后的影评')'''词频统计
'''
import jieba
from wordcloud import WordCloud
# 不需要统计的词汇
nope = ['电影', '没有', '一个', '之后', '这部']
for k, v in dict_rv_info.items():dict_word_count = {}# 遍历每个用户的评论for review in v.values():# 遍历每个词for x in jieba.cut(review['rv_info']):if(len(x) >= 2) and x not in nope:dict_word_count.setdefault(x, 0)dict_word_count[x] = dict_word_count[x] + 1#生成词云 保存到本地t = WordCloud(width=600, height=480, # 图片大小background_color='white', # 背景颜色scale=10,font_path=r'c:\windows\fonts\simfang.ttf' ).generate_from_frequencies(dict_word_count)save_path = './count_images/' + k + '.jpg't.to_file(save_path)print(f'[INFO] >> 电影[{k}] 评论的词频统计词云生成完毕, 保存位置在[{save_path}]')
# print(dict_word_count)
评论词云的结果如下图所示:
美丽人生:
辛德勒的名单
这里展示了两部电影的评论词云,而且是在21年1月份以后的评论,在MongoDB的强大支持下,检索某个日期里的文档数据十分遍历,通过这样的方式,我们能感受到电影从去年到现在的影响力。
MongoDB 实战(一)基于PyMongo的电影影评分析 | 对数据结果进行可视化展示以及分析 | 评论词云 | 分时间段分析相关推荐
- Spark商业案例与性能调优实战100课》第20课:大数据性能调优的本质和Spark性能调优要点分析
Spark商业案例与性能调优实战100课>第20课:大数据性能调优的本质和Spark性能调优要点分析 基于本元想办法,大智若愚,大巧若拙!深入彻底的学习spark技术内核!
- 《大数据存储:MongoDB实战指南》一1.1 什么是大数据
本节书摘来异步社区<大数据存储:MongoDB实战指南>一书中的第1章,第1.1节,作者: 郭远威 , 彭文波 责编: 陈冀康,更多章节内容可以访问云栖社区"异步社区" ...
- 基于微信小程序的电影交流论坛系统 基于SSM的电影影评小程序(源码调试+讲解+文档)
- R语言实战应用精讲50篇(十八)-R语言实现分词、词频与词云案例解析
前言 我真的超爱R语言,原因之一就是R有许多已经写好."开箱即用"的程序包可以直接拿来用:要知道,程序包减少了多少工作量.当然,其他语言也有类似的包,但是貌似没那么多.没那么细.这 ...
- 【微博爬虫教程实例】基于requests、mysql爬取大数据量博主关键字下博文及评论
[关键词:手把手教程.反爬.数据库.python爬虫.微博关键词爬虫.较大数据量.数据简单过滤] 本教程适合微博相关爬虫需求者阅读,完整实例源码将放置在文末github链接中. 该实例针对微博的反爬措 ...
- 基于Scrapy框架爬取豆瓣《复联4》影评,并生成词云
基于Scrapy框架爬取豆瓣<复联4>影评,并生成词云 1. 介绍及开发环境 2. 爬虫实现 2.1 新建项目 2.2 构造请求 2.3 提取信息 2.4 数据存储 2.4 运行结果 3. ...
- 基于Python的海量豆瓣电影、数据获取、数据预处理、数据分析、可视化、大屏设计项目(含数据库)
目录 项目介绍 研究背景 国内外研究现状分析 研究目的 研究意义 研究总体设计 网络爬虫介绍 豆瓣电影数据的采集 数据预处理 大数据分析及可视化 豆瓣影评结构化分析 大屏可视化 文本可视化 总结 每文 ...
- 【项目实战】基于python的 p2p 贷后指标全自动日报制作
需要数据分析.风控评分卡等相关数据.代码,请添加qq群:102755159,或留言联系笔者邮件发送!!! 如果对金融风控.机器学习.数据科学.大数据分析等感兴趣的小伙伴,可加微信交流(邮件中备注,我会 ...
- 电影《战狼2》的可视化分析
<战狼2>真心堪称中国的好莱坞大片,不管是打斗场景的展现,还是在特效的细节处理.吴京的那句"我只会花钱在武器上,花在取景上,永远不会花在小鲜肉上!",也是近年来,观众对 ...
最新文章
- 设计模式学习2 工厂模式
- 用 Python 实现答题卡识别!
- mysql ldap_OpenLDAP 使用MySQL作为数据库
- [HDU 1427]速度计算24点(DFS暴力搜索)
- 云信迎来五周年里程碑:日活破3亿,消息量破10000亿
- boost::hana::flatten用法的测试程序
- when is this.oModel in sap-ui-core.js initialized for navigation working
- php ioc容器,PHP 在Swoole中使用双IoC容器实现无污染的依赖注入
- 基于java教学管理系统设计(含源文件)
- ansys怎么使用anand模型_详细剖析ANSYS有限元分析这个软件
- 如何得到DataTable的列名
- Pycharm下载包慢的问题
- python判断是否为英文_Python判断字符串是否纯英文(纯ASCII码字符)
- 推荐10个超级实用的电脑软件 (可以快速提高工作效率)
- c语言stdin输入字符,scanf如何从stdin中读取数据的
- python处理金融数据_Python金融大数据分析-数据获取与简单处理
- NOI / 2.1基本算法之枚举 1809:两倍
- 《IBM SPSS Modeler数据与文本挖掘实战》之文本挖掘算法
- BLE-1の蓝牙4.0协议栈概览
- Vue源码实现之watcher拾遗
热门文章
- 网站安全公司生存发展趋势分析
- 关于lightroom 安装出现乱码问题
- python抓取小红书_小红书很难爬?最新爬取方法教给你啦~
- java输出华氏摄氏温度转换表_C语言入门教程-示例:编写能够打印华氏-摄氏温度转换表的程序...
- IMS:开发者选项Touch点显示
- oracle查询为姓 张,Oracle经典查询案例
- c语言圆周率小数点后500万位,圆周率500位
- 在c语言如何对拨码开关编程,拨码开关控制实验
- 关于 618的前世今生,我帮东哥告诉你
- inurl_inurl,intitle指令的含义、作用及用法