基于豆瓣top250电影简介和类型的电影分类
在这篇博客中,我们将探讨一个数据科学项目,该项目旨在根据电影的简介和类型对电影进行分类。我们将使用Python的Pandas库进行数据操作,并使用Matplotlib库进行数据可视化。这个项目可以帮助我们更好地了解不同类型电影的分布情况,并为不同观众推荐合适的电影。
项目背景
我们从一个包含电影信息的CSV文件入手,文件名为豆瓣.csv
。该文件包含电影的名称、简介和类型等信息。我们的目标是根据电影的简介和类型,将电影分类为适合家庭观影、适合年轻人、适合成年观众等多个类别。
项目步骤
- 读取CSV文件
- 定义分类函数
- 应用分类函数
- 分类统计
- 绘制饼图
- 生成电影列表
步骤详解
1. 读取CSV文件
首先,我们使用Pandas库读取CSV文件,并将数据存储在一个DataFrame中。
import pandas as pd
# 读取CSV文件
df = pd.read_csv('豆瓣.csv')
2. 定义分类函数
我们定义一个函数classify_movie
,该函数根据电影的简介和类型进行分类。我们定义了一些关键字,函数会检查简介和类型中是否包含这些关键字,从而将电影归类到不同的类别。
def classify_movie(row):
intro = row['简介']
types = row['类型']
all = f"{intro}{types}"
if isinstance(all, str):
if any(keyword in all for keyword in ['家庭', '孩子', '温馨', '亲情', '合家欢', '友情', '传统', '伦理', '照顾', '家园', '父母', '兄弟姐妹', '家庭团聚', '爱心', '和谐', '保护', '抚养', '家庭责任', '团结', '亲密', '家庭传统']):
return '适合家庭观影'
elif any(keyword in all for keyword in ['青春', '爱情', '活力', '校园', '浪漫', '冒险', '励志', '梦想', '运动', '热血', '成长', '挑战', '同学', '友情', '独立', '自由', '激情', '音乐', '派对', '自我发现', '旅行', '青春困惑', '事业', '奋斗']):
return '适合年轻人'
elif any(keyword in all for keyword in ['深刻', '历史', '复杂', '政治', '犯罪', '悬疑', '惊悚', '战争', '社会', '心理', '人性', '暴力', '伦理', '辩论', '法律', '道德', '伦理困境', '剧情', '人生', '政治阴谋', '社会问题', '心理学', '犯罪调查', '战争历史', '权力斗争']):
return '适合成年观众'
elif any(keyword in all for keyword in ['科幻', '未来', '太空', '外星人', '机器人', '科技', '平行宇宙', '时间旅行', '人工智能', '异形', '末日', '未来战争', '宇宙探险', '克隆', '超能力', '超自然', '纳米技术', '赛博朋克', '量子力学', '虚拟现实', '星际旅行', '银河帝国', '时间悖论', '外太空']):
return '适合科幻迷'
elif any(keyword in all for keyword in ['喜剧', '搞笑', '幽默', '讽刺', '搞怪', '滑稽', '轻松', '欢乐', '恶搞', '反差', '荒诞', '讽刺社会', '黑色幽默', '欢乐时光', '喜剧片', '搞笑场景', '喜剧人物', '搞笑对白', '欢乐冒险', '笑声', '喜剧剧情', '滑稽人物', '荒谬情节']):
return '适合喜剧迷'
elif any(keyword in all for keyword in ['动画', '卡通', '动漫', '儿童', '幻想', '魔法', '冒险', '奇幻', '超自然', '童话', '传奇', '动物', '幻想世界', '英雄', '动画片', '魔幻冒险', '童年', '童趣', '卡通角色', '动漫角色', '梦幻', '动画奇观', '卡通片', '幻想故事']):
return '适合动画迷'
elif any(keyword in all for keyword in ['恐怖', '惊悚', '鬼怪', '血腥', '灵异', '恐惧', '惊骇', '恐怖片', '超自然', '灵异事件', '恐怖怪物', '黑暗', '恐怖杀手', '诡异', '鬼魂', '恐怖故事', '阴森', '恐怖电影', '黑暗力量', '恐怖氛围', '恐怖场景', '恐怖声音', '恐怖角色', '惊悚剧情']):
return '适合恐怖迷'
elif any(keyword in all for keyword in ['纪录片', '真实', '纪实', '历史', '社会', '生态', '文化', '科学', '自然', '人文', '探索', '实地', '采访', '深度', '记录', '观察', '紀錄', '纪实报道', '真实事件', '历史文献', '自然世界', '文化探索', '科学发现', '社会研究']):
return '适合纪录片爱好者'
elif any(keyword in all for keyword in ['历史', '战争', '古代', '帝国', '文明', '革命', '传奇', '古代故事', '历史事件', '历史人物', '文献', '古代文化', '战争历史', '历史背景', '古代传奇', '古文明']):
return '适合历史迷'
elif any(keyword in all for keyword in ['动作', '战斗', '追逐', '武打', '竞技', '爆破', '特技', '冒险', '英雄', '战争', '反派', '拳击', '枪战', '追击', '暴力', '激战', '动作片', '武术', '动作场面', '动作角色']):
return '适合动作迷'
elif any(keyword in all for keyword in ['音乐', '演唱', '演奏', '歌舞', '音乐剧', '音乐会', '音乐家', '乐队', '音乐史', '流行音乐', '古典音乐', '音乐作品', '音乐节', '歌曲', '作曲', '音乐表演']):
return '适合音乐迷'
elif any(keyword in all for keyword in ['冒险', '探险', '荒野', '挑战', '探索', '冒险故事', '冒险片', '野外', '生存', '冒险旅程', '冒险人物', '神秘', '古迹', '秘境', '探险队']):
return '适合冒险迷'
elif any(keyword in all for keyword in ['运动', '比赛', '体育', '竞技', '球类', '奖杯', '运动员', '运动会', '体育精神', '训练', '体育赛事', '比赛场面', '体育历史', '体育英雄', '体育电影', '运动纪录片']):
return '适合运动迷'
return '其他'
3. 应用分类函数
我们将分类函数应用于数据框的每一行,并将结果存储在新列分类
中。
# 应用分类函数
df['分类'] = df.apply(classify_movie, axis=1)
4. 分类统计
统计每个分类的数量,并存储在变量category_counts
中。
# 分类统计
category_counts = df['分类'].value_counts()
5. 绘制饼图
使用Matplotlib库绘制一个改进后的饼图,显示各分类的分布情况。
import matplotlib.pyplot as plt
import numpy as np
# 绘制改进后的饼图
plt.figure(figsize=(10, 7))
wedges, texts, autotexts = plt.pie(category_counts, labels=category_counts.index, autopct='%1.1f%%', startangle=140)
# 确保饼图是圆形的
plt.axis('equal')
# 设置标题
plt.title('电影分类分布')
# 为每个扇区添加注释
for wedge, label, count in zip(wedges, category_counts.index, category_counts):
angle = (wedge.theta2 - wedge.theta1) / 2. + wedge.theta1
x = np.cos(np.deg2rad(angle))
y = np.sin(np.deg2rad(angle))
horizontalalignment = {-1: 'right', 1: 'left
'}[int(np.sign(x))]
connectionstyle = "angle,angleA=0,angleB={}".format(angle)
plt.annotate(f'{label}: {count}', xy=(x, y), xytext=(1.35*np.sign(x), 1.4*y),
horizontalalignment=horizontalalignment, fontsize=10,
arrowprops=dict(arrowstyle="->", connectionstyle=connectionstyle))
# 显示图表
plt.show()
6. 生成电影列表
创建一个字典,存储每个分类下的电影列表并为每个电影编号。
# 创建一个字典存储每个类别下的电影列表并编号
category_movies = {}
for category in category_counts.index:
movies = df[df['分类'] == category]['电影名'].tolist()
category_movies[category] = {i+1: movie for i, movie in enumerate(movies)}
# 打印每个类别下的电影列表并编号
for category, movies in category_movies.items():
print(f"\n{category}:")
for number, movie in movies.items():
print(f" {number}. {movie}")
代码详解
导入必要的库
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
这段代码导入了三个库:
pandas
:用于数据操作和分析。matplotlib.pyplot
:用于绘图和数据可视化。numpy
:用于数值计算。
读取CSV文件
# 读取CSV文件
df = pd.read_csv('豆瓣.csv')
这行代码使用pandas
的read_csv
函数读取名为豆瓣.csv
的CSV文件,并将其存储在df
(数据框)变量中。
定义扩展后的分类函数
def classify_movie(row):
intro = row['简介']
types = row['类型']
all = f"{intro}{types}"
if isinstance(all, str):
if any(keyword in all for keyword in ['家庭', '孩子', '温馨', '亲情', '合家欢', '友情', '传统', '伦理', '照顾', '家园', '父母', '兄弟姐妹','家庭团聚', '爱心', '和谐', '保护', '抚养', '家庭责任', '团结', '亲密', '家庭传统']):
return '适合家庭观影'
elif any(keyword in all for keyword in ['青春', '爱情', '活力', '校园', '浪漫', '冒险', '励志', '梦想', '运动', '热血', '成长', '挑战', '同学', '友情', '独立', '自由', '激情', '音乐', '派对', '自我发现', '旅行', '青春困惑', '事业', '奋斗']):
return '适合年轻人'
elif any(keyword in all for keyword in ['深刻', '历史', '复杂', '政治', '犯罪', '悬疑', '惊悚', '战争', '社会', '心理', '人性', '暴力', '伦理', '辩论', '法律', '道德', '伦理困境', '剧情', '人生', '政治阴谋', '社会问题', '心理学', '犯罪调查', '战争历史', '权力斗争']):
return '适合成年观众'
elif any(keyword in all for keyword in ['科幻', '未来', '太空', '外星人', '机器人', '科技', '平行宇宙', '时间旅行', '人工智能', '异形', '末日', '未来战争', '宇宙探险', '克隆', '超能力', '超自然', '纳米技术', '赛博朋克', '量子力学', '虚拟现实', '星际旅行', '银河帝国', '时间悖论', '外太空']):
return '适合科幻迷'
elif any(keyword in all for keyword in ['喜剧', '搞笑', '幽默', '讽刺', '搞怪', '滑稽', '轻松', '欢乐', '恶搞', '反差', '荒诞', '讽刺社会', '黑色幽默', '欢乐时光', '喜剧片', '搞笑场景', '喜剧人物', '搞笑对白', '欢乐冒险', '笑声', '喜剧剧情', '滑稽人物', '荒谬情节']):
return '适合喜剧迷'
elif any(keyword in all for keyword in ['动画', '卡通', '动漫', '儿童', '幻想', '魔法', '冒险', '奇幻', '超自然', '童话', '传奇', '动物', '幻想世界', '英雄', '动画片', '魔幻冒险', '童年', '童趣', '卡通角色', '动漫角色', '梦幻', '动画奇观', '卡通片', '幻想故事']):
return '适合动画迷'
elif any(keyword in all for keyword in ['恐怖', '惊悚', '鬼怪', '血腥', '灵异', '恐惧', '惊骇', '恐怖片', '超自然', '灵异事件', '恐怖怪物', '黑暗', '恐怖杀手', '诡异', '鬼魂', '恐怖故事', '阴森', '恐怖电影', '黑暗力量', '恐怖氛围', '恐怖场景', '恐怖声音', '恐怖角色', '惊悚剧情']):
return '适合恐怖迷'
elif any(keyword in all for keyword in ['纪录片', '真实', '纪实', '历史', '社会', '生态', '文化', '科学', '自然', '人文', '探索', '实地', '采访', '深度', '记录', '观察', '紀錄', '纪实报道', '真实事件', '历史文献', '自然世界', '文化探索', '科学发现', '社会研究']):
return '适合纪录片爱好者'
elif any(keyword in all for keyword in ['历史', '战争', '古代', '帝国', '文明', '革命', '传奇', '古代故事', '历史事件', '历史人物', '文献', '古代文化', '战争历史', '历史背景', '古代传奇', '古文明']):
return '适合历史迷'
elif any(keyword in all for keyword in ['动作', '战斗', '追逐', '武打', '竞技', '爆破', '特技', '冒险', '英雄', '战争', '反派', '拳击', '枪战', '追击', '暴力', '激战', '动作片', '武术', '动作场面', '动作角色']):
return '适合动作迷'
elif any(keyword in all for keyword in ['音乐', '演唱', '演奏', '歌舞', '音乐剧', '音乐会', '音乐家', '乐队', '音乐史', '流行音乐', '古典音乐', '音乐作品', '音乐节', '歌曲', '作曲', '音乐表演']):
return '适合音乐迷'
elif any(keyword in all for keyword in ['冒险', '探险', '荒野', '挑战', '探索', '冒险故事', '冒险片', '野外', '生存', '冒险旅程', '冒险人物', '神秘', '古迹', '秘境', '探险队']):
return '适合冒险迷'
elif any(keyword in all for keyword in ['运动', '比赛', '体育', '竞技', '球类', '奖杯', '运动员', '运动会', '体育精神', '训练', '体育赛事', '比赛场面', '体育历史', '体育英雄', '体育电影', '运动纪录片']):
return '适合运动迷'
return '其他'
这个函数classify_movie
根据电影的简介和类型进行分类。详细说明如下:
-
提取电影简介和类型:
intro = row['简介'] types = row['类型']
intro
:获取当前行的简介内容。types
:获取当前行的类型内容。
-
合并简介和类型:
all = f"{intro}{types}"
- 将简介和类型合并成一个字符串。
-
检查合并字符串是否为字符串类型:
if isinstance(all, str):
-
根据关键词进行分类:
- 使用
if any(keyword in all for keyword in [...])
结构,检查合并字符串中是否包含特定关键词。 - 根据匹配的关键词返回相应的分类标签,如"适合家庭观影"、"适合年轻人"等。
- 使用
-
默认返回"其他":
return '其他'
- 如果没有匹配到任何关键词,则返回"其他"。
应用分类函数
# 应用分类函数
df['分类'] = df.apply(classify_movie, axis=1)
这行代码将classify_movie
函数应用于数据框的每一行,并将结果存储在新列分类
中。
分类统计
# 分类统计
category_counts = df['分类'].value_counts()
这行代码统计每个分类的数量,并存储在category_counts
变量中。
绘制改进后的饼图
plt.figure(figsize=(10, 7))
wedges, texts, autotexts = plt.pie(category_counts, labels=category_counts.index, autopct='%1.1f%%', startangle=140)
# 确保饼图是圆形的
plt.axis('equal')
# 设置标题
plt.title('电影分类分布')
# 为每个扇区添加注释
for wedge, label, count in zip(wedges, category_counts.index, category_counts):
angle = (wedge.theta2 - wedge.theta1) / 2. + wedge.theta1
x = np.cos(np.deg2rad(angle))
y = np.sin(np.deg2rad(angle))
horizontalalignment = {-1: 'right', 1: 'left'}[int(np.sign(x))]
connectionstyle = "angle,angleA=0,angleB={}".format(angle)
plt.annotate(f'{label}: {count}', xy=(x, y), xytext=(1.35*np.sign(x), 1.4*y),
horizontalalignment=horizontalalignment, fontsize=10,
arrowprops=dict(arrowstyle="->", connectionstyle=connectionstyle))
# 显示图表
plt.show()
这段代码绘制一个改进后的饼图:
-
设置图表大小:
plt.figure(figsize=(10, 7))
-
绘制饼图:
wedges, texts, autotexts = plt.pie(category_counts, labels=category_counts.index, autopct='%1.1f%%', startangle=140)
category_counts
:每个分类的数量。labels
:分类标签。autopct
:显示百分比。startangle
:起始角度。
-
确保饼图是圆形的:
plt.axis('equal')
-
设置标题:
plt.title('电影分类分布')
-
为每个扇区添加注释:
for wedge, label, count in zip(wedges, category_counts.index, category_counts): angle = (wedge.theta2 - wedge.theta1) / 2. + wedge.theta1 x = np.cos(np.deg2rad(angle)) y = np.sin(np.deg2rad(angle)) horizontalalignment = {-1: 'right', 1: 'left'}[int(np.sign(x))] connectionstyle = "angle,angleA=0,angleB={}".format(angle) plt.annotate(f'{label}: {count}', xy=(x, y), xytext=(1.35*np.sign(x), 1.4*y), horizontalalignment=horizontalalignment, fontsize=10, arrowprops=dict(arrowstyle="->", connectionstyle=connectionstyle))
- 计算每个扇区的中心角度,用于确定注释的位置。
- 使用
plt.annotate
在每个扇区附近添加注释,包括分类标签和数量。
-
显示图表:
plt.show()
创建一个字典存储每个类别下的电影列表并编号
# 创建一个字典存储每个类别下的电影列表并编号
category_movies = {}
for category in category_counts.index:
movies = df[df['分类'] == category]['电影名'].tolist()
category_movies[category] = {i+1: movie for i, movie in enumerate(movies)}
这段代码创建一个字典category_movies
,其中每个类别的键对应一个编号的电影列表:
-
初始化空字典:
category_movies = {}
-
遍历每个分类:
for category in category_counts.index:
-
获取每个分类下的电影列表:
movies = df[df['分类'] == category]['电影名'].tolist()
-
将电影列表编号并存储在字典中:
category_movies[category] = {i+1: movie for i, movie in enumerate(movies)}
打印每个类别下的电影列表并编号
# 打印每个类别下的电影列表并编号
for category, movies in category_movies.items():
print(f"\n{category}:")
for number, movie in movies.items():
print(f" {number}. {movie}")
这段代码打印每个分类下的电影列表,并为每个电影添加编号:
-
遍历每个分类和对应的电影列表:
for category, movies in category_movies.items():
-
打印分类名称:
print(f"\n{category}:")
-
打印每个电影的编号和名称:
for number, movie in movies.items(): print(f" {number}. {movie}")
这段代码主要完成了以下任务: