它想解决什么问题?
当直飞航班太贵、时间不合适,或者已经没有余票时,平台通常会推荐“附近航班”。比如,你原本要从北京出发,系统也可以推荐天津出发的航班;你原本计划周五走,也可以看看周四或周六的选择。
问题是,附近航班并不是越便宜越好。便宜 200 元,但要多坐两小时高铁去另一个机场,对很多人并不划算;晚一天出发即使价格更低,也可能完全不符合行程安排。传统方法通常依赖固定规则,很难回答一个关键问题:
面对同一个替代方案,不同用户究竟愿意为低价做出多大让步?
CPNet 是怎么做的?
CPNet 主要从三个角度理解用户的选择。
第一,学习用户的个人偏好。模型会结合用户过去看过和购买过的航班,判断他更在意价格、出发时间、机场位置,还是航空公司。这样,同一趟附近航班面对不同用户时,可以得到不同的推荐结果。
第二,学习用户过去为类似方案付出的代价。模型不仅看用户买过什么,还会比较当时的原始需求与最终选择。例如,一个用户多次为了节省几百元接受邻近机场,说明他对价格更敏感;另一个用户始终坚持原机场,则可能更重视便利性。
第三,把候选航班放回当前列表中比较。一张票是否值得推荐,不能只看它自身,还要看它相对其他航班便宜多少、需要多走多远、时间改变多少。CPNet 会学习这些“额外成本”与“潜在收益”,判断替代方案是否真的值得。
背后的理论与公式
理解 CPNet,可以先把附近航班看成一次“用不方便换低价”的交易。设原始方案价格为 $p_0$,附近航班价格为 $p_i$,那么用户获得的价格收益是:
\[\Delta p_i=p_0-p_i\]但用户也要付出额外成本,例如多走的距离 $\Delta d_i$ 和改变的出发时间 $\Delta t_i$。于是,附近航班对用户 $u$ 的净价值可以简化写成:
\[U_{u,i}=w_u^p\Delta p_i-w_u^d\Delta d_i-w_u^t|\Delta t_i|\]这个公式的意思很直接:省下的钱是收益,额外距离和时间变化是成本。$w_u^p$、$w_u^d$、$w_u^t$ 表示用户对价格、距离和时间的重视程度,它们因人而异。价格敏感的用户会有更大的 $w_u^p$,重视便利性的用户会有更大的 $w_u^d$ 或 $w_u^t$。
这些个人权重不能凭空设定,需要从历史选择中学习。设用户过去有 $T$ 次行为,模型会根据每次经历与当前航班 $i$ 的相似程度分配权重:
\[\alpha_t=\frac{\exp(g(b_t,i))}{\sum_{k=1}^{T}\exp(g(b_k,i))}, \qquad h_{u,i}=\sum_{t=1}^{T}\alpha_t b_t\]$b_t$ 是第 $t$ 次历史行为,$g(b_t,i)$ 衡量它与当前航班的相关性,$\alpha_t$ 则表示模型应该参考这段经历多少。所有 $\alpha_t$ 都大于等于 0,并且总和为 1,因此当前结果是相关历史行为的加权总结,而不是被某一条无关记录随意左右。
最后,排序关心的是两个候选谁更好。候选 $i$ 排在候选 $j$ 前面的概率可以写成:
\[P(i\succ j\mid u)=\sigma(U_{u,i}-U_{u,j})\]如果 $U_{u,i}>U_{u,j}$,那么这个概率就大于 0.5。与此同时,$U_{u,i}$ 对价格收益的偏导为 $w_u^p>0$,对额外距离的偏导为 $-w_u^d<0$。这说明在其他条件不变时,省钱越多越值得推荐,额外路程越长越不值得推荐;不同用户的权重不同,因此最终排序也不同。CPNet 的三个模块,本质上就是在学习这些个人权重、历史成本和候选之间的相对收益。
一句话类比
CPNet 像一位了解你的旅行顾问:
“这趟航班虽然要从天津出发,但能省不少钱,而且你过去愿意接受类似安排,所以值得推荐;换成更在意便利性的用户,就不应该排得这么靠前。”
效果
论文在真实生产数据上进行了离线实验和大规模线上实验,结果均优于对比方法。CPNet 已部署到飞猪的附近航班推荐场景,为大量用户提供个性化的替代行程推荐。