资讯动态

票房预测的机器学习落地:特征工程、模型选型与避坑指南

发布时间:2026/9/26 9:35:10 来源:尧图企业网站定制
简介这是一份基于机器学习算法构建电影票房预测模型的PDF文献面向机器学习学习者、数据分析从业者及电影市场研究人员可作为课题参考或专业指导资料。文献以线性回归和xgboost算法为核心完整覆盖了票房预测的建模流程从TMDB电影数据集7398部影片出发进行缺失值填充、特征工程与相关性分析再通过损失函数和梯度下降迭代优化模型并检验模型在短期与长期票房走势上的预测准确性。同时文中也讨论了模型泛化能力、高维变量处理等现实挑战提供了基于实验的改进思路。资源为单个PDF文件大小1.13MB内容精炼便于离线阅读目前已有1753人学习使用。借助该文献读者可系统掌握机器学习票房预测的算法原理、数据处理技巧与实验评估方法为相关研究、毕业设计或行业分析提供扎实的理论参考与可复现的实践路线。1. 电影票房预测到底在预测什么一个可以用历史数据反复验证的回归任务「电影票房预测」这四个字听着像给投资人讲故事的玄学但它本质是一个有明确输入输出、可以用历史数据反复验证的机器学习回归任务给定一部电影的类型、档期、主创阵容、宣发强度预测首周末票房与最终总票房。我见过不少团队把精力花在「猜爆款」上实盘做下来才发现把预测误差率稳定压到 20% 以内比「猜中年度冠军」更值钱——排片、投放、回本测算全都用得上。适合谁发行公司的排片策略组、制片方的回本测算以及想拿真实业务练手的算法工程师都能从这套方案里拿到可直接复用的东西。2. 先定问题边界票房预测的三种任务形态与样本构造动手写特征之前我习惯先跟业务方对齐一件事你要的是一个数字还是一组决策这两个答案会导向完全不同的建模方式。票房预测不是「拿一个算法套上数据就行」它首先要回答三个问题预测什么、在什么时点预测、用什么样本训练。这三个问题没定清楚后面所有特征工程都是白做。2.1 分类、回归、时序先决定你要哪个「预测结果」电影票房相关的机器学习任务按输出类型可以分成三类业务含义完全不同。任务形态业务问题典型算法输出主要缺陷分类这片要不要给 S 级排片逻辑回归、梯度提升树命中概率丢失量级信息没法算回本回归总票房能到多少能否回本LightGBM、随机森林具体数字长尾分布下误差波动大时序首周之后每天怎么排片LSTM、Prophet日票房曲线数据量要求高可解释性弱三种形态对应三类决策。宣发团队最常用分类判断一部片「能不能过亿」决定要不要追加投放制片方和投资方最常用回归算的是回本线需要一个具体票房数字院线和发行方做周排片调整时才需要第三类——逐日的票房曲线预测。这个区分和用户消费预测、金融时序预测是同一类问题先想清楚业务要的是概率、数值还是序列再选算法。如果你一上来就调 LSTM多半是因为没意识到项目级电影样本往往只有几百到上千条根本喂不饱深度模型。我的习惯是先把分类和回归各做一个 baseline再决定要不要上时序模型。2.2 预测时点上映前 90 天和上映前 7 天用的是两套特征票房预测最容易忽略的维度是时间。同样是「预测一部电影的票房」上映前 90 天你能拿到的只有剧本、阵容、IP、档期上映前 7 天你多了预售、想看人数、物料播放量上映后第 1 天你才有首日排片和口碑。这三个时点能用的特征完全不一样模型也应该分开训练。机器学习模型能工作的前提是训练分布和预测分布一致。票房预测恰恰经常违背这个假设你用今年的数据训练明年春节档的市场环境可能已经变了。所以我的做法是给每条特征打一个available_at标签严格按可获取时间切分。所谓「上映前 90 天预测」就是要模拟那个时点的信息状态重建特征而不是拿最终数据倒推。预测时点还决定了样本怎么构造。常见做法是「一部电影一条样本」比如用 2015 年到 2024 年所有公映电影每部一行标签是最终总票房如果按时间切分也要保证训练集里的片子全部早于验证集。另一种做法是「电影 × 预测时点」拆成多条样本同一个项目预测 3 次、误差逐步收敛这样能模拟真实业务里滚动预测的节奏但对特征时效要求更高。2.3 机器学习应用流程在这个题目上的固定套路这套题目的应用流程其实高度固定数据收集、特征工程、样本构造、模型训练、评估、迭代上线。数据收集阶段要拿全量公映电影不能只收票房榜前列特征工程阶段把档期、主创、预售、竞品变成数值样本构造阶段按预测时点打标签训练阶段用时间序列交叉验证评估阶段分层看误差上线后每周补新样本重训。流程里最花时间的是特征工程其次是样本构造。模型选型反而是最后一步因为样本量小、特征异质性强树模型通常比深度学习更稳。接下来两章我把特征工程和训练流程分别展开讲。3. 票房特征工程把「玄学」拆成能进模型的 20 个特征票房预测总被人说是玄学是因为「导演水平」「观众口碑」「档期运气」这些词太模糊。特征工程做的就是把这几个词拆成可计算的变量导演近三年同类片票房均值、上映日距最近节假日的天数、预售票房除以档期均值。拆完之后你才会发现所谓玄学大部分是「小样本 高噪声」造成的错觉。3.1 特征候选池档期、主创、预售、竞品一个都不能少我一般会把候选特征按组收进特征池每组对应一类业务信息。下面是 T-7上映前 7 天时点常用的特征清单特征组具体特征常用处理T-7 是否可得档期上映日距最近节假日天数连续化替代节假日哑变量是主创历史导演近 3 年同类型电影票房均值分类型统计后归一化是主创历史主演近 3 年同类型电影票房均值分类型统计后归一化是IP/系列是否为续集、前作票房系列均值 续集标记是宣发宣发费用、路演场次缺失用同类型中位数补部分可得预售想看人数、预售票房除以档期均值消除档期差是首日排片首日排片场次、排片占比注意这是 T1 信息T-7 不能用否竞品同期上映影片数量与预期票房同档期竞品均值是制式是否 IMAX/CINITY、特效公司哑变量是舆情微博话题量、物料播放量对数变换部分可得这张表有两个关键信息。第一「主创历史」必须分类型统计一个喜剧导演拍科幻片的号召力不能直接用他的喜剧票房均值衡量第二表里有三分之一特征在「T-7 是否可得」列标了「否」或「部分可得」这就是后面特征泄漏的重灾区先记住这一点。3.2 特征清洗与构造把 300 列的原始表压缩到 40 列拿到的原始数据通常是几百列的大宽表大部分列要么缺失严重要么是没法直接进模型的文本。下面这段是 T-7 预测节点的特征构造骨架一行一部电影import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler def build_features(df): df df.copy() # 缺失值宣发费用按同类型影片中位数补不填 0 # 填 0 会让模型学出“没有宣发”的伪规律 df[promo_budget] df[promo_budget].fillna( df.groupby(genre)[promo_budget].transform(median) ) # 档期连续化用距最近节假日的天数替代“春节档/国庆档”哑变量 df[days_to_holiday] (df[release_date] - df[nearest_holiday]).dt.days # 导演历史票房必须用“该片上映之前”的数据 # 简化版先用训练集全量均值正式流程要改成 rolling window否则会泄漏 df[dir_hist] ( df.groupby(director)[gross] .transform(mean).rank(pctTrue) ) # 预售强度想看人数 / 首日排片场次再除以档期均值 df[presale_intensity] ( df[wanna_watch] / df[first_day_sessions] ) / df.groupby(slot)[wanna_watch].transform(mean) # 树模型不需要标准化但后面要试线性模型时先用上 scaler StandardScaler() for col in [promo_budget, days_to_holiday, presale_intensity]: df[col] scaler.fit_transform(df[[col]]) return df代码逻辑上有四点值得说明。中位数填充用groupby(genre)是因为不同片型的宣发投入差异很大全局中位数会抹平类型差异档期连续化成「距节假日天数」是因为纯哑变量在样本量小的时候容易过拟合连续值还能表达「节前三天 vs 节后一天」这种细微差别dir_hist用rank(pctTrue)归一是为了避免个别头部导演的票房巨值把数值拉偏转成排名后模型更容易比较预售强度除以档期均值相当于做了个简单的季节调整春节档和普通周末的预售量级本来就不在同一条线上不除以均值模型只会学到「春节档预售高」这个伪规律。参数说明也要注意groupby(director).transform(mean)在这种写法里用的是训练集全部历史数据严格上线时应该改成按上映日期排序后的滚动窗口均值否则会把未来信息带进特征。这里先留个口子第 5 章会专门讲怎么排查这类泄漏。3.3 特征选择少喂一点噪声模型才能学到规律特征池里经常躺着三四百列但真正有用的通常不超过 40 列。无脑全喂进去的第一个问题是共线性比如「微博话题量」和「物料播放量」高度相关两个都进模型等于给同一个信息加了双倍权重。第二个问题是高基数类别特征导演、主演这类列有几百个取值直接 one-hot 会让特征维度爆炸模型还把每个导演当成独立符号学不到「两个导演都拍过喜剧且有票房成功经验」这种相似性。我的做法分两步。第一步用相关性矩阵粗筛corr X_train.corr().abs() upper corr.where(np.triu(np.ones(corr.shape), k1).astype(bool)) drop_cols [col for col in upper.columns if any(upper[col] 0.85)] X_train.drop(columnsdrop_cols, inplaceTrue)第二步对导演、主演这类高基数特征不用 one-hot而是用「历史票房均值 历史作品数」两个统计量代替。有人建议先用聚类算法给影片分档再做回归我试过效果一般而且多了一层解释成本业务方会问你「模型凭什么把我这片归到那一档」。直接用主创历史统计量解释起来简单得多。最终特征数量控制在 20 到 40 列之间。特征少于 20 个模型学不到档期、竞品、预售之间的交互超过 40 个几百条样本根本撑不起这么多维度验证误差会开始反弹。这个范围不是拍脑袋定的是用不同特征数量跑过几轮验证集之后观察到的规律。3.4 预售与排片最容易引入「未来数据」的两个特征预售和排片是票房预测里信息量最大的两个特征也是最容易翻车的两个。预售在 T-7 时点已经存在可以直接用首日排片场次在 T-1 才最终确定如果你在 T-7 预测时把首日排片喂给模型等于提前用了未来数据训练时误差会好看上线后必崩。我给每个特征都维护一个available_at字段建特征的时候就写死它的最晚可得时点想看人数标T-30预售票房标T-7首日排片标T-1豆瓣开分标T1。训练时available_at晚于预测节点的特征一律不参与。这一步看着简单实际排查泄漏时全靠它救命。4. 模型选型与训练流程从线性回归到 LightGBM 的落地路线特征工程做完模型选型反而没什么可纠结的。这个任务的数据特点是样本量小每年有效公映电影几百部、特征异质连续值、类别值、比率值混在一起、特征之间有强交互档期和竞品强关联、主创和宣发互相影响。按这个画像去选模型答案基本会收敛到梯度提升树。4.1 模型对比样本量只有几百条时为什么树模型是首选我见过不少人第一反应上神经网络理由是「票房预测这么复杂的问题深度学习能力强」。实际跑下来几千条样本的 MLP 往往不如几百棵树的 LightGBM还更容易过拟合。如果只读过《机器学习》里的经典模型更容易掉进这个坑——书上的算法各有适用场景但实际业务里数据量会替你做出选择。模型优点缺点在本任务中的表现线性回归可解释、快需要手动构造大量交互项只适合当基线随机森林不需要标准化、抗噪声外推能力差稳但精度一般LightGBM/XGBoost自带缺失处理、自动特征交互参数多小样本易过拟合项目级预测首选LSTM/GRU适合长序列建模需要逐日样本且数据量大日级排片预测的次选需要区分的是设备寿命预测这类长时序任务样本是连续的传感器读数LSTM 很合适但电影票房是「一部电影一条记录」的项目级数据样本之间没有连续时间步硬上 LSTM 反而丢掉了一部电影最重要的一次性特征。日级排片预测这类真正的时序任务里LSTM 才有它的位置。4.2 时间序列交叉验证 LightGBM一段能直接跑的脚本模型训练的第一原则是不能用随机 KFold。随机打乱会把「2023 年的电影出现在训练集、2024 年的出现在验证集」这种未来信息带进来验证误差虚低。这里要用按上映日期排序后的时序交叉验证import lightgbm as lgb import numpy as np from sklearn.model_selection import TimeSeriesSplit from sklearn.metrics import mean_absolute_percentage_error # 先按上映日期排序保证训练集永远在验证集之前 X_sorted X_train.sort_values(release_date) y_sorted y_train.loc[X_sorted.index] tscv TimeSeriesSplit(n_splits5) models [] for train_idx, val_idx in tscv.split(X_sorted): X_tr, X_val X_sorted.iloc[train_idx], X_sorted.iloc[val_idx] y_tr, y_val y_sorted.iloc[train_idx], y_sorted.iloc[val_idx] model lgb.LGBMRegressor( n_estimators1000, learning_rate0.05, num_leaves31, feature_fraction0.8, bagging_fraction0.8, bagging_freq1, random_state42, ) model.fit( X_tr, y_tr, eval_set[(X_val, y_val)], callbacks[lgb.early_stopping(50), lgb.log_evaluation(0)], ) models.append(model) val_mape np.mean([ mean_absolute_percentage_error(y_val, m.predict(X_val)) for m, (_, val_idx) in zip(models, tscv.split(X_sorted)) ]) print(fval MAPE: {val_mape:.3f})这里每个参数都对应一个坑。learning_rate0.05配合n_estimators1000是让小学习率慢慢学靠early_stopping(50)在验证误差不再下降时自动停而不是一次性训满 1000 棵num_leaves31是单棵树的复杂度上限小样本下叶子数超过 64 很容易把样本背下来feature_fraction0.8和bagging_fraction0.8分别是列采样和行采样给树模型加随机性降低过拟合。最后用 MAPE平均绝对百分比误差而不是 RMSE 评估是因为票房是长尾分布RMSE 会被头部影片主导详见第 5 章。这套脚本跑出来的验证误差通常比随机 KFold 高 5 到 10 个百分点别慌这才是真实水平。4.3 用 SHAP 值向业务方解释模型不是黑匣子树模型精度高但业务方最怕的是「你告诉我模型预测 3.2 亿它凭什么这么算」。票房决策涉及真金白银的宣发投入模型必须可解释。我习惯给每个预测出一份 SHAP 值让业务方看到贡献拆解import shap explainer shap.TreeExplainer(models[-1]) shap_values explainer.shap_values(X_val) # 画特征贡献图看哪些特征把预测值往上推、哪些往下压 shap.summary_plot(shap_values, X_val, max_display15)SHAP 值的读法是某个特征的 SHAP 值为正则推高票房为负则压低票房。比如一部科幻续集的预测被压到 2 亿看 SHAP 图会发现「同档期竞品强度」贡献了 −0.8 亿「预售强度」贡献了 −0.3 亿业务方就能理解不是模型不看好这片是同期有两部大片分流了 IMAX 场次。这一步看着是锦上添花实际是模型能上线的前提。5. 票房预测实战中常见的 5 个坑泄漏、样本偏差与评估错配这一章全是血泪经验。票房预测的模型训练流程本身不复杂复杂的是数据里藏着各种「看起来能用、实际不能用」的信息。以下 5 个坑我几乎每个都踩过按现象、原因、解决三步写清楚。5.1 特征泄漏把「上映后的口碑评分」带进了训练集现象训练集上 MAPE 能做到 8%一上新的未上映片子验证误差直接飙到 35% 以上模型像换了个人。原因特征里混进了上映后才有的信息。最常见的是豆瓣开分、首日排片、上映后的口碑词云。这类特征在历史样本里取值完整、和目标票房相关性极高模型学起来特别「轻松」所以训练误差很好看但对未上映的片子这些变量根本不存在。解决给每条特征维护一个available_at字段训练前做一次门禁校验凡是在预测时点之后才能拿到的特征一律删除。你可以写个简单脚本遍历特征列表assert feature.available_at predict_time不合格的直接报警。排查泄漏时先看两个指标训练误差是不是低得不正常、特征重要性第一名是不是直觉上不可能提前知道的变量。5.2 样本偏差只盯着爆款模型学不到腰部影片现象预测《流浪地球》这类头部片误差还行一旦预测几千万票房的小成本片就完全没谱误差率经常超过 50%。原因公开的票房数据集往往只收录票房榜前列的片子腰部影片样本占比太低。模型在训练时见过的样本都是「高票房片」自然学不到小成本片的规律。但排片决策最常碰到的恰恰是腰部区间。解决建数据集时尽量收全量公映电影包括亏损片。评估时按票房区间分层看误差不要只看整体 MAPE。如果腰部样本确实太少可以改用分位数损失训练让模型在低票房区间的拟合更积极而不是被几个头部样本牵着走。提示判断样本有没有偏差先看训练集票房分布如果中位数票房超过 3 亿说明数据集已经是头部偏的了。5.3 档期断层春节档的票房产出被当成普遍规律现象模型给五一档的普通喜剧片预测了偏高的票房因为训练集里大量「档期效应」来自春节档样本而五一档的样本又少又弱。原因节假日效应对票房的影响巨大但每个档期的样本量差异也巨大。春节档一年只有十几部片模型容易把它学成一个「高票房万能解释」的强特征遇到观影习惯完全不同的档期就翻车。解决把档期从哑变量改成连续化特征距节假日天数再单独构造「同档期历史均值」作为条件特征。更稳妥的做法是训练年份与档期的交互项比如「距离最近长假天数 × 该电影的年份」让模型知道 2024 年春节档和 2025 年春节档的基数不同。跨年预测时按宏观票房涨跌给基准值做手工修正。5.4 评估指标错配用 RMSE 评估一个长尾分布现象模型总 RMSE 看起来不高业务方一用就骂「这部片预测 2.5 亿实际 3 亿差 5000 万叫准」RMSE 把 10 亿级头部片的误差放大后平均掉了掩盖了中小成本片的真实误差。原因票房分布是典型长尾几部头部影片贡献了大部分误差平方和。RMSE 对大偏差极度敏感导致评估结果被极少数样本主导无法反映「每部片预测得怎么样」。解决以 MAPE 为主指标因为它按百分比衡量误差对不同量级的片子相对公平同时按票房区间分别统计 MAPE低票房区间的误差单独看。模型调优时如果目标是让 0.5 亿到 2 亿区间的决策更准可以直接把损失函数换成加权 MAPE或者用 q0.5 的分位数损失。5.5 超参数过度调优几百个样本支撑不起大规模搜索现象用 Optuna 跑了几千轮验证误差从 21% 降到 19.8%自我感觉良好上线预测下个月新片误差反而比 baseline 高。原因样本量只有几百条参数搜索空间一大模型会把验证集的噪声也学进去。调出来的参数是针对验证集的「定制方案」不是通用规律。解决把调参限制在「合理范围的小搜索」固定learning_rate0.05和n_estimators早停只调num_leaves、feature_fraction两三个参数搜索轮次限制在 50 轮以内。大部分收益来自特征工程和样本质量花两天调参不如花半天修掉一个泄漏特征。6. 把预测误差率压到 20% 以内的几个进阶习惯模型能跑到 20% 误差率剩下的事就不再是调参了而是建立一套「预测 反馈」的迭代机制。两个习惯是我认为最有用的。6.1 分档残差监控误差率要按票房区间分开看整体 MAPE 不骗人但也帮不了人。我会把验证集按实际票房分成四档分别统计误差每档给不同的处理动作票房区间典型问题处理动作0.5 亿以下腰部样本被头部淹没误差率最高单独跑一个轻量模型或设置预测下限保护0.5 亿 ~ 2 亿排片决策最敏感的区间误差波动大重点核对竞品与预售特征2 亿 ~ 10 亿模型相对稳定按周滚动重训即可10 亿以上样本极少但单部影响大人工审查 融合模型保留人工修正接口这个表格的意义是把「模型哪里不准」变成可执行的清单。连续两周误差集中在 0.5 亿以下区间就去查样本收集是不是漏了亏损片集中在 10 亿以上就把头部片单独做案例复盘别动整体特征。6.2 滚动重训与规则对冲模型不可能替你兜住所有档期票房市场的规律每年都在变模型必须跟着市场滚。我的节奏是每周日把新增的上映影片补进训练集重训一次每部片首日数据出来后再做一次增量预测用真实首日票房修正后续预测。滚动重训的周期不能太长否则模型永远停在半年前的档期结构里也不能太短每天重训会因为单日噪声反复横跳。最后一条习惯是给业务规则留出口模型输出 3 亿但片方线下预售异常火爆、一线城市点映口碑爆了这时不应该强行让模型认错而是保留一个人工修正系数。我现在的做法是每次预测都留一份残差报告记录哪些片被业务方手动改了、改了多少连续几次都往同一个方向改就把这个方向做成特征喂回模型。电影票房预测做到最后拼的不是哪个模型更先进而是你对数据的敬畏程度。把特征时效、样本偏差、评估口径这些脏活做扎实误差率自然就下来了。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