news 2026/9/23 18:29:06

电影票房预测实战:从特征工程到FastAPI部署,避开数据泄露

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
电影票房预测实战:从特征工程到FastAPI部署,避开数据泄露

简介:基于机器学习的电影票房预测平台,是一套面向毕业设计、课程设计与期末大作业的高分实战项目,适合具备Python和一定机器学习基础的学生直接学习与部署。平台以历史票房、影片信息、市场趋势等真实数据为基础,完整实现从数据清洗、特征工程到线性回归、决策树、随机森林、神经网络等模型训练,再到预测区间输出与可视化的全流程;代码均附有注释,配套文档说明和数据分析报告,便于理解与二次开发。资源包共58个文件,以16个Python源码和16个CSV数据集为主体,配有多张可视化图表、Markdown分析文档及Word手册,压缩包整体约30.71MB;项目内部模块划分清晰,包含多种预测与推荐算法模块及结果文件,可按需复用。目前已有502人学习,适合需要快速搭建完整项目、完成算法对比或进行论文实验的读者。

1. 基于机器学习的电影票房预测,真正的门槛不在模型

大多数能被称作“高分项目”的票房预测作品,最后都载在同一个坑上:不是模型精度不够,而是用上了电影上映之后才有的数据来预测上映前的票房。这种漂亮到离谱的结果,在评审眼里是极其典型的“数据泄露”。基于机器学习的电影票房预测平台,核心不是跑通一个 XGBoost,而是把“映前已知信息”和“映后已知信息”严格隔离,再在一条固定流水线上完成从原始数据集到预测接口的交付。下面按一线工程做法展开完整方案:先设计特征与数据集结构,再比较传统机器学习模型和深度学习模型在本场景的取舍,然后用 FastAPI 把模型封装成可运行、可演示、可答辩的平台,最后补上数据泄露自检与 SHAP 解释这种答辩加分项。新手可以照步骤复现,熟手则重点看边界条件和参数设计。

2. 数据集构成与特征工程:票房模型的成败在第一张表

搭建机器学习票房预测平台的第一步不是选模型,而是先把原始数据集摊开,逐列盘问“这个字段在上映之前能不能拿到”。票房数据集的清洗和特征工程,决定了后续所有机器学习算法能学到的上限,这个环节偷懒,后面调参再勤快也救不回来。

2.1 先划定信息边界:哪些字段能用,哪些一用就是泄露

常见的做法是按“上映日”划一条红线。凡是影片上映之后才能拿到的值,比如豆瓣开分、首日排片率、观众口碑,在映前预测任务里统统不能进特征,否则模型拿到的是“开卷考试”,而不是预测。构建最小可行数据集时,我一般会准备这样一张表:

字段类型示例是否可用
titlestr流浪地球2可用
release_datedate2023-01-22可用
genrelist[str][“科幻”, “冒险”]可用
directorstr郭帆可用
actor_1..actor_3str吴京可用
budgetfloat4.0e8可用
runtimeint173可用
ratingfloat8.3泄露,不可用
imdb_votesint1.2e6泄露,不可用
revenuefloat4.02e9目标变量

注意 rating 这类评分列在公开数据集里几乎都存在,很多开源项目直接把它塞进训练集,导致验证分数虚高。一个实用的自检方式:把特征按“上映日”排序,逐列问自己,这一列在电影上映前能否从公开渠道查到,拿不准就删。

提示:评审最喜欢看的数据泄露案例,就是“用评分预测票房、用首周末票房预测总票房”。这两类字段不是不能用,而是必须放在不同的预测阶段里。

2.2 目标变量怎么定义:回归、分档、排序带来完全不同的评价体系

票房预测平台的目标变量有三种常见定义方式,各有各的评价指标和答辩侧重点。

定义方式目标值示例评价指标优缺点
回归log1p(revenue)RMSE、MAE、R²信息保留完整,能画残差图,但长尾下高票房样本误差被稀释
二分类/多分类普通片、热映、爆款F1、AUC、混淆矩阵结果直观,符合业务汇报,但丢失金额信息
排序票房榜前10NDCG@5、NDCG@10更贴近排片决策,但评估复杂度高

