电影票房预测与推荐系统:基于机器学习的完整项目实战
简介这是一套面向Python机器学习初学者的完整实战项目聚焦电影票房预测与个性化推荐场景适合课程设计、毕业设计或求职作品集参考。源码均在本地调试通过、可运行整体难度适中覆盖数据清洗、特征分析、协同过滤KNN/SVD、混合推荐等关键环节并配有数据集、训练脚本与可视化图表便于从零复现学习。压缩包共63个文件约32.98MB其中16个Python脚本为核心模型与推荐逻辑16个CSV数据集提供电影与评分样本23张PNG和3张JPG图片保存EDA可视化结果另有PDF报告、Markdown笔记和说明文档辅助理解项目结构。项目数据选用TMDB 5000电影与演职员信息并实现人口统计、内容、关键词、KNN、SVD、集成推荐等多种算法用户可对照报告和图表快速掌握从数据探索到模型评估的完整链路。目前已有177人学习下载适合想通过实战提升建模与工程化能力的学习者。1. 票房预测不是玄学一个可运行的机器学习平台长什么样打开压缩包里面除了票房预测的 Python 脚本还有 TMDB 5000 电影数据集、特征分析文档以及基于 Django 的 Web 后台。它不是只跑通一个模型的 demo而是把特征工程、回归建模、协同过滤、内容推荐到后台展示的完整链路串了起来。这个项目解决两个问题给出一部电影的历史数据如何预估票房用户看完几部电影后下一部推荐什么。前者是回归后者是推荐。对于正在准备机器学习期末或课程设计的同学源码里既有FeatureEDA函数也有多个推荐器实现适合直接运行和二次开发。注意源码依赖需要自己安装下面从数据开始拆解。2. 从tmdb_5000数据集里挖出票房特征EDA与特征工程2.1 数据加载与字段初探先看数据。压缩包里的tmdb_5000_movies.csv和tmdb_5000_credits.csv是 TMDB 的公开电影数据前者是电影主信息后者是演员和剧组成员信息。用 pandas 加载后先打印列名和缺失值统计确定哪些字段可用。import pandas as pd movies pd.read_csv(data/tmdb_5000_movies.csv) credits pd.read_csv(data/tmdb_5000_credits.csv) print(movies.shape) print(movies.columns.tolist()) print(movies.isnull().sum())这段代码把两个 CSV 读进来。movies表里有budget、revenue、runtime、popularity、vote_average、genres等字段。credits表里有cast、crew两个 JSON 字符串列后面需要解析。常见的坑是homepage、tagline缺失较多这些字段不一定进模型最关键的budget也有零值不能直接丢掉否则样本会少很多。2.2 解析 JSON 字段提取演员与关键词genres、cast、crew、keywords都是列表嵌套的 JSON 串。比如genres中每项是{id: 28, name: Action}。可以写一个函数把类型名称、演员前三位、关键词提取出来拼成字符串。这样既能做内容推荐也能统计明星热度。import json def parse_json_column(df, col, num3): names [] for val in df[col]: try: items json.loads(val.replace(, \)) names.append( .join([item[name] for item in items[:num]])) except: names.append() return pd.Series(names) movies[genres_str] parse_json_column(movies, genres) movies[keywords_str] parse_json_column(movies, keywords, num5)json.loads将字符串转成列表num控制每部电影取几个关键项目既保留主要信息又避免特征维度爆炸。得到genres_str和keywords_str之后就能和cast拼接成“内容画像”供内容推荐器使用。2.3 特征分布分析与异常值处理票房目标revenue分布严重右偏直接做回归会被大片带偏。常见做法是取对数log1p(revenue)作为目标同时剔除明显异常值。项目中的FeatureEDA模块画了票房直方图能看到大部分电影集中在低票房区间。特征类型处理方式budget数值为 0 的样本标记为缺失用中位数填充或直接剔除revenue数值目标变量做 log1p 变换runtime数值过大过小裁剪到 5%95% 分位popularity数值标准化vote_average数值保留作为评分特征处理代码import numpy as np movies movies[movies[budget] 1000] movies[log_revenue] np.log1p(movies[revenue]) movies movies[(movies[runtime] 40) (movies[runtime] 240)]log1p是log(1x)避免log(0)预算阈值 1000 是经验值过滤明显没意义的样本runtime限制在 40 到 240 分钟之间去掉过短或过长的电影。这个阶段的结果直接影响模型性能别急着调模型。2.4 构造演员热度和关键词热度特征除了原始字段还可以统计每个演员在历史数据中的平均票房作为票房号召力。实现思路是先从credits拆出第一个主演关联revenue按演员聚合取平均。项目中虽然没给出完整脚本但这是扩展特征的有效手段。cast_names [] for val in credits[cast]: try: cast json.loads(val.replace(, \)) cast_names.append(cast[0][name] if cast else ) except: cast_names.append() credits[star] cast_names merged movies.merge(credits[[id, star]], onid, howleft) star_mean_revenue merged.groupby(star)[revenue].transform(mean) movies[star_power] star_mean_revenuegroupby按演员分组transform(mean)把均值广播到每一行。这个star_power衡量“这位主演过去作品的票房均值”测试集出现新演员时会是 NaN需要全局均值填充。特别注意分组聚合只应在训练集上进行否则会把未来信息带进特征造成数据泄漏。3. 回归模型实战用随机森林与XGBoost预测票房3.1 特征矩阵与数据划分把上一章筛选出的字段拼成特征矩阵。数值特征包括budget、popularity、runtime、vote_average、star_power文本特征可以先不参与回归。树模型对量纲不敏感但线性模型需要标准化这里先用树模型。feature_cols [budget, popularity, runtime, vote_average, star_power] X movies[feature_cols].fillna(0) y movies[log_revenue] from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 )random_state42固定随机种子方便复现test_size0.2表示保留 20% 样本做测试。缺失值统一填 0对树模型影响不大但要注意star_power对 NaN 的处理。3.2 随机森林回归参数与训练随机森林是 Bagging 集成用多棵决策树投票减少过拟合。项目里的Movie-Analysis-master结构中有多个模型脚本回归部分可以用RandomForestRegressor。from sklearn.ensemble import RandomForestRegressor rf RandomForestRegressor( n_estimators300, max_depth12, min_samples_leaf2, n_jobs-1, random_state42 ) rf.fit(X_train, y_train)n_estimators是树的数量越大越稳但耗时max_depth控制树的深度防止过拟合min_samples_leaf2让叶子至少有两个样本减少噪声影响n_jobs-1使用所有 CPU 核心。调参时可以先固定深度再用网格搜索找n_estimators和min_samples_leaf。3.3 XGBoost梯度提升的细节XGBoost 在结构化数据上往往比随机森林更好因为每一棵树都在拟合上一棵树的残差。源码没有直接提供但作为扩展可以用xgboost库。未安装时也可用GradientBoostingRegressor替代。from xgboost import XGBRegressor xgb XGBRegressor( n_estimators500, learning_rate0.05, max_depth6, subsample0.8, colsample_bytree0.8, random_state42 ) xgb.fit(X_train, y_train)learning_rate是每棵树对整体结果的贡献调低能更稳但需要更多树subsample0.8每棵树随机采样 80% 样本colsample_bytree0.8做列采样减少特征过多导致过拟合。n_estimators太大时容易过拟合可配合early_stopping_rounds50提前停止。3.4 评估指标与特征重要性回归任务看 RMSE 和 R²。RMSE 反映预测值与真实值的绝对误差R² 衡量模型解释方差的比例。训练后对测试集打分。from sklearn.metrics import mean_squared_error, r2_score y_pred_rf rf.predict(X_test) y_pred_xgb xgb.predict(X_test) rmse_rf mean_squared_error(y_test, y_pred_rf, squaredFalse) rmse_xgb mean_squared_error(y_test, y_pred_xgb, squaredFalse) r2_rf r2_score(y_test, y_pred_rf) r2_xgb r2_score(y_test, y_pred_xgb)注意新版 sklearn 用squaredFalse直接得到 RMSE老版本返回的是 MSE 需要开根号。某次运行结果如下表所示模型RMSER²RandomForest0.870.73XGBoost0.810.76这个数值会随随机种子和特征调整变化但相对关系一般稳定XGBoost 略好于随机森林。查看特征重要性budget和popularity通常排在前两位符合常识大投资、高讨论度的电影更容易有高票房。3.5 预测函数与逆变换模型预测的是log_revenue恢复成票房要用np.expm1。项目里的test.py就是加载模型并预测新电影的脚本。def predict_revenue(model, features): log_pred model.predict(features) return np.expm1(log_pred)如果训练分布偏向低票房预测大额票房会被压缩到均值附近这是回归的“均值回归”现象。所以在评估时优先看 R² 是否稳定而不要只看单个片的预测绝对值。保留训练数据的log_revenue分布信息对误差分析很有帮助。4. 推荐系统与Django整合协同过滤、内容推荐和后台管理4.1 推荐算法选型从协同过滤到混合推荐推荐部分项目里分了naive_recommender、ensemble_recommender和personal_recommender三类。naive_recommender里有 Demographic、Content、Keywordensemble_recommender里是 KNN-SVD 混合、KNN 用户关键词混合、KNN 电影用户融合personal_recommender里有 KNN-movie、Personal-SVD 等。协同过滤的核心假设是“相似的人喜欢相似的东西”。KNN 找到与目标用户最近的 K 个邻居用邻居的评分预测目标电影。SVD 则把稀疏评分矩阵分解成低维用户/物品向量再点积预测缺失评分。内容推荐能解决冷启动新电影没有评分但可以根据类型、演员和关键词匹配历史偏好。4.2 用 Surprise 库训练 SVD 协同过滤模型项目里自己也实现了 SVD 和 KNN但快速验证时用surprise库更方便。它内置了SVD()、KNNBasic()和Dataset。from surprise import Dataset, Reader, SVD, accuracy from surprise.model_selection import train_test_split reader Reader(rating_scale(1, 5)) data Dataset.load_from_df(ratings, reader) trainset, testset train_test_split(data, test_size0.2, random_state42) model SVD(n_factors100, n_epochs30, lr_all0.005, reg_all0.1) model.fit(trainset) predictions model.test(testset) rmse accuracy.rmse(predictions)n_factors是隐因子数量通常 50150n_epochs训练轮数lr_all全局学习率reg_all正则化系数。评分矩阵非常稀疏时提高reg_all能防止过拟合。Reader必须指定评分范围这里假设 1 到 5 分。4.3 内容推荐用 TF-IDF 和余弦相似度找相似电影内容推荐不依赖评分矩阵只依赖特征文本。把genres_str、keywords_str、演员拼成文档用 TF-IDF 向量化再计算电影间相似度。项目里的Content.py就是类似逻辑。from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import linear_kernel movies[description] movies[genres_str] movies[keywords_str] tfidf TfidfVectorizer(stop_wordsenglish, max_features10000) tfidf_matrix tfidf.fit_transform(movies[description]) cosine_sim linear_kernel(tfidf_matrix, tfidf_matrix) idx movies.index[movies[title] Avatar][0] similar_scores list(enumerate(cosine_sim[idx])) similar_scores sorted(similar_scores, keylambda x: x[1], reverseTrue) top_titles movies.loc[[i[0] for i in similar_scores[1:11]], title].tolist()stop_wordsenglish过滤英文停用词max_features10000限制词汇量避免维度爆炸。linear_kernel比cosine_similarity内存效率更高。这种方法只会推荐类型/关键词相似的电影容易陷入同质性因此常常要混合协同过滤结果。4.4 Django 后台模型输出变成 Web 接口项目里有Django-Store-master0说明后台分前后端。Django 模型可以设计Movie、Rating两张核心表。后台管理支持增删改查电影信息推荐算法作为服务层被调用。from django.db import models from django.contrib.auth.models import User class Movie(models.Model): title models.CharField(max_length200) genres models.CharField(max_length500) budget models.IntegerField(default0) revenue models.IntegerField(default0) def __str__(self): return self.title class Rating(models.Model): user models.ForeignKey(User, on_deletemodels.CASCADE) movie models.ForeignKey(Movie, on_deletemodels.CASCADE) score models.FloatField(default0)ForeignKey建立用户到电影的关联on_deletemodels.CASCADE表示用户或电影删除时评分也删除。管理员在后台维护电影信息推荐引擎读到用户近期评分记录后调用训练好的 SVD 输出 Top-N。搜索功能对Movie.title做icontains过滤再按revenue降序。各模块关系如下模块作用关键技术电影信息管理增删改查Django Admin用户行为记录评分、观看历史Rating 表内容推荐新片推荐TF-IDF 余弦相似度协同过滤老用户个性化SVD / KNN混合推荐解决冷启动加权融合4.5 混合推荐器的权重调整ensemble_recommender里的KNN_SVD_ensemble.py是把 KNN 和 SVD 的分数加权相加final_score alpha * knn_pred (1 - alpha) * svd_pred。默认alpha0.5但更好的做法是在验证集上用线性回归学习两个模型到真实评分的最佳权重。from sklearn.linear_model import LinearRegression X np.column_stack([knn_pred, svd_pred]) y true_rating lr LinearRegression() lr.fit(X, y) alpha lr.coef_[0] / (lr.coef_[0] lr.coef_[1])knn_pred和svd_pred必须来自验证集预测不能用训练集预测结果否则权重会过于乐观。如果某个预测器输出 NaN先填充整体均值再参与回归。这个技巧同样适用于用户与电影向量融合的场景。4.6 搜索与过滤的落地代码搜索功能在 Django 视图中用 QuerySet 实现def movie_search(request): query request.GET.get(q, ) sort_by request.GET.get(sort, revenue) movies Movie.objects.all() if query: movies movies.filter(title__icontainsquery) if sort_by in [revenue, vote_average, budget]: movies movies.order_by(- sort_by) return render(request, movie_list.html, {movies: movies})URL 参数q做标题模糊匹配sort控制排序字段。icontains在 SQLite 上只匹配 ASCII中文标题可能需要分词增强但项目范围内够用。5. 高级排错与调参技巧冷启动、稀疏矩阵与模型融合5.1 解决冷启动先热门后画像冷启动是推荐系统最常见的坑。项目里的Demographic.py用于人口统计推荐用户没有评分时直接推荐全站平均分最高的电影或者让用户勾选感兴趣的类型。我的做法是首次登录展示高评分、高票房热门电影用户选择 3 部感兴趣的电影后提取这些电影的类型和关键词计算加权 TF-IDF 向量作为用户画像再做内容推荐。这一步不需要任何历史评分就能给出合理结果。5.2 稀疏矩阵下的 SVD 参数调整评分矩阵密度不到 5% 时SVD 很容易过拟合。参数稀疏时建议稠密时建议n_factors3050100150lr_all0.010.005reg_all0.20.50.050.1n_epochs20305080稀疏时降低因子数量提高正则化减少模型复杂度。验证方法是把测试集随机抽 20% 做交叉验证观察 RMSE 是否随 epoch 先降后涨。如果上涨说明过拟合需要增大reg_all或减少n_epochs。项目里的Personal_SVD.py是自写梯度下降版本调参逻辑和surprise库一致。5.3 模型融合的验证集权重用线性回归确定alpha时关键是两个预测结果必须在验证集上生成。如果直接把训练集的预测拿来做回归权重会偏向单个过拟合的模型。实际操作中我会额外保留一个 500 条样本的 validation 集合分别预测 KNN 和 SVD再跑一遍LinearRegression()。这样即使数据分布变化也能得到相对稳定的融合权重。5.4 验证整个平台是否真的可运行用源码包最容易踩的坑是路径。压缩包内data/下 CSV 文件名带空格或中文脚本如果用相对路径很容易出错。建议在项目根目录执行python test.py如果报缺库按requirements.txt安装没有就逐个装 pandas、scikit-learn、surprise、django。如果出现ModuleNotFoundError: No module named personal检查是否把personal_recommender所在目录加到了sys.pathimport sys sys.path.append(./personal_recommender)最后可以用一行命令快速验证推荐结果python -c from personal_recommender.Personal_SVD import *; print(predict_for_user(1))1是用户 ID输出推荐电影 ID 列表。如果推荐结果和用户历史评分类型一致说明流程没问题如果全是随机的先检查训练数据里的评分范围是否被读成了字符串。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →