数据:summer_movies | summer_movie_genres
流程
graph LR
A[1导入库] --> B[2导入数据]
B --> C[3数据探索与处理]
C --> D[4数据可视化]
D --> E[5特征工程]
E --> F[6模型训练与评估]
F --> G[7预测新数据]
数据集说明
以下是两个数据文件的详细说明:
文件1:summer_movies.csv
数据预览:
tconst | title_type | primary_title | original_title | year | runtime_minutes | genres | simple_title | average_rating | num_votes |
---|---|---|---|---|---|---|---|---|---|
tt0011462 | movie | Midsummer Madness | Midsummer Madness | 1920.0 | 60.0 | Drama | midsummer madness | 7.4 | 19 |
tt0026714 | movie | A Midsummer Night's Dream | A Midsummer Night's Dream | 1935.0 | 133.0 | Comedy,Fantasy,Romance | a midsummer nights dream | 6.8 | 3931 |
tt0033864 | movie | The Teachers on Summer Vacation | Magistrarna på sommarlov | 1941.0 | 86.0 | Comedy | the teachers on summer vacation | 5.5 | 78 |
tt0037325 | movie | Summer Storm | Summer Storm | 1944.0 | 106.0 | Crime,Drama,Film-Noir | summer storm | 6.6 | 688 |
tt0038406 | movie | Centennial Summer | Centennial Summer | 1946.0 | 102.0 | History,Music,Romance | centennial summer | 6.1 | 431 |
列名及解释:
- tconst: 电影的唯一标识符(通常用于与其他数据集关联)。
- title_type: 电影类型(例如 "movie" 表示电影)。
- primary_title: 电影的主要标题。
- original_title: 电影的原始标题(可能与主要标题相同)。
- year: 电影的上映年份。
- runtime_minutes: 电影的时长(以分钟为单位)。
- genres: 电影的类型(多个类型之间用逗号分隔)。
- simple_title: 电影标题的简化版本(用于便于处理或查找)。
- average_rating: 电影的平均评分。
- num_votes: 给电影评分的总人数。
文件2:summer_movie_genres.csv
数据预览:
tconst | genres |
---|---|
tt0011462 | Drama |
tt0026714 | Comedy |
tt0026714 | Fantasy |
tt0026714 | Romance |
tt0033864 | Comedy |
列名及解释:
- tconst: 电影的唯一标识符(与
summer_movies.csv
中的tconst
对应,用于关联电影类型与其他电影信息)。 - genres: 电影的单一类型(每一行仅表示一个类型,如果电影属于多个类型,则会有多行数据)。
总结
summer_movies.csv
: 包含电影的详细信息,如标题、上映年份、时长、评分等。summer_movie_genres.csv
: 包含电影的类型信息,每个类型占一行,适合与主数据集进行合并。
这些数据可以通过tconst
字段进行关联,以便进一步的分析和处理。
7步分析法
第1步:导入库
首先,我们需要导入必要的Python库,如pandas
、matplotlib
和scikit-learn
等。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
第2步:导入数据
然后,我们导入您提供的两个CSV文件。
movies = pd.read_csv('data/IMDb Summer Movies Data/summer_movies.csv')
genres = pd.read_csv('data/IMDb Summer Movies Data/summer_movie_genres.csv')
# 查看前几行数据
print(movies.head())
print(genres.head())
tconst title_type primary_title \
0 tt0011462 movie Midsummer Madness
1 tt0026714 movie A Midsummer Night's Dream
2 tt0033864 movie The Teachers on Summer Vacation
3 tt0037325 movie Summer Storm
4 tt0038406 movie Centennial Summer
original_title year runtime_minutes genres \
0 Midsummer Madness 1920.0 60.0 Drama
1 A Midsummer Night's Dream 1935.0 133.0 Comedy,Fantasy,Romance
2 Magistrarna på sommarlov 1941.0 86.0 Comedy
3 Summer Storm 1944.0 106.0 Crime,Drama,Film-Noir
4 Centennial Summer 1946.0 102.0 History,Music,Romance
simple_title average_rating num_votes
0 midsummer madness 7.4 19
1 a midsummer nights dream 6.8 3931
2 the teachers on summer vacation 5.5 78
3 summer storm 6.6 688
4 centennial summer 6.1 431
tconst genres
0 tt0011462 Drama
1 tt0026714 Comedy
2 tt0026714 Fantasy
3 tt0026714 Romance
4 tt0033864 Comedy
第3步:数据探索与处理
在这一步中,进行数据的初步探索,包括检查缺失值、数据类型、合并两个数据集等操作。
# 处理缺失值(如有)
movies = movies.dropna()
# 合并数据集并去掉重复的列
genres_unique = genres.drop_duplicates()
merged_data = pd.merge(movies, genres_unique, on='tconst', how='inner')
merged_data = merged_data.rename(columns={'genres_x': 'genres'}).drop(columns=['genres_y'])
# 如果存在多类型电影,合并类型为字符串
merged_data = merged_data.groupby(['tconst', 'primary_title', 'year', 'runtime_minutes', 'average_rating', 'num_votes'])['genres'].apply(lambda x: ','.join(set(x))).reset_index()
# 检查数据结构
print(merged_data.head())
tconst primary_title year runtime_minutes \
0 tt0011462 Midsummer Madness 1920.0 60.0
1 tt0026714 A Midsummer Night's Dream 1935.0 133.0
2 tt0033864 The Teachers on Summer Vacation 1941.0 86.0
3 tt0037325 Summer Storm 1944.0 106.0
4 tt0038406 Centennial Summer 1946.0 102.0
average_rating num_votes genres
0 7.4 19 Drama
1 6.8 3931 Comedy,Fantasy,Romance
2 5.5 78 Comedy
3 6.6 688 Crime,Drama,Film-Noir
4 6.1 431 History,Music,Romance
第4步:数据可视化
通过可视化来进一步理解数据,比如不同类型电影的平均评分和平均时长。
plt.rcParams['font.family'] = 'Noto Sans CJK SC'
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 1. 不同类型电影的平均评分 (仅显示前十条)
plt.figure(figsize=(10, 6))
top_10_genres = merged_data.groupby('genres')['average_rating'].mean().sort_values(ascending=False).head(10)
sns.barplot(x=top_10_genres.index, y=top_10_genres.values, errorbar=None)
plt.title('前十类型的平均评分')
plt.xlabel('类型')
plt.ylabel('平均评分')
plt.xticks(rotation=45)
plt.show()
# 2. 不同年份的电影数量
plt.figure(figsize=(10, 6))
sns.histplot(data=merged_data, x='year', bins=30)
plt.title('Number of Movies by Year')
plt.xlabel('Year')
plt.ylabel('Number of Movies')
plt.show()
# 3. 电影时长的分布
plt.figure(figsize=(10, 6))
sns.histplot(data=merged_data, x='runtime_minutes', bins=30, kde=True)
plt.title('Distribution of Movie Runtimes')
plt.xlabel('Runtime (minutes)')
plt.ylabel('Frequency')
plt.show()
# 4. 电影评分与票数的关系
plt.figure(figsize=(10, 6))
sns.scatterplot(x='num_votes', y='average_rating', data=merged_data)
plt.title('Relationship between Number of Votes and Average Rating')
plt.xlabel('Number of Votes')
plt.ylabel('Average Rating')
plt.show()
# 5. 每种类型电影的平均时长 (仅显示前十条)
plt.figure(figsize=(10, 6))
top_10_runtime_genres = merged_data.groupby('genres')['runtime_minutes'].mean().sort_values(ascending=False).head(10)
sns.barplot(x=top_10_runtime_genres.index, y=top_10_runtime_genres.values, errorbar=None)
plt.title('前十类型的平均时长')
plt.xlabel('类型')
plt.ylabel('平均时长 (分钟)')
plt.xticks(rotation=45)
plt.show()
# 6. 各类型电影的数量分布 (仅显示前十条)
plt.figure(figsize=(10, 6))
top_10_count_genres = merged_data['genres'].value_counts().head(10)
sns.barplot(x=top_10_count_genres.index, y=top_10_count_genres.values, errorbar=None)
plt.title('前十类型的电影数量')
plt.xlabel('类型')
plt.ylabel('电影数量')
plt.xticks(rotation=45)
plt.show()
# 7. 不同评分区间的电影数量
plt.figure(figsize=(10, 6))
sns.histplot(data=merged_data, x='average_rating', bins=20)
plt.title('Distribution of Average Ratings')
plt.xlabel('Average Rating')
plt.ylabel('Number of Movies')
plt.show()
第5步:特征工程
特征工程包括对分类变量进行编码,以及准备模型训练所需的特征和目标变量。
# 将 genres 转换为数值变量(多标签二值化)
genre_dummies = merged_data['genres'].str.get_dummies(sep=',')
merged_data = pd.concat([merged_data, genre_dummies], axis=1)
# 删除重复的列
merged_data = merged_data.loc[:, ~merged_data.columns.duplicated()]
# 显示新的数据集信息
print("特征工程后的数据集列名:", merged_data.columns.tolist())
print("特征工程后的数据集前几行:")
print(merged_data.head())
# 选择特征和目标变量
X = merged_data.drop(['tconst', 'primary_title', 'genres', 'average_rating'], axis=1)
y = merged_data['average_rating']
# 输出数据集形状和列信息
print("特征矩阵 X 的形状:", X.shape)
print("目标变量 y 的形状:", y.shape)
特征工程后的数据集列名: ['tconst', 'primary_title', 'year', 'runtime_minutes', 'average_rating', 'num_votes', 'genres', 'Action', 'Adventure', 'Animation', 'Biography', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Family', 'Fantasy', 'Film-Noir', 'History', 'Horror', 'Music', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Short', 'Sport', 'Talk-Show', 'Thriller', 'War', 'Western']
特征工程后的数据集前几行:
tconst primary_title year runtime_minutes \
0 tt0011462 Midsummer Madness 1920.0 60.0
1 tt0026714 A Midsummer Night's Dream 1935.0 133.0
2 tt0033864 The Teachers on Summer Vacation 1941.0 86.0
3 tt0037325 Summer Storm 1944.0 106.0
4 tt0038406 Centennial Summer 1946.0 102.0
average_rating num_votes genres Action Adventure \
0 7.4 19 Drama 0 0
1 6.8 3931 Comedy,Fantasy,Romance 0 0
2 5.5 78 Comedy 0 0
3 6.6 688 Crime,Drama,Film-Noir 0 0
4 6.1 431 History,Music,Romance 0 0
Animation ... Musical Mystery Romance Sci-Fi Short Sport Talk-Show \
0 0 ... 0 0 0 0 0 0 0
1 0 ... 0 0 1 0 0 0 0
2 0 ... 0 0 0 0 0 0 0
3 0 ... 0 0 0 0 0 0 0
4 0 ... 0 0 1 0 0 0 0
Thriller War Western
0 0 0 0
1 0 0 0
2 0 0 0
3 0 0 0
4 0 0 0
[5 rows x 31 columns]
特征矩阵 X 的形状: (837, 27)
目标变量 y 的形状: (837,)
第6步:模型训练与评估
选择一个回归模型进行训练,并评估模型性能。
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练随机森林回归模型
model = RandomForestRegressor()
model.fit(X_train, y_train)
# 预测并评估模型
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
# 输出评估结果 (中文)
print(f"模型的均方误差 (MSE): {mse:.2f}")
print(f"模型的 R^2 评分: {model.score(X_test, y_test):.2f}")
print(X.columns)
模型的均方误差 (MSE): 1.37
模型的 R^2 评分: 0.10
Index(['year', 'runtime_minutes', 'num_votes', 'Action', 'Adventure',
'Animation', 'Biography', 'Comedy', 'Crime', 'Documentary', 'Drama',
'Family', 'Fantasy', 'Film-Noir', 'History', 'Horror', 'Music',
'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Short', 'Sport',
'Talk-Show', 'Thriller', 'War', 'Western'],
dtype='object')
第7步:预测新数据
最后,我们可以使用训练好的模型来预测新的电影数据。
# 假设 X 是训练数据集的 DataFrame,并且包含了所有需要的特征
# 确保 new_movie 字典包含所有特征,并且顺序与 X.columns 一致
new_movie = {
'year': 2024, # 年份
'runtime_minutes': 120, # 电影时长(分钟)
'num_votes': 1500, # 投票数量
'Action': 0, # 动作片
'Adventure': 0, # 冒险片
'Animation': 0, # 动画片
'Biography': 0, # 传记片
'Comedy': 0, # 喜剧片
'Crime': 0, # 犯罪片
'Documentary': 0, # 纪录片
'Drama': 1, # 剧情片
'Family': 0, # 家庭片
'Fantasy': 0, # 奇幻片
'Film-Noir': 0, # 黑色电影
'History': 0, # 历史片
'Horror': 0, # 恐怖片
'Music': 0, # 音乐片
'Musical': 0, # 音乐剧
'Mystery': 0, # 悬疑片
'Romance': 0, # 爱情片
'Sci-Fi': 0, # 科幻片
'Short': 0, # 短片
'Sport': 0, # 体育片
'Talk-Show': 0, # 脱口秀
'Thriller': 0, # 惊悚片
'War': 0, # 战争片
'Western': 0 # 西部片
}
# 创建新的 DataFrame,确保列的顺序与 X.columns 一致
new_movie_df = pd.DataFrame([new_movie], columns=X.columns)
# 预测新数据的评分
predicted_rating = model.predict(new_movie_df)
print(f'预测的平均评分为: {predicted_rating[0]:.2f}')
预测的平均评分为: 6.04
原创文章,作者:曾确令,如若转载,请注明出处:https://www.zengqueling.com/psjfxbismd/