摘要
HiMCM 2018A 要求只用客观数值参数为过山车排名。本文把它当成预测问题来做: 以 Golden Ticket Awards 2018 的钢质、木质两张 top-50 榜单为标签, 从 RCDB 的 1744 台过山车数据中学习"给参数打分、分高者胜"的评分函数,再对全库打分。
预处理阶段解决了三件事:最大倾角缺 83%,弃用;高度与落差相关 0.95 且落差缺 78%—— 推补落差等于把高度放进模型两次,故弃落差留高度;时长缺 41%,用"长度÷极速"回归推补并全程带 * 标注 (推补的可靠性有专门评估)。一个基线实验显示预处理选择的分量:同一组权重下, 百分位与 min-max 两种归一化给出的 Top 10 只重合 1/10——归一化因此被当作正式的模型假设对待。 建模用榜内成对比较的逻辑回归(Bradley-Terry):投票人实际奖励的只有极速(+0.82)和长度(+0.41), 翻滚数系数为零——大众口味约等于"快而长"。只用时长实测的 69 台完整样本重训,系数几乎不变,结论不依赖推补。
模型对全库的预测经受了一次时间检验:它评为"被低估"的 Steel Dragon 2000, 次年(2019)真的以第 20 名进入 GTA 榜单。但稳健性检查同时暴露两个问题: 模型在木质榜上几乎失灵(tau +0.21 对钢质 +0.50);预测偏差最大的车各自凑成同一类—— 参数之外存在决定口碑的变量。对残差的分层置换检验把它定位到"谁建造、谁运营": 榜内名次与国家无关,与运营方显著相关(连锁园的车平均跑输参数约 8 个名次,p=0.037), 与制造商显著相关(组间方差占比 20%,p=0.029,GCI 与 CCI 两组均值差 22 个名次)。 全部数字可由随附脚本复现。
1 问题、数据与假设
问题。网上的"世界十佳过山车"榜单全是主观投票。原题要求:只用客观数值参数设计可复算的排名算法, 评出世界 Top 10,与线上榜单对比,设计推荐 App,并写一页非技术新闻稿。
数据。RCDB(rcdb.com)快照 rcdb_strict.csv,1744 行, 字段含名称、乐园、地点、运营状态、开业时间、材质、机型、长度、高度、落差、极速、翻滚数、最大倾角、时长。 标签用 Golden Ticket Awards 2018 的两张 top-50 榜单(业内发行量最大的投票奖项), 100 条榜单条目与数据库匹配上 97 条,匹配明细全部列在 3.1 的表 1。
假设(各带一句理由)。
- GTA 榜单的先后顺序是"大众偏好"的可用测量——它由数千名游乐行业读者投票产生;投票人偏北美的问题真实存在,第 4、5 节专门处理。
- 只排运营中的车——"世界最佳"应当买票能坐到。
- 缺失的时长可由长度与极速近似(2.4 节给出推补式和可靠性评估);推补值带 * 标注,其影响用划分实验单独检验(4.2 节)。
- 高度与落差高度冗余,二选一(2.2 节论证)。
- 改造过的车按现轨道的建造者归属(如 RMC 改造车归 RMC)——投票人坐的是现在的轨道。
2 数据预处理
2.1 缺失有三种长相
| 字段 | 缺失率 | 处置 |
|---|---|---|
| 高度 / 极速 / 长度 / 翻滚数 | 0% | 直接可用(快照按此预筛过) |
| 时长 | 41% | 可推补(2.4) |
| 落差 78% / 最大倾角 83% | 缺过大半 | 倾角弃用;落差另有冗余问题(2.2) |
数据还有两类脏东西,处理时都要留心:同名车(好几台 Viper、Colossus、Medusa——一律按记录处理,不按名字合并); 录入错误(Thorpe Park 的 Colossus,乐园一栏填成了城市名 Chertsey)。排名范围限定为运营中且核心字段齐全的 1207 台。
2.2 一个重复的维度:高度与落差
五个数值字段两两算相关系数(图 1)。高度与落差相关 0.95——物理上是一回事,爬多高决定摔多深, 同时计分等于同一个优点算两次。落差更贴近体验,但缺失 78%;如果用落差~高度回归推补(R²=0.904), 1207 台里 924 台的落差将是推补值,而推补公式是 落差 ≈ 0.95×高度 − 1.2—— 这个变量的四分之三就成了高度的化名。所以弃落差、留高度(缺 0%)。
图 1 · 五个数值字段的相关系数
高度×落差 r=0.95(橙框):物理同源,只能留一个。高度×极速 0.90 也很高,但极速另有独立信息(2.3)。
2.3 高度与极速的关系:一次物理检验
高度与极速相关 0.90,但两者都保留,因为极速有自己的信息。检验:用 1744 台全量数据拟合极速对高度(图 2)。 线性拟合 R²=0.815 表面够用(图 2a),但残差按高度分箱呈系统模式(图 2b:矮车段 −2.9 mph、中段 +3.3、 250 ft 以上 −15.2)——关系是弯的。改用能量守恒的形式拟合:
v = 5.43√h − 4.7,R² = 0.849
√(2g) 在 mph/英尺单位制下的理论值是 5.47,回归拟出 5.43,负截距对应摩擦(图 2c、2d)。 残差压平后剩下的离群点全是弹射车(Formula Rossa:高度 170.6 ft,极速 149.1 mph)—— 它们的速度不来自落差,这正是极速独立信息的来源,也是后文外推问题的伏笔。
图 2a · 线性拟合
图 2b · 线性模型的残差
图 2c · 根号模型 v = a√h + b
图 2d · 根号模型的残差
2.4 补时长:怎么补、补得多可靠
时长缺 41%。删列丢关键区分度(240 秒对 28 秒);删行让样本减半且缺失非随机;均值填充是评委点名批评的做法。 我们用时长对"长度÷极速"(按极速匀速跑完全程的时间)回归:在 702 台有实测时长的车上,R²=0.291(图 3)。
图 3 · 时长推补的可靠程度:R²=0.29 长什么样
竖着看任何位置:全速时间差不多的车,实测时长能差 100 秒以上。橙色带是回归的典型误差(±36 秒);灰色水平线是"猜全库平均"(±43 秒)。回归只比瞎猜好一点,但大方向不会错——推补值只用于预测,不驱动训练结论(4.2 划分实验验证)。
2.5 归一化的分量:一个警示实验
预处理的最后一步是把不同单位的特征变得可比(归一化)。这一步看起来最无害,实际分量最重,值得专门演示。 做一个最朴素的基线:不学习,手拍一组权重(极速 28%、时长 24%、高度 22%、长度 16%、翻滚 10%,仅作演示), 五个特征加权求和给全库打分——唯一改动的是归一化方式:百分位(这个指标上超过全库百分之几的车) 或 min-max(全库最小到最大压到 0~1)。
同一份数据、同一组权重,两张 Top 10 只重合 1 台(图 4)。 百分位抹平纪录之间的差距(456 ft 和 250 ft 都是前 1%,几乎同分),偏向各项均衡的机型; min-max 保留数值差距,偏向纪录保持者——Kingda Ka 在 min-max 榜第 7、百分位榜第 321。 作为对照,同一个矩阵上把加权求和换成 TOPSIS 算法,Top 10 只换 1 台: 结论对归一化的敏感,远超对算法的敏感。
图 4 · 同一份数据、同一组权重,两种归一化的 Top 12 对照
高亮三台:Steel Dragon 2000(橙,唯一双榜前十)、Kingda Ka(蓝,min-max 第 7 → 百分位第 321)、Steel Vengeance(绿,百分位第 2 → min-max 第 17)。
这个教训贯穿后文:第 3 节的模型对特征做 z 标准化并在正文写明——归一化不是预处理的技术细节, 是和权重同级的模型假设,必须当作假设来交代。
2.6 预处理小结
| 项目 | 结果 |
|---|---|
| 排名范围 | 运营中且核心字段齐全,1207 台 |
| 最终特征 | 极速、高度、长度、时长、翻滚数(标准化) |
| 弃用 | 落差(与高度冗余)、最大倾角(缺 83%) |
| 推补 | 时长 505 台(42%),全程带 *,不驱动训练结论 |
| 标签 | GTA 2018 两张 top-50,进入建模 96 台 |
3 建模:把榜单变成比赛
3.1 标签:两张榜单的原委
标签的来历值得完整交代,因为整个模型学到的东西,含义都由它决定。
我们需要的是"大众偏好"的测量。逐车打分的评分网站有两个先天问题:不同人打分手松手紧、 五星制十分制混在一起,跨人不可比;而且逐人打分的原始数据大多不公开。榜单没有这些毛病—— 它是把很多人的意见用同一套程序聚合成的一个顺序。我们选的是 Golden Ticket Awards(GTA): 美国游乐行业刊物 Amusement Today 每年颁发的奖项,业内称作游乐园界的"奥斯卡"。 机制是杂志邀请一批阅历足够的资深投票人(要求坐过的车足够多、跨区域),各自提交选票, 加权汇总后发布钢质、木质各一张 top-50。选它的理由有三:年份与原题对齐(2018); 两张 50 名的榜单合计给出约 100 个标签,覆盖面够大;程序年年稳定——这让我们能拿 2019 年的同一榜单 做时间外检验(4.2 用到)。
下载到的两张榜单全文如表 1(* = 榜单名称与数据库记录不一致、靠模糊匹配加人工核对; † = 数据库快照里没有这台车,只能放弃):
| # | 钢质榜 | # | 木质榜 |
|---|---|---|---|
| 1 | Fury 325 | 1 | Phoenix |
| 2 | Millennium Force | 2 | El Toro |
| 3 | Steel Vengeance | 3 | Voyage |
| 4 | Expedition GeForce | 4 | Boulder Dash† |
| 5 | Superman: The Ride | 5 | Beast |
| 6 | Apollo's Chariot | 6 | Lightning Rod† |
| 7 | Iron Rattler | 7 | Outlaw Run |
| 8 | Leviathan | 8 | Ravine Flyer II |
| 9 | Maverick | 9 | Gold Striker |
| 10 | Diamondback | 10 | Thunderhead |
| 11 | Nitro | 11 | Mystic Timbers |
| 12 | Intimidator 305 | 12 | Lightning Racer |
| 13 | Phantom's Revenge | 13 | GhostRider |
| 14 | Magnum XL-200 | 14 | Balder |
| 15 | Taron | 15 | Thunderbolt |
| 16 | Top Thrill Dragster | 16 | Wodan* |
| 17 | Mako | 17 | Wildfire |
| 18 | Time Traveler | 18 | Raven |
| 19 | Blue Fire* | 19 | Goliath |
| 20 | Nemesis | 20 | Jack Rabbit |
| 21 | Helix | 21 | Giant Dipper |
| 22 | Intimidator | 21 | Shivering Timbers |
| 23 | New Texas Giant | 23 | Legend |
| 24 | Twisted Colossus | 24 | White Lightning |
| 25 | Mind Bender | 25 | Troy |
| 26 | Goliath | 26 | Renegade |
| 27 | Behemoth | 27 | Cu Chulainn |
| 28 | Montu | 28 | Colossos* |
| 29 | Banshee | 29 | Cyclone |
| 30 | Skyrush | 30 | Prowler |
| 31 | X2 | 30 | Rampage |
| 32 | Alpengeist | 32 | Comet |
| 33 | Wicked Cyclone | 33 | Boardwalk Bullet |
| 34 | Black Mamba | 34 | Flying Turns |
| 35 | Cheetah Hunt | 35 | Rutschebanan* |
| 36 | Verbolten† | 36 | Switchback |
| 37 | Kumba | 37 | Blue Streak |
| 38 | Twisted Timbers | 38 | American Thunder |
| 39 | Jetline | 38 | Screamin' Eagle |
| 39 | Superman Ride of Steel | 40 | Grizzly |
| 41 | Goliath | 41 | Blue Streak |
| 42 | Lisebergbanan | 42 | Playland Wooden Coaster* |
| 43 | Griffon | 43 | Boss |
| 44 | Cannibal | 44 | Wild One |
| 45 | Shambhala | 45 | T Express |
| 46 | Expedition Everest | 46 | Megafobia |
| 47 | Storm Chaser | 47 | Hades 360 |
| 48 | Raging Bull | 48 | Mine Blower |
| 49 | Thunderbird | 49 | Wooden Warrior |
| 50 | Whizzer | 50 | Twister |
(木质榜的 21、30、38 名各有并列,所以名次有重复。)与 RCDB 快照按"名称+乐园"匹配:100 条对上 97 条。 5 条模糊匹配的对应关系显式列出,每条都人工核对过是同一台车:
| 榜单原文 | 数据库记录 |
|---|---|
| Blue Fire | blue fire Megacoaster |
| Wodan | Wodan Timbur Coaster |
| Colossos | Colossos - Kampf der Giganten |
| Rutschebanan | Rutschebanen |
| Playland Wooden Coaster | Coaster(PNE Playland) |
另一个陷阱是同名车:榜上有三台 Goliath(Six Flags Over Georgia、La Ronde、Six Flags Great America 各一台) 和两台 Blue Streak(Conneaut Lake、Cedar Point),必须靠乐园字段区分,按名字合并就全错了。 97 条匹配里还有一条要交代:木榜 30 名(并列)的 Rampage,数据库把它的乐园记成了别名, 自动匹配不稳定,保守弃用——最终进入建模的是 96 台。 整张标签表(含每条的匹配结果)即 class05-gta2018-labels.csv。
我们拿到的是聚合后的名次,不是任何人的选票。"A 胜 B"指投票人群体的汇总意见把 A 排在 B 前; 钢榜和木榜是两次独立的汇总,只在榜内配对、不跨榜配对。
由此有一个必须写明的统计事实:这些"对"不是独立观测。以四台车的迷你榜单 A>B>C>D 为例, 可以配出 6 对——A-B、A-C、A-D、B-C、B-D、C-D——但其中 A-C、A-D、B-D 三对完全由 A>B、B>C、C>D 这三个相邻判断推出:6 对里只有 3 份独立信息。同理,一张 50 名的榜单派生 1225 对, 独立信息只有 49 个相邻判断;两张榜共 2300 对,实际信息量就是两个排序本身。 因此本文所有区间按"车"整台重抽(bootstrap)、所有 p 值按"车"做置换,不使用按对数计算的标准误—— 那等于把 2300 当成样本量,会严重高估精度。
这份标签还有两个先天的偏,后文都会撞上:投票人集中在北美——"能否上榜"受地理影响 (4.3 的 Formula Rossa、Hyperion);top-50 只露出头部——"没上榜"不等于"差",只是没被看见, 这个外推问题在 3.2 正面处理。若能拿到逐人选票(历史上 Mitch Hawker 的木质过山车年度调查收的就是这种数据, 能算任意两台车的真实交手胜率),才能做个体级的对决模型,并顺带处理"每个投票人坐过哪些车"的问题。
3.2 样本怎么分
表 1 里匹配成功、进入建模的 96 台,就是全部带标签的样本。1207 台运营中的车由此分成两类。 训练集 96 台:其中 27 台的时长是推补值,这部分"数据不齐"的样本另做一个划分实验—— 从训练中剔除、只当检验集用(4.2)。预测集 1111 台:没有标签,不是因为它们差, 而是投票人根本没坐过(3.1 说的头部截断)。模型会给这 1111 台打分,但那是外推; 什么时候可信、什么时候不可信,第 4、5 节回答。
3.3 方法的本质:两两对决 + 一条 S 形曲线
榜单不是打分——没人给 50 台车各打一个可比的分数——但榜单蕴含大量"谁在谁前面"的判断。 把每张 top-50 拆成两两对决(A 排在 B 前 = A 胜 B 一场),两张榜共 2300 场"比赛"。 给每台车一个分数,用一条 S 形曲线(logistic)把分差变成胜率: 分差大 → 胜负几乎确定;分差小 → 接近掷硬币。
分数从哪来,是这个方法和棋类 Elo 的关键区别。Elo 给每个棋手一个自由的分数,靠输赢直接调整—— 照搬过来,每台车会得到一个自由分数,但那只是把榜单顺序重新编码一遍:学不到"什么参数让车受欢迎", 也没法给从未上榜的 1111 台打分。我们把每台车的分数锁死为参数的线性组合: 分数 = w₁×极速 + w₂×高度 + w₃×长度 + w₄×时长 + w₅×翻滚数(都用 z 值),车没有自由分数, 五个 w 是模型里唯一可调的量。训练就是调这五个数:给定一组 w,每台车立刻有分、每场对决立刻有预测胜率; 把 2300 场"实际胜者恰好获胜"的概率乘起来,就是这组 w 的成绩;找出让成绩最大的那组 w—— 3.4 表里的系数就是它。
搜索这组 w 的具体步骤(全部代码约 30 行,在 class05-bt-rank.py 里):
- 从 w 全零出发——此时所有车同分,每场对决都判 50:50;
- 每一轮,对 2300 场对决逐场算当前的预测胜率 p,并累加"推力":实际胜者与败者的特征差 ×(1−p)。一场对决预测得越离谱(实际赢家的 p 越小),推力越大;已经预测很准的对决(p 接近 1)几乎不再出力;
- 把 w 沿 2300 场推力的合力挪一小步(步长 0.1),同时轻微向零收缩(正则化,防止 96 台的小样本把系数推到离谱);
- 重复约一千轮,w 不再移动即收敛。
直觉版:每场对决都在投票——榜单说 Fury 325 赢了 Whizzer,而当前 w 给 Whizzer 更高分, 这场就把 w 往"抬高 Fury 强项、压低 Whizzer 强项"的方向推一点。 这套"错得越狠推得越重"的更新就是逻辑回归的梯度上升。
把分数绑在参数上,代价与好处同源:学到的是参数与偏好的关系(可解释),没比过赛的车也能打分(外推的基础); 但参数相同的两台车必然同分——模型天生说不出"同参数、不同口碑",这正是第 5 节残差分析的出发点。
图 5 · 分差怎样变成胜率:三场真实对决
悬殊对决(Fury 325 对 Whizzer,分差 2.57)模型给 93%;前二之争(Fury 对 Millennium Force,分差 0.07)它诚实地说"掷硬币"(52%);Nitro 对 Diamondback 给了 56% 却猜反了——相邻名次本来就在误差里。
搜索过程本身画在图 6:五个系数从零出发,约 300 轮后基本稳定。最有信息量的是高度那条线—— 前 30 轮它跟着极速一起上升(两者相关 0.90,速度的功劳起初被两个特征平分), 随后被极速一步步挤压,120 轮左右转负,最终停在 −0.24。3.4 里那个看似反直觉的负系数不是谁拍板的假设, 是 2300 场对决拉锯出来的结果。
图 6 · 训练过程:五个系数从零到收敛
高度(橙)先随极速上升到 +0.14,随后被相关 0.90 的极速(蓝)逐步挤成负值——负系数是拉锯的结果,不是预设。约 300 轮后五条线都不再移动。
3.4 学到的口味
全部 96 台训练的系数(标准化特征,bootstrap 95% 区间见图 7):
图 7 · 学到的系数及 bootstrap 95% 区间
只有极速(+0.82)和长度(+0.41)稳在零的右侧;高度、时长、翻滚数全部跨零。强相关的极速+高度按 4.1 的结果报两者合计(最下行,稳定为正)。
三个结论。其一,大众口味约等于"快而长":只有极速和长度的区间稳在零的右侧。 其二,翻滚数是干净的零——单用翻滚数排序 tau 还是负的(钢 −0.45、木 −0.86),翻滚多的车在榜上反而靠后。 其三,控制极速后高度没有独立正贡献;高度和极速相关 0.90,按 4.1 的结果,单个系数不下结论, 报两者合计:[+0.27, +0.94],稳定为正。
负的高度系数有一个直观读法:给定速度,矮的车更受青睐——模型在给"速度的性价比"记账。 实例:Taron(98 ft / 73 mph,弹射)与 Fujiyama(259 ft / 81 mph)模型同分 +2.12, 前者少用 161 英尺换到了几乎同样的速度;投票人也这么想——Taron 排钢榜第 15, Maverick(105 ft / 70 mph)排第 9,而"堆高换速度"的巨塔在榜内并不讨好。
打分的算法只有一行:每个特征减全库均值、除以标准差得到 z 值,再乘上上表刚学到的对应系数,五项相加。 z 值只负责把 95 mph 和 8133 ft 换算到同一把尺上;每项值多少分,由学到的系数决定—— 学习的产出就是这五个乘数。用一台不在训练集里的车把这一行算完整—— Steel Dragon 2000(2018 年两榜均未收录):
| 特征 | 原始值 | 全库均值 | 标准差 | z 值 | ×学到的系数 | 贡献 |
|---|---|---|---|---|---|---|
| 极速 | 95 mph | 42.3 | 16.6 | +3.18 | +0.822 | +2.62 |
| 高度 | 318.3 ft | 82.6 | 53.1 | +4.44 | −0.240 | −1.07 |
| 长度 | 8133 ft | 1926 | 1229 | +5.05 | +0.405 | +2.05 |
| 时长 | 240 s | 103.1 | 35.0 | +3.91 | −0.169 | −0.66 |
| 翻滚数 | 0 | 1.2 | 1.8 | −0.64 | +0.043 | −0.03 |
| 总分 | +2.91 |
+2.91 使它在 1111 台未上榜车里排第 4:极速和长度两项巨大的正贡献压过了高度、时长两项的负贡献。 对照一下"不学习"的情形:若五个 z 直接相加(等于五项等权),这台车会得 +15.9, 且高度成为最大加分项——学到的系数正是把这份等权直觉修正成投票人的真实口味。 这个分数后来的命运见 4.2 的时间外检验。
这些系数只能按"榜内梯度"读,不能按"配方"读:标签车的极速集中在 45–95 mph,榜内已有饱和迹象—— 在榜最快的 Top Thrill Dragster(120 mph)只排第 16,前三名的极速是 95、93、74。 把车造得更快更长,并不能按系数比例买到口碑。
4 稳健性检查
4.1 强相关的两个特征,各自的系数说了不算
高度与极速相关 0.90,直接报单个系数有陷阱,用一个能看清答案的实验演示。 做法:取 384 台高度、落差、极速都有实测的车,用"高度+落差"这对强相关特征(相关 0.95)预测极速; 从这 384 台里有放回重抽同样多的车,重新拟合,记下两个系数和 R²;重复 200 次, 取各量的 2.5%–97.5% 分位当区间。再把每次重抽的规模改成 50 台(榜单标签的量级)重做一遍:
| n=384 | n=50 | |
|---|---|---|
| R²(预测) | 0.906 [0.88, 0.93] | 0.909 [0.85, 0.96] |
| 高度系数 | +0.10 [−0.00, +0.25],翻符号 7/200 | +0.10 [−0.24, +0.56],翻符号 62/200 |
| 落差系数 | +0.86 [0.72, 0.96] | +0.85 [0.41, 1.18] |
| 两系数之和 | +0.956 [0.943, 0.967] | +0.957 [0.92, 0.98] |
看 n=50 那列:预测精度纹丝不动(R² 稳在 0.9 上下),高度的单独系数却每三次有一次符号是反的, 而两系数之和始终稳定。预测稳,不代表能说清各自的功劳:小样本下, 强相关的一对特征只报两者合计的贡献。全文照此执行。
4.2 对没见过的样本表现如何:三个检验的做法与结果
交叉验证。96 台在榜车随机均分五折;划分单位是车、不是对——3.1 说明过对不独立, 若按对分折,同一台车会同时出现在训练与检验两侧。每轮留出一折,用其余四折的榜内对训练, 在留出的车之间统计 Kendall tau(预测顺序与榜单顺序一致的对数减不一致的对数,除以总对数; +1 全对,0 等于乱猜)。整个过程画在图 8:五轮划分、每轮在留出的钢车之间和木车之间各算一个 tau (对子只在同材质内数,榜单不跨材质可比),十个数从 +0.05 到 +0.73,均值 +0.34; 换一个随机种子重新分折,均值 +0.29。折间抖动如此之大,说明 96 台样本下任何单次评估都不可精读, 正文因此只报"约 +0.3"。补充两点:分折未按材质分层,五折的钢/木构成为 12/8、8/11、10/9、10/9、9/10, 均超过"至少 5 台才计 tau"的门槛;按材质分层重跑,两个种子的均值为 +0.31 与 +0.31—— 结论不变,且种子间更稳,正式做法应首选分层。
图 8 · 五折交叉验证:每轮谁被留出,各得多少分
十个 tau 从 +0.05 抖到 +0.73(竖线为均值 +0.34)。钢的得分在五轮中四轮高于木——模型猜钢车准、猜木车不准,这个系统性差距在 4.3 展开。各折钢/木台数:12/8、8/11、10/9、10/9、9/10。
完整性划分(假设 3 的验证)。做法:把 96 台在榜车按"时长是否实测"切开—— 69 台实测的进训练,27 台推补的完全不进训练、只当检验集。两组系数对照:
| 特征 | 全部 96 台训练 | 只用 69 台完整样本 |
|---|---|---|
| 极速 | +0.82 | +0.87 |
| 长度 | +0.41 | +0.59 |
| 高度 | −0.24 | −0.32 |
| 时长 | −0.17 | −0.21 |
| 翻滚数 | +0.04 | +0.06 |
五个系数方向全同、大小相近——"快而长"不是推补数据造出来的。再看检验集:模型没见过的 27 台推补车, 内部排序的 tau 是钢质 +0.50(14 台)、木质 +0.13(13 台)。钢质和训练集内水平一样, 说明推补不是主要误差源;木质照崩——这个信号先记下,4.3 要用。
时间外检验。做法:给 1207 台全部打预测分,去掉在榜的 96 台, 剩下预测分最高的就是"模型认为被低估"的名单;然后抓 2019 年的 GTA 钢质榜,逐台核对:
| 候选(未上榜车中预测分名次) | 2019 年结果 |
|---|---|
| Formula Rossa(1) | 未上榜(Captain Coaster 全球第 58;地理因素,见 4.3) |
| Do-Dodonpa(2) | 未上榜(后因 18 起乘客骨折停运,2024 年永久关闭) |
| Kingda Ka(3) | 未上榜(2024 年底停运,2025 年拆除) |
| Steel Dragon 2000(4) | 上榜,第 20 名 |
| Red Force(5) | 未上榜 |
| Hyperion(6) | 未上榜(玩家社区评为欧洲最佳 hyper 之一) |
一次干净的命中——用 2018 年的数据提前指出了次年的上榜者;外加一整排落空。 落空的成分为什么如此一致,是 4.3 和第 5 节的主题。
4.3 检查中发现的两个问题
问题一:模型在木质榜上几乎失灵。钢榜 in-sample tau +0.50,木榜只有 +0.21; 4.2 划分实验的检验集上,木质只有 +0.13。木质车的口碑几乎和参数无关——模型缺了某个东西, 而且这个东西在木车上作用更大。
问题二:预测偏差最大的车,各自凑成同一类。名次远好于参数预测的: Phoenix(GTA 第 1 / 预测第 38)、Time Traveler(+28 个名次)、Iron Rattler(+24)、 Gold Striker(+24)、Nemesis(+21)——全是以做工和乘坐体验著称的车。 参数远好于名次的,就是 4.2 时间外检验表里那串落空者,外加 Boss(−39)、T Express(−37)、 Hades 360(−36)这类失修木车——全是"参数漂亮、坐起来不行"的类型 (弹射纪录机里两台后来一台伤人关闭、一台被拆除)。随机误差不会挑主题; 两串名单各自成分如此一致,说明预测偏差不是随机的。(Formula Rossa 单独注脚: 在投票人以欧洲玩家为主的 Captain Coaster 上它排全球第 58——它的 GTA 缺席大头是投票人的地理构成, 这提示"上不上榜"和"榜内排第几"受不同因素支配。)
两个问题指向同一个方向:参数表之外有一个系统性的变量在起作用。第 5 节直接到数据里找它。
5 隐藏参数
思路:如果模型没缺变量,残差(预测名次 − 实际名次)应该谁也解释不了;反过来, 拿模型没用过的字段去解释残差,解释得动,就说明缺的变量和那个字段有关。 我们把数据里现成的、以及公开登记可查的字段逐个试了一遍。
5.1 过程与结果
以运营方为例,把完整过程走一遍(全部步骤在 class05-bt-decomp.py 里,一条命令复现):
- 对 96 台在榜车各算一个残差,得到 96 个数;
- 按"乐园名是否以 Six Flags 开头"分两组:17 台对 79 台,组均值 −7.6 对 +0.2,差 7.8 个名次;
- 检验这个差是不是运气:把 96 个残差随机重排、重新分成 17+79 两组再算组差,重复 5000 次——能凑出 ≥7.8 的只有约 3.7%,即 p=0.037。乐园名的前八个字母本不该有任何预测力,它显著了。
同一过程换上其余分组变量(多组时统计量换成组间方差占比,置换手续不变):
| 分组层 | 结果 | 判定 |
|---|---|---|
| 国家 | R²=0.02,p≈0.7 | 无信号:榜内名次与国籍无关(地理只影响"能否上榜") |
| 运营方(乐园名以 Six Flags 开头,纯字符串判定) | 连锁 −7.6 vs 其他 +0.2,p=0.037 | 显著:连锁园的车系统性跑输参数约 8 名 |
| 乐园(≥2 台在榜的 23 个园) | R²=0.38,p=0.36 | 方向一致,检验力不足(每园 2–4 台) |
| 机型 | 悬挂式 +9.0(n=5),p=0.11 | 不显著 |
| 车龄(木榜内) | 相关 +0.05 | 否决"老木车吃情怀分":1920 年的 Jack Rabbit 跑赢 +20,1976 年的 Screamin' Eagle 跑输 −25 |
| 节奏代理(长度÷实测时长) | 相关 −0.23 | 不支持 |
5.2 制造商:同一过程,分组变量换成建造者
分组变量换成"现轨道的建造者"——公开登记信息,96 台的标注表写在 class05-bt-mfr.py 里逐条可查 (改造车按现轨道归属,见假设 5)。n≥3 的 10 组覆盖 90 台,组间方差占比 R²=0.20, 置换检验 p=0.029:
| 制造商 | n | 组均值 | 制造商 | n | 组均值 |
|---|---|---|---|---|---|
| Mack | 3 | +14.7 | B&M | 20 | −2.8 |
| GCI | 11 | +10.1 | 乐园自建 | 10 | −4.6 |
| RMC | 10 | +2.5 | Gravity Group | 8 | −4.6 |
| Schwarzkopf | 4 | +2.0 | Intamin | 14 | −6.4 |
| PTC | 5 | +0.2 | CCI | 5 | −11.8 |
两端差 22 个名次:GCI(以顺滑耐用著称)对 CCI(以老得快闻名,The Boss 粗暴到 2018 年被砍掉终场螺旋)。 Intamin −6.4 与 4.3 的弹射纪录机现象同源——它家在榜的多是"参数容易高估"的巨型规格机。
5.3 这些结果合起来说明什么
残差不随国家变(榜内)、不随机型和车龄变,却随"谁建造"(p=0.029)和"谁运营"(p=0.037)变。 一个固定在单台车上、跟着建造者和运营方走的变量,最合理的解释是车的做工和保养状态—— 参数表里没有这一列。极端个案吻合:跑输 −19 名的 Colossos,2016 年被 TÜV 判定轨道不可运营、 停运三年花 1200 万欧元换轨——2018 年投票时它根本坐不了。 要把这一列真正补上:制造商字段扩到全库、给运营方分类,是马上可做的两列; 玩家社区的众包乘坐质量标签是第三列。
6 结论
三条。(i) 预处理的每个选择都在改答案:落差和高度是同一件事,只能算一次; 归一化换一种,Top 10 十换九(2.5)。这些选择必须写在明面上。 (ii) 榜单可以当标签用:学出来的大众口味是"快而长",模型通过了三种检验 (换折、剔除推补样本重训、次年榜单对照),对 Steel Dragon 2000 的预测一年后应验。 但系数只在榜单覆盖的范围内成立——把车造得更快,名次不会按比例上涨 (在榜最快的 Top Thrill Dragster 只排第 16)。 (iii) 参数表算不出口碑的全部:预测偏差跟着"谁建造、谁运营"走, 缺的是一列"做工和保养状态";要补上它,得引入制造商等新字段。
优点。全流程可复现(六个脚本,数字与正文一一对应);缺失值处理有论证、有标注、有专门的划分实验; 结论带不确定度(bootstrap 区间、置换检验 p 值);用次年榜单做了真正的时间外验证。
弱点。标签只覆盖头部车辆且偏北美,对全库的预测是外推;时长推补很弱(R²=0.29); 制造商只标注了 96 台在榜车;隐藏变量被定位但未被直接测量。
参考资料。COMAP,HiMCM 2018 Problem A 及评委 commentary(Consortium 116); RCDB(rcdb.com,数据快照);Golden Ticket Awards 2018 钢质/木质 top-50 与 2019 钢质榜(goldenticketawards.com); Captain Coaster(全球排名及个别车辆页面);Wikipedia:The Boss、Colossos – Kampf der Giganten、 Do-Dodonpa、Kingda Ka(停运与拆除报道)。
数据与代码。rcdb_strict.csv(原始数据)、 class05-gta2018-labels.csv(标签:GTA 2018 两张榜单及匹配结果)、 class05-collinearity-demo.py(4.1 实验)、 class05-bt-rank.py(建模与名单)、 class05-bt-split.py(4.2 划分实验)、 class05-bt-decomp.py(5.1 分层检验)、 class05-bt-mfr.py(5.2 制造商表)。 配套课件:课堂练习、 交互题解(含归一化对比、权重滑杆排名器、bootstrap 演示等课堂内容)。