高分项目通常选“回归 + 分档翻译”的组合:先预测连续票房值,再按业务阈值翻译成档位指标,两类指标都能在答辩中展示。分类任务里正负样本通常不均衡,用准确率做指标会掩盖模型“只会猜多数类”的问题,这一点在写文档说明时要明确写出来。

2.3 构造特征函数:把原始表变成模型能吃的 X

特征构造的核心原则是“只用当前样本上映日之前的信息”。比如“导演历史平均票房”这个特征,必须只统计该导演过去已经上映的电影,不能把当前电影的票房也平均进去,否则就是目标泄露。下面这个函数用 expanding 均值实现:

import pandas as pd def build_past_stats(df: pd.DataFrame, key: str, target: str = "revenue_log1p") -> pd.Series: """按上映时间排序后,统计过去已上映样本的均值,shift(1)排除自身。""" d = df.sort_values("release_date") past = d.groupby(key)[target].transform( lambda s: s.expanding().mean().shift(1) ) return past.reindex(df.index)

逻辑说明:先把全表按 release_date 升序排列,再按导演或演员分组,组内做 expanding 均值后 shift(1),这样每个样本拿到的都是“该导演此前所有电影票房的均值”,不包含当前样本,也不包含未来的样本。返回时用 reindex 恢复原始行顺序,保证和 X 对齐。

这个函数的两个关键参数需要注意,一个是 key,传导演列时得到导演历史表现,传主演列时得到演员历史表现,通常两者要分开统计再合并;另一个是 target,默认用对数变换后的票房列,而不是原始票房,原因见 2.4。

还有一类特征是类别标签,比如电影类型。类型本身是多标签,不能直接 one-hot 成几百列,常见做法是只保留高频类型:

top_genres = ["剧情", "喜剧", "动作", "爱情", "科幻", "动画"] for g in top_genres: df[f"genre_{g}"] = df["genre"].apply(lambda lst: 1 if g in lst else 0)

这样把“多标签类型”转成若干个 0/1 布尔列,维度可控,模型也能直接消费。参数说明:top_genres 列表可以按训练集出现频率排序后取前 6 到 10 个,频率太低的类型合并到“其他”里,否则会造成特征稀疏。

2.4 缺失值与长尾分布:先让数据长成模型习惯的样子

票房原始数据集不像 iris 那种教科书画布,第一眼永远是脏的。缺失值和长尾分布是两个必须解决的问题。

缺失值处理策略要按列区分:导演缺失填 “unknown”,预算缺失用训练集中位数填充,演员缺失则保留为空,在构造演员历史均值时跳过即可。类别特征不要用全局众数填充,因为“最热门导演”这一项本身会引入偏差,低频导演统一聚到 “unknown” 更干净。

票房目标值呈典型的长尾分布,头部大片票房可能是尾部小片的数千倍,直接把原始值丢给回归模型,损失函数会被头部样本主导。我一般会对目标做对数变换:

import numpy as np df["revenue_log1p"] = np.log1p(df["revenue"])

逻辑说明:log1p 是 log(1 + x),既压缩长尾,又能保留 0 票房的样本。预测完成后用 np.expm1 还原成原始金额,换算关系在文档说明里必须写清楚,否则评审只看预测结果会一头雾水。

低频类别同样要处理。导演或主演出现次数少于 20 次的,统一替换成 “OTHER”,避免模型为每个低频类别单独建分支而过拟合:

freq = df["director"].value_counts() rare = freq[freq < 20].index df["director_grp"] = df["director"].where(~df["director"].isin(rare), "OTHER")

参数说明:低频阈值 20 不是硬性标准,数据量大可以提到 50,数据量小可以降到 10。核心思路是让类别列的分组数量可控,不能出现“一个导演一个类别”的局面,否则树模型会在这些叶子上记住噪声。

3. 模型选型与交叉验证:把验证集当成评审团

数据和特征准备到位后,才轮到机器学习模型登场。票房预测平台里模型不是越复杂越好,评价一个模型的标准永远是“在时间序列验证集上的表现”,而不是“能不能在训练集上收敛”。

3.1 为什么传统机器学习模型在票房预测里仍是首选

