研究问题:如何根据电影上映前的一些信息来预测出该电影的票房。
数据来源
数据主要是电影数据库中的 7000 多部过去电影的元数据。提供的数据信息包括演员,工作人员,情节关键词,预算,海报,发布日期,语言,制作公司和国家等。
数据导入
还是之前一模一样的操作
#数据导入
import pandas as pd
df = pd.read_csv("https://labfile.oss.aliyuncs.com/courses/1363/TMDB.csv")
df.head()
#数据查看
df.shape
df.info()
df.describe()
df.describe(include=['O'])
#查看一下票房前10的电影
df.sort_values(by='revenue', ascending=False).head(10)[
['title', 'revenue', 'release_date']]
数据预处理
数据预处理:数据清洗+填充空缺值等
上映时间
release_date为电影的上映时间列,对该列进行处理。将时间中的年、月、日这些信息都分别提取出来。
def date_features(df):
df['release_date'] = pd.to_datetime(df['release_date']) # 转换为时间戳
df['release_year'] = df['release_date'].dt.year # 提取年
df['release_month'] = df['release_date'].dt.month # 提取月
df['release_day'] = df['release_date'].dt.day # 提取日
df['release_quarter'] = df['release_date'].dt.quarter # 提取季度
return df
df = date_features(df)
df['release_year'].head()
检查是否存在异常值,即电影上映时间超过 2019 年,因为收集的数据是 2019 年之前的。
import numpy as np
# 查看大于 2019 的数据
df['release_year'].iloc[np.where(df['release_year'] > 2019)][:10]
#存在异常值,需要处理。大于2019的减去100
df['release_year'] = np.where(
df['release_year'] > 2019, df['release_year']-100, df['release_year'])
df['release_year'].iloc[np.where(df['release_year'] > 2019)][:10]
#已经没有大于2019的了
cols = ['release_year', 'release_month',
'release_day']
df[cols].isnull().sum()
#再查看日期列是否有缺失值,结果显示没有
#其他列还是存在着空值情况的
显示票房随时间变化,即每月的票房分布。进行月对比
#显示每个月的平均电影票房
from matplotlib import pyplot as plt
%matplotlib inline
fig = plt.figure(figsize=(14, 4))
df.groupby('release_month').agg('mean')['revenue'].plot(kind='bar', rot=0)
plt.ylabel('Revenue (100 million dollars)')
#由图可以看到,电影的上映时间主要集中在 6 月和 12 月。这可能的原因是这两段时间都是假期。
得到图表后应该给出合适的结论
#显示每年的电影平均票房数
release_year_mean_data = df.groupby(['release_year'])['revenue'].mean()
fig = plt.figure(figsize=(14,5))
plt.plot(release_year_mean_data)
plt.ylabel('Mean revenue value')
plt.title('Mean revenue Over Years')
#从上图可以看到,电影的每年平均票房都是逐年递增的,这可能跟我们的经济增长有关,因为人们越来越有钱了,花费在精神上的消费比例也越来越大了。
#每次做出图后,最好给一个结论
和上面的代码类似
#电影时长与年份的折线图
release_year_mean_data = df.groupby(['release_year'])['runtime'].mean()
fig = plt.figure(figsize=(14, 5)) # 设置画布大小
plt.plot(release_year_mean_data)
plt.ylabel('Mean popularity value') # 设置 y 轴的标签
plt.title('Mean popularity Over Years') # 设置标题
#从上图中可以发现,在 1980 年之前,电影的平均时长都是不定的,而 1980 年之后,趋向于稳定,差不多是 100 多分钟。
收藏集
将该列的中的name提取出来,并统计空缺
#先打印前5列进行观察
#enumerate在字典上是枚举、列举的意思.利用它可以同时获得索引和值
#如果对一个列表,既要遍历索引又要遍历元素时,用它
for i, e in enumerate(df['belongs_to_collection'][:5]):
print(i, e)
print(type(e))
#通过判断该列的值是否是字符串来判断是否存在值或为空值。
df['belongs_to_collection'].apply(
lambda x: 1 if type(x) == str else 0).value_counts()
#在 3000 份数据中,该列的缺失值就有 2396。
#从该列中提取 name 属性。且创建一列保存是否缺失。
df['collection_name'] = df['belongs_to_collection'].apply(
lambda x: eval(x)[0]['name'] if type(x) == str else 0)
df['has_collection'] = df['belongs_to_collection'].apply(
lambda x: 1 if type(x) == str else 0)
df[['collection_name', 'has_collection']].head()
电影类型
同上面,处理genres 列
for i, e in enumerate(df['genres'][:5]):
print(i, e)
#先提取类型名
list_of_genres = list(df['genres'].apply(lambda x:[i['name'] for i in eval(x)] if type(x) == str else []).values)
list_of_genres[:5]
#统计类型的数据
from collections import Counter
most_common_genres = Counter(
[i for j in list_of_genres for i in j]).most_common()
most_common_genres
#绘制图片
fig = plt.figure(figsize=(10, 6))
data = dict(most_common_genres)
names = list(data.keys())
values = list(data.values())
#排序做柱状图
plt.barh(sorted(range(len(data)), reverse=True),
values, tick_label=names, color='teal')
plt.xlabel('Count')
plt.title('Movie Genre Count')
plt.show()
词云图
#先安装 词云库 wordcloud
!pip install wordcloud
from wordcloud import WordCloud
plt.figure(figsize=(12, 8))
text = ' '.join([i for j in list_of_genres for i in j])
# 设置参数
wordcloud = WordCloud(max_font_size=None, background_color='white', collocations=False,
width=1200, height=1000).generate(text)
plt.imshow(wordcloud)
plt.title('Top genres')
plt.axis("off")
plt.show()
将类型展开,类似One-Hot 编码
df['num_genres'] = df['genres'].apply(
lambda x: len(eval(x)) if type(x) == str else 0)
df['all_genres'] = df['genres'].apply(lambda x: ' '.join(
sorted([i['name'] for i in eval(x)])) if type(x) == str else '')
top_genres = [m[0] for m in Counter(
[i for j in list_of_genres for i in j]).most_common(15)]
for g in top_genres:
df['genre_' + g] = df['all_genres'].apply(lambda x: 1 if g in x else 0)
cols = [i for i in df.columns if 'genre_' in