Kiggle电影数据分析与可视化(pandas)

Kiggle电影数据分析与可视化(pandas)

前言

本次项目展示了基于 5000+ 条电影数据,分别围绕电影市场、电影观众、电影发行方等多方面进行的各项数据分析。

数据清洗

1. 导入包

python 复制代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sn
import warnings
# 忽略警告
warnings.filterwarnings("ignore")
#导入词云包
from wordcloud import WordCloud,STOPWORDS,ImageColorGenerator 
%matplotlib inline

2. 导入数据

ini 复制代码
movie = pd.read_csv('tmdb_5000_movies.csv')
credits = pd.read_csv("tmdb_5000_credits.csv")
​
scss 复制代码
# 观察数据类型
movie.info()
credits.info()

根据info()信息,发现movies中 homepage runtime tagline 有缺失值,但是这些字段对于我们后期的分析无关,所以可以不做处理。

3. 去重

scss 复制代码
len(movie.id.unique()) 
-- 4803 与数据表长度对应 无重复值
​
// 或者
​
movie.duplicated().sum()
-- 0 无重复值
ini 复制代码
# 若有重复值,如下代码删除即可
movie.drop_duplicates(inplace=True)

4. 去空

由info()得知,没有空数据,所以无需处理

5. 规范数据

5.1 两表连接

将movie和credits通过共同列id进行连接

ini 复制代码
# 使用merge函数,movie左连接credits
movie_credits = movie.merge(credits,left_on = "id",right_on = "movie_id",how = "left")

5.2 读取json数据

观察数据,发现geners、keywords、cast列等都是json格式,对json数据进行处理

ini 复制代码
​
json_columns = ["genres","keywords","production_companies","production_countries","cast","crew"]
​
# 使用json.loads()函数对以上列进行读取
for column in json_columns:
    movie_credits[column] = movie_credits[column].apply(json.loads)
​

5.2 提取数据

根据上一步,我们已经将json数据类型转化为python对象,但是我们观察genres

name后面的值才是我们真正想要的类型,所以需要将数据提取出来

python 复制代码
# 定义一个提取函数
# 传入一个列,遍历列中的每一行,再遍历每一行中的每个字典,将字典中为name的key的value提取出来
​
def extract_name(column):
    # 此处用列表推导式,col将是列表的格式
    col = [[dic["name"] for dic in row] for row in column]
    return col
​
ini 复制代码
# 待提取的列
to_extract_col = ["genres","production_companies","production_countries"]
​
# 将原来列中的数据覆盖
for column in to_extract_col:
    movie_credits[column] = extract_name(movie_credits[column])
​
​
# 根据分析需求 cast 和 keywords列中含有多个value,我们只提取前几个
movie_credits['actors'] = [[dic["name"] for dic in row[0:4]] for row in movie_credits["cast"]] # 演员取前四个
movie_credits['keywords'] = [[dic["name"] for dic in row[0:5]] for row in movie_credits["keywords"]] # 关键字取前五
ini 复制代码
# 为了方便后续的分析,只保留genres中第一个值
movie_credits.genres = movie_credits.genres.str.get(0)
movie_credits.genres
css 复制代码
# 提取release_date中的年份
movie_credits['year'] = pd.to_datetime(movie_credits["release_date"]).apply(lambda x:x.year)
ini 复制代码
# 将我们想要的列拼接成一个新的表
data = movie_credits[["id","original_title","genres","keywords","budget","revenue","popularity","production_companies","production_countries","release_date","vote_average","vote_count","actors","director","year"]].dropna()
​
data.year = data.year.astype(int)

5.3 规范数据

ini 复制代码
# 重命名列
data.rename(columns={"original_title":"movieName"},inplace = True)
kotlin 复制代码
data.describe()
bash 复制代码
# 发现投票人数波动过大,并且评价人数太少的电影评分也不具备参考价值,筛选投票人数大于 40 的
# 上映时间跨度大,过早的电影对我们的分析没有参考价值,选取2000年后的数据
# 发现电影预算与票房的最小值为0,这些数据没有参考意义,应筛选掉
scss 复制代码
data.groupby("year")["id"].count()
# 2016年和2017年的数据量少,所以这两年的数据也不要
kotlin 复制代码
# 结合上述条件写出过滤语句
data = data[(data.year > 2000) & (data.year <2016) & (data.vote_count > 50) 
            & (data.budget * data.revenue * data.popularity * data.vote_average != 0)].reset_index(drop ="True")
​
diff 复制代码
data.shape
-- (1971,34) 
剩余1971条数据

可视化与数据分析

1. 从市场角度

1.1 对比是市面上各类型电影数量

ini 复制代码
# 更改字体
plt.rcParams['font.family']='Kaiti'
# 创建画布
plt.figure(figsize = (12,9))
# 分组聚合
genres = data['genres'].value_counts() # 按类型进行分组并计数
# 绘制横向柱状图
plt.barh(y = genres.index[::-1],
        width = genres.values[::-1],
        color = '#3c7f99')
​
plt.box(False) #不显示边框
​
plt.title(label = '各类型电影数量对比',
         fontsize = 32,
         weight = 'bold',
         color = 'white',
         backgroundcolor = '#c5b783',
         pad = 20) # 图与标题间的距离
​
plt.tick_params(labelsize = 16) # 刻度字体设置
​
plt.grid(axis = 'x', # 分割线
        linewidth = 0.5,# 线宽
        color = '#3c7f99')
​

由图中看出,目前市面上电影类型最多的Drama、Comedy、Action、Adventure等

1.2 对比每年利润最高的电影类型

ini 复制代码
plt.rcParams['font.family']='Kaiti'
plt.figure(figsize = (22,12))
​
# 对类型分组,且对revenue求和
genres_t = data.groupby('genres')["revenue"].sum()
​
# 绘制柱状图
plt.bar(genres_t.index, # y轴
        genres_t, # x轴
        color = '#3c7f99'
        )
plt.xlabel('类型', fontsize=30) # x轴标签
plt.ylabel('收入(亿美元)', fontsize=30) # y轴标签
​
# 标题设置
plt.title(label = '不同类型电影收入对比', 
         fontsize = 50,
         weight = 'bold',
         color = 'white',
         backgroundcolor = '#c5b783',
         pad = 30) 
​
# 刻度标签设置
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)

由图可知,在2000-2015年间,收入最高的电影类型的从大到小的顺序为:Action、Adventure、Comedy、Drama等

1.3 电影收入随年份变化

ini 复制代码
plt.rcParams['font.family']='Kaiti'
plt.figure(figsize = (12,9))
​
revenue_year_t = data.groupby("year")["revenue"].sum()
​
# 绘制折线图
plt.plot(revenue_year_t)
plt.ylabel("收入(百亿美元)",fontsize = 20)
plt.xlabel("年份",fontsize = 20)
plt.title(label = '电影收入逐年趋势',
         fontsize = 32,
         weight = 'bold',
         color = 'white',
         backgroundcolor = '#c5b783',
         pad = 20) # 图与标题间的距离
​

由图可知,电影收入呈逐年上涨趋势。但光看票房不看预算不准确,应该进一步去看ROI

1.4 ROI趋势

ini 复制代码
profit = data.groupby("year")[["budget","revenue"]].sum()
profit['roi'] = (profit.revenue - profit.budget) / profit.budget
profit
plt.figure(figsize = (12,9))
plt.plot(profit.roi)
plt.ylabel("ROI",fontsize = 20)
plt.xlabel("年份",fontsize = 20)
plt.title("ROI随年份变化曲线",
          fontsize = 32,
         weight = 'bold',
         color = 'white',
         backgroundcolor = '#c5b783',
         pad = 20
         )

由图可知,每年的投资回报率呈上涨趋势,电影市场向好。

1.5 影响票房的多种因素

1.5.1 电影票房与预算的关系
ini 复制代码
plt.scatter(data["budget"],data["revenue"],color='#3c7f99')
plt.xlabel('预算')
plt.ylabel('票房')
plt.title("预算与票房的相关性",
           fontsize = 25,
         weight = 'bold',
         color = 'white',
         backgroundcolor = '#c5b783',
         pad = 20)
ini 复制代码
# 计算相关系数
reference=pd.DataFrame({'budget':data["budget"],'revenue':data["revenue"]})
reference.corr()
​

相关系数为0.7,说明预算与票房之间相关性较强,预算越高,电影的票房越高

1.5.2 电影票房与评分的关系
ini 复制代码
plt.scatter(data["vote_average"],data["revenue"],color='#3c7f99')
plt.xlabel('评分')
plt.ylabel('票房')
plt.title("预算与票房的相关性",
           fontsize = 25,
         weight = 'bold',
         color = 'white',
         backgroundcolor = '#c5b783',
         pad = 20)
ini 复制代码
# 计算相关系数
reference=pd.DataFrame({'vote':data["vote_average"],'revenue':data["revenue"]})
reference.corr()

相关系数为0.2,说明评分与票房之间关联不大

1.6 档期对电影票房的影响

scss 复制代码
​
​
data["release_month"] = pd.to_datetime(data.release_date)
# data["release_month"].dtype
data["release_month"] = data["release_month"].dt.month
# data["release_month"]
​
# 平均每个月上映的电影数
release_month_num = data.groupby('release_month').count()['id']/15
​
​
release_month_num.plot(kind='bar',title='平均每月上映的电影数量(2000-2015)\n', figsize=(12,9));
​
plt.xlabel('月份')
plt.ylabel('数量')
plt.xticks(rotation=360)
ini 复制代码
revenue_month_revenue = data.groupby('release_month').sum()['revenue']/15
revenue_month_revenue.plot(kind = "bar",title='平均每月票房(2000-2015)', figsize=(12,9))
plt.xticks(rotation=360)
plt.title('平均每月票房(2000-2015)',
          fontsize = 32,
         weight = 'bold',
         color = 'white',
         backgroundcolor = '#c5b783',
         pad = 20)

由此可以看出,六月份上映的电影利润最高。

2. 从观众角度

2.1 电影风格随时间变化趋势

ini 复制代码
# 取出不重复的电影类型
listgenres=set()
for s in  data['genres'].str.split(','):
    listgenres=set().union(s,listgenres)
