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. 导演对票房的贡献属于电影的长尾效应,极少数的导演贡献出超高的票房,名导效应有所加成。
相关推荐
API快乐传递者29 分钟前
除了网页标题,还能用爬虫抓取哪些信息?
开发语言·爬虫·python
豌豆花下猫37 分钟前
REST API 已经 25 岁了:它是如何形成的,将来可能会怎样?
后端·python·ai
平头哥在等你2 小时前
Python中的正则表达式教程
python·正则表达式
Best_Me072 小时前
如何在Pycharm的终端里进入自己的环境
ide·python·pycharm
好看资源平台3 小时前
爬虫开发工具与环境搭建——环境配置
爬虫·python
大G哥3 小时前
python 数据类型----可变数据类型
linux·服务器·开发语言·前端·python
赛丽曼4 小时前
Python中的HTML
python·html
数模竞赛Paid answer4 小时前
2023年MathorCup数学建模B题城市轨道交通列车时刻表优化问题解题全过程文档加程序
数学建模·数据分析·mathorcup
luky!4 小时前
算法--解决熄灯问题
python·算法
深度学习lover4 小时前
<项目代码>YOLOv8 番茄识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·番茄识别