在几百到几千条样本量的票房数据集上,传统机器学习模型通常是比深度学习模型更稳的选择。深度学习模型需要大量数据支撑才能让 embedding 层学到有意义的表示,样本量不足时,MLP 很容易在验证集上振荡,而梯度提升树却能稳定输出不错的结果。

模型类别样本量需求类别特征支持可解释性本场景定位
线性回归需手动编码基线模型
LightGBM / XGBoost中等原生支持较高(配合 SHAP)主力模型
MLP / 简单 DNN需 embedding可作对比实验

这个场景的机器学习入门策略是:先用线性回归跑通基线,再用 LightGBM 提精度,最后有精力再补一个 MLP 做对比。把对比结果写进文档说明,比单纯堆一个高精度模型更能体现工程判断力。

3.2 用时间感知的交叉验证替代随机划分

票房数据有季节效应和通胀效应,直接用KFold(shuffle=True)随机划分会让训练集看到未来数据,验证分数虚高。我一般用TimeSeriesSplit,并额外加一个 gap 把训练集和验证集在时间上隔开,避免邻近档期的样本互相渗透:

from sklearn.model_selection import TimeSeriesSplit # 训练前必须按 release_date 排好序 X = X.sort_values("release_date") tscv = TimeSeriesSplit(n_splits=5, gap=30) for fold, (tr_idx, va_idx) in enumerate(tscv.split(X)): print(f"fold {fold}: train {tr_idx.size} samples, valid {va_idx.size} samples")

逻辑说明:TimeSeriesSplit 按顺序切分,保证训练集永远在验证集之前。gap 参数表示前后两段之间空出 30 天,这 30 天的样本不参与任何一边的训练,可以防止“离验证集最近的训练样本”和验证集存在过多相似信息。

参数说明:gap 取值要根据具体数据的时间跨度调整。如果你的数据跨度是 10 年,30 天 gap 偏短,可以设到 90 天;如果只有 1 年数据,gap 设 7 天即可,太长会浪费样本。

3.3 用 LightGBM 搭主力模型:一份可以直接复用的训练脚本

LightGBM 是目前票房表格数据上最常见的主力选择。它对类别特征的原生支持和训练速度,明显优于 XGBoost。下面是一份可以直接复用的训练脚本核心段:

import lightgbm as lgb import numpy as np from sklearn.metrics import mean_squared_error model = lgb.LGBMRegressor( objective="regression", metric="rmse", max_depth=4, num_leaves=15, learning_rate=0.05, n_estimators=2000, colsample_bytree=0.8, reg_alpha=0.5, reg_lambda=1.0, random_state=42, verbose=-1, ) model.fit( X_train, y_train, eval_set=[(X_valid, y_valid)], callbacks=[lgb.early_stopping(100), lgb.log_evaluation(100)], ) pred_log1p = model.predict(X_valid) rmse = mean_squared_error(y_valid, pred_log1p, squared=False) print(f"valid rmse(exp): {rmse:.4f}")

逻辑说明:目标变量和对数变换后的票房值,在 log 空间算 RMSE 等价于评估相对误差,避免高票房样本主导损失。early_stopping 让模型在验证集上连续 100 轮没有提升时自动截断,实际迭代次数通常远小于 n_estimators。

关键参数的作用和调整方向如下:

参数推荐值说明
max_depth4牺牲深度换稳定,防止小样本过拟合
num_leaves15控制树复杂度,数值越大拟合越强,但过拟合风险同步上升
learning_rate0.05减小学习率就要增大 n_estimators,两者联动
colsample_bytree0.8每棵树只用 80% 特征列,增加泛化能力
reg_alpha0.5L1 正则,适合特征列较多、包含大量稀疏类别的场景
reg_lambda1.0L2 正则,缩小叶子节点权重

不要上来就做大范围超参数搜索。先保持默认参数跑通流程,再针对 max_depth、num_leaves、learning_rate 三个参数做小网格搜索,一次实验控制在几十组以内。每一组实验的结果按时间戳存档,方便回溯。

3.4 把连续分数翻译成业务档位:阈值搜索与校准

回归模型直接输出金额,但在汇报时通常需要变成“普通片 / 热映 / 爆款”这样的业务档位。分档阈值不应该拍脑袋定,而是用验证集上搜索出来的:

from sklearn.metrics import f1_score, precision_score, recall_score thresholds = np.linspace(0.2, 0.8, 61) scores = [] for t in thresholds: y_pred = (val_proba >= t).astype(int) scores.append((t, f1_score(y_val, y_pred), precision_score(y_val, y_pred), recall_score(y_val, y_pred))) best = max(scores, key=lambda x: x[1]) print(f"best threshold={best[0]:.2f}, f1={best[1]:.3f}")

逻辑说明:票房正样本在数据集中通常远少于负样本,默认 0.5 的行为是把多数样本都判为“普通片”,F1 看起来不差,但没有任何业务价值。阈值搜索就是在 precision 和 recall 之间找一个平衡点。

参数说明:linspace 的范围和步长要看验证集概率分布来定,如果模型输出集中在 0.3 到 0.6 之间,搜索范围就收敛到这一段,步长取 0.01 到 0.02 更精细。搜索结果保存成图片或表格放进文档说明里,比空口说“模型精度高”有说服力得多。

4. 平台落地:把机器学习模型包成能演示和答辩的服务

训练脚本跑通只是中点,一个完整的电影票房预测平台还需要把模型暴露成可调用的服务,让评审能直接体验预测过程。这一章负责把源码组织、API 封装和文档说明落到位。

4.1 从 Notebook 到可提交仓库:推荐目录结构

如果整个项目只有一个 Jupyter Notebook,评审第一印象就会打折扣。我一般会把源码组织成这样的目录结构:

movie-boxoffice/ ├── data/ │ ├── raw/ # 原始数据,只读不写 │ ├── processed/ # 清洗后的训练数据 │ └── external/ # 外部统计(导演历史票房等) ├── notebooks/ # 探索性分析 ├── src/ │ ├── features.py # 特征工程模块 │ ├── train.py # 训练与模型保存 │ ├── predict.py # 批量预测脚本 │ └── api.py # FastAPI 服务 ├── models/ # 训练产物 ├── results/ # 预测结果输出 ├── requirements.txt └── README.md

目录设计的原则是“数据、代码、产物三分离”。raw 目录下的数据文件保持只读,processed 存放每次预处理后的版本,models 里只保留一个最终模型和它的超参数记录,这样整个训练流程才可复现。

4.2 用 FastAPI 封装一个最小可用的预测接口

FastAPI 是目前封装机器学习模型最顺手的 Web 框架。原因很简单:声明式请求校验、自动生成 OpenAPI 文档、异步支持,都不需要额外配置。核心接口代码如下:

from fastapi import FastAPI from pydantic import BaseModel import numpy as np app = FastAPI(title="BoxOffice API", version="1.0.0") class MovieInput(BaseModel): title: str release_date: str genre: list[str] director: str actors: list[str] budget: float @app.post("/api/v1/predict") def predict(m: MovieInput) -> dict: # 用特征工程模块把请求转成模型输入的 DataFrame X = build_single_input( title=m.title, release_date=m.release_date, genre=m.genre, director=m.director, actors=m.actors, budget=m.budget, ) y_log1p = model.predict(X)[0] return { "revenue_pred": float(np.expm1(y_log1p)), "revenue_log1p": float(y_log1p), "unit": "元", }

逻辑说明:build_single_input 必须和训练时用同一个特征工程函数,不能重新写一套,否则特征顺序对不齐,预测结果直接失真。返回体同时给出 log 空间和原始金额,方便不同口径的调用方使用。

参数说明:release_date 传入后内部会拆解成档期特征、星期特征等;budget 在特征函数内部会做对数变换,与训练时一致;genre 必须用 list[str] 而不是逗号分隔的字符串,这样 pydantic 能自动完成类型校验,非法请求会在到达模型之前被拦截。

启动服务用一行命令:

uvicorn src.api:app --host 0.0.0.0 --port 8000 --reload

启动后浏览器访问/docs就能看到交互式接口文档,可以直接在页面里填参数测试。这一步演示效果很好,也是答辩时的常用开场。

4.3 批量离线预测:跑完整张测试表