listgenres=list(listgenres)
​
​
for genre in listgenres:
   data[genre]=data['genres'].str.contains(genre).apply(lambda x:1 if x else 0)
   
genres_y=data.loc[:,listgenres]
​
genres_y.index=data['year']
​
genresx = genres_y.groupby('year').sum()     #groupby函数对数据集进行聚类运算 
genresx = genresx[['Drama','Comedy','Action','Adventure','Horror','Thriller','Crime','Animation']]
​
plt.rcParams['font.family']='Kaiti'
genresx.plot(figsize = (12,8))
plt.ylabel("数量",fontsize = 20)
plt.xlabel("年份",fontsize = 20)
plt.title('电影类型随时间变化',
                  fontsize = 32,
         weight = 'bold',
         color = 'white',
         backgroundcolor = '#c5b783',
         pad = 20)
plt.show()

电影类型的数量变化能够反映观众的口味变化,从图中可以看出,Drama、Comedy、Action类型依旧占领电影市场相当大的比重。

2.2 词云分析

ini 复制代码
# 关键词分析
# 利用关键字制作词云图
# 建立keywordlist列表
​
​
import matplotlib.colors as colors
​
​
keywordlist = []
for i in data['keywords']:
    keywordlist.append(i)
    keywordlist = list(keywordlist)
    keywordlist
​
# 把字符串列表连接成一个长字符串
lis = ''.join(str(keywordlist))
​
# # 使用空格替换中间多余的字符串''s'
# lis.replace(''s','')
​
# 自定义颜色函数
def randomcolor():
    colorArr = ['1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
    color ="#"+''.join([np.random.choice(colorArr) for i in range(6)])
    return color
color_list=[randomcolor() for i in range(20)]
​
# 生成词云
wc = WordCloud( background_color="white", # 背景颜色  
                max_words=2000,           # 词云显示的最大词数  
                max_font_size=100,        # 字体最大值  
                colormap = colors.ListedColormap(color_list))
​
# 根据字符串生成词云
wc.generate(lis)
plt.figure(figsize=(8,8))
# 以下代码显示图片  
plt.imshow(wc)  
plt.axis("off")  
plt.show()  
​

占比最重的关键字为loss、novel、relationship等

3. 从发行方角度

3.1 导演对电影票房的影响

ini 复制代码
director_revenue_avg.hist(bins=100,figsize=(5,4))
plt.title('导演平均票房',
          fontsize = 10,
         weight = 'bold',
         color = 'white',
         backgroundcolor = '#c5b783',
         pad = 10)
​

极少数的导演贡献了极高的票房

ini 复制代码
data.groupby("director").revenue.mean().sort_values().tail(10).plot(kind = "bar",figsize = (10,6))
plt.xticks(rotation=360)
                            # 标签旋转      标签距离坐标轴的距离
plt.ylabel("票房",fontsize = 15,rotation=360,labelpad = 20)
plt.ylabel("导演",fontsize = 15,labelpad = 20)
plt.title("导演票房分布", fontsize = 25,
         weight = 'bold',
         color = 'white',
         backgroundcolor = '#c5b783',
         pad = 20)
​

平均票房排名前十的导演,詹姆斯-卡梅隆位列第一

结论

综上分析看来,得出以下结论:

  1. 近年来电影市场前景向好,投资者们往往都能获得不错的收益
  2. 动作、冒险、戏剧、Drama四种类型的电影收益是最高的,且这四类影片依旧受观众追捧。
  3. 预算越高,往往能拍出更高质量的额电影,从而获得更高的票房;而观众评分则对票房的影响不大,例如有些文艺片的评分普遍较高,但电影受众却很小,容易出现叫好不叫座的现象。
  4. 每年的5、6、11、12月份的票房普遍高,避开寒暑期及十一黄金档,电影上映量不高,往往能收获不错的票房。
  5. 近年来上映的电影中 "loss"、"relationship"等关键词高频出现,说明电影主题的重点放在 "人" 上,更加关注人文精神。
  6. 导演对票房的贡献属于电影的长尾效应,极少数的导演贡献出超高的票房,名导效应有所加成。
相关推荐
Jay_2716 分钟前
python项目如何创建docker环境
开发语言·python·docker
老胖闲聊35 分钟前
Python Django完整教程与代码示例
数据库·python·django
爬虫程序猿39 分钟前
利用 Python 爬虫获取淘宝商品详情
开发语言·爬虫·python
noravinsc39 分钟前
django paramiko 跳转登录
后端·python·django
声声codeGrandMaster41 分钟前
Django之表格上传
后端·python·django
元直数字电路验证1 小时前
Python数据分析及可视化中常用的6个库及函数(一)
python·numpy
waterHBO1 小时前
一个小小的 flask app, 几个小工具,拼凑一下
javascript·vscode·python·flask·web app·agent mode·vibe coding
智商不够_熬夜来凑1 小时前
anaconda安装playwright
开发语言·python
溜溜刘@♞1 小时前
python变量
python
丁值心1 小时前
6.01打卡
开发语言·人工智能·python·深度学习·机器学习