接口适合单条预测,但评审手里通常有一批测试数据要批量出结果。单独写一个命令行预测脚本,而不是在 Jupyter 里手动改路径跑:

# src/predict.py import argparse import pandas as pd import numpy as np from src.features import build_features def main(): parser = argparse.ArgumentParser() parser.add_argument("--input", required=True, help="测试集 CSV 路径") parser.add_argument("--output", default="results/predictions.csv") args = parser.parse_args() df = pd.read_csv(args.input) X = build_features(df) df["revenue_pred"] = np.expm1(model.predict(X)) df.to_csv(args.output, index=False) print(f"已输出 {len(df)} 条预测,文件:{args.output}") if __name__ == "__main__": main()

调用方式:

python -m src.predict --input data/raw/test.csv --output results/test_pred.csv

逻辑说明:批量预测脚本复用了 train.py 里保存的模型文件和 features.py 里的特征工程函数,保证离线预测和在线接口预测结果一致。输出文件保留原始字段,同时追加预测结果列,方便和真实票房对比计算误差。

参数说明:--output 路径默认落在 results 目录下,文件名建议带上日期或版本号,同一份数据跑多轮时不会互相覆盖。如果数据量超过几万行,可以加一个 batch_size 参数分批预测,但票房数据集通常远达不到这个规模。

4.4 把数据字典和文档说明写进平台,而不是等到最后补

标题里明确写了“文档说明”是评分的一部分,那它就是平台的一等公民。README 至少要有四段:环境安装说明、数据字典、训练流程、API 调用示例。

数据字典建议用表格列出每个字段的含义、类型、是否用于训练,以及取自哪个数据源。这个表格并不难写,但能显著降低评审理解项目的成本,也方便三个月后的你自己回过头来维护。

requirements.txt 里的依赖不要无脑pip freeze全量导出,只保留直接依赖的包:

numpy pandas scikit-learn lightgbm fastapi uvicorn pydantic

逻辑说明:全量导出会把环境里无关的包一并锁进去,评审换台机器复现时容易踩版本冲突。只列直接依赖,再注明 Python 版本要求,这样可复现性更好。文档说明里还要写清“先装什么后装什么”的顺序,常见做法是先建虚拟环境,再逐行安装 requirements.txt。

5. 答辩与自检技巧:用特征重要性和 SHAP 给评审一个交代

模型跑完、平台上线,这只是解决了“能不能用”的问题。评审关心的是“为什么这个参数是 4、那个阈值是 0.57”,以及“你怎么证明自己没有作弊”。这一章给出三个具体技巧,把它们写进文档说明,能明显拉开和普通调包项目的差距。

5.1 数据泄露自检:特征重要性分布会说话

特征重要性是第一道自检防线。把模型的特征重要性打印出来,观察头部特征的分布是否异常:

importance = pd.Series(model.feature_importances_, index=X.columns) importance = importance.sort_values(ascending=False) print(importance.head(10))

如果某个特征的重要性超过 0.4,甚至一骑绝尘压过所有其他特征,先别高兴,回头检查这个特征是不是上映后才有的字段,大概率是评分、评论数、首周末票房这类泄露列混进来了。特征重要性排序截图放进文档说明,是回应数据泄露质疑的最直接证据。

5.2 SHAP 解释:让模型的选择可被行业常识校验

SHAP 是答辩环节最实用的工具,能把树模型的黑盒输出变成人和模型都能理解的一张图:

import shap explainer = shap.TreeExplainer(model) shap_values = explainer.shap_values(X_valid) shap.summary_plot(shap_values, X_valid)

summary_plot 会展示每个特征对预测结果的贡献方向和大小。答辩前先用行业常识校验一遍:档期特征的贡献方向应该是春节档、暑期档显著为正;导演历史均值应该是正向贡献。如果 SHAP 图里出现了违背常识的特征方向,比如“导演历史票房越高,预测票房越低”,那就是特征工程阶段出了问题,趁答辩前赶紧修。

5.3 两阶段拆分:映前预测与首周末修正

票房预测平台真正能体现业务深度的做法,是把预测任务拆成两个阶段。第一阶段只用映前信息预测总票房,这个模型做的是“定档到上映”之间的决策;第二阶段引入首周末实际票房作为新特征,预测最终总票房,这个模型做的是“上映后一周内”的修正。两者共用同一套特征工程框架,但目标不同:

# 第二阶段:在特征集合中加入首周末实际票房 X_stage2 = build_features(df) X_stage2["opening_weekend_gross"] = df["opening_weekend_gross"] model_stage2 = lgb.LGBMRegressor(**best_params) model_stage2.fit(X_stage2, y_train)

逻辑说明:首周末实际票房本身是上映后数据,在单阶段模型里属于泄露字段,但在两阶段框架下,它的角色从“泄露源”变成了“合法特征”。把两个阶段的模型都保留,并在文档说明里对比两阶段的 MAE 下降幅度,这个数字比任何调参记录都有说服力,因为它证明了平台不是一次性预测,而是能持续修正的完整闭环。把你自己的数据按同样的拆法跑一遍,观察两阶段模型的误差收敛幅度,你会更快理解阈值、gap 和特征边界这些参数在不同任务里的真实意义。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 18:22:10

RBF vs BP神经网络时间序列预测:选型、实现与避坑指南

简介&#xff1a;这份资源面向时间序列预测的初学者与进阶学习者&#xff0c;提供基于RBF径向基神经网络与BP反向传播神经网络两套完整实现方案&#xff0c;可用于股票、销售、气象等趋势预测场景的对比实验。压缩包共5个文件&#xff0c;约349KB&#xff0c;包含2个m脚本文件作…

作者头像 李华
网站建设 2026/9/23 18:20:53

碳粉原理与实操:从静电成像到兼容粉选择及故障排查

1. 碳粉到底是什么&#xff1f;先拆一盒粉看门道很多人以为碳粉就是“磨细的炭”&#xff0c;其实差远了。打印机、复印机里用的碳粉&#xff0c;标准名称叫“墨粉”或者“显影剂”&#xff0c;它是静电成像系统的核心耗材。你在电商平台搜“碳粉”&#xff0c;出来一堆几十块钱…

作者头像 李华
网站建设 2026/9/23 18:18:14

Linux安全基线整改实践:修复 Business Use Notice MOTD ISSUE Existence 检查项

目录 一、背景二、问题分析三、排查过程四、修复方案五、验证修复结果六、自动化修复脚本七、风险评估八、总结 一、背景 在企业 Linux 安全基线扫描过程中&#xff0c;发现服务器存在如下基线告警&#xff1a; Category: Business Use NoticeName: Business Use Notice MOT…

作者头像 李华
网站建设 2026/9/23 18:15:22

电动汽车制动系统设计:从法规到再生制动与踏板感的关键技术解析

简介&#xff1a;PDF文献《电动汽车制动系统的设计》面向新能源汽车、汽车工程相关专业的学生与技术人员&#xff0c;聚焦电动汽车行驶安全中的制动问题&#xff0c;以真空助力器为核心&#xff0c;完整介绍制动系统的分析、计算与设计流程。资源为单份PDF文档&#xff0c;共1个…

作者头像 李华
网站建设 2026/9/23 18:14:25

PX4 AI 辅助贡献规范:作者身份、披露与提交合规指南

嵌入式物联网机器人自动驾驶智能硬件 【免费下载链接】PX4-Autopilot PX4 Autopilot Software 项目地址&#xff1a; https://gitcode.com/gh_mirrors/px/PX4-Autopilot 点击查看 免费下载 本指南围绕 PX4-Autopilot 仓库中的 AI 辅助贡献官方政策&#xff0c;系统讲解使用 AI…

作者头像 李华
网站建设 2026/9/23 18:12:48

SSM+微信小程序健身房私教预约系统:毕设97分项目实战与避坑指南

简介&#xff1a;这是一套面向高校计算机相关专业学生的Java毕业设计完整项目包&#xff0c;主题为基于SSM框架与微信小程序的健身房私教预约系统&#xff0c;适合正在准备毕业设计、课程设计或需要实战练手SSM与小程序开发的学习者。资源共946个文件&#xff0c;压缩包约30.96…

作者头像 李华