交通 | 司乘匹配:基于增量成本计算的优化算法

在这里插入图片描述

编者按:

司乘匹配是打车服务中一项至关重要的任务,如果这一步做得不够优化,可能导致乘客需要更长的时间才能到达目的地,同时司机的收入也会因此减少。由于司乘匹配是一个持续进行的过程,每一时刻都在不断涌入新的打车订单和新的司机,这使得计算最优匹配成为一项非常具挑战性的任务。今天解读的这篇文章是由东南亚打车公司Grab在2021年发表于数据库顶会VLDB [1],并被评选为当年的Best Scalable Data Science Paper。作者发现了一个有意思的事情,最优匹配问题中最常用的Kuhn-Munkres算法(也称为匈牙利算法)中的一步对算法的效率提升有很大的影响,并且作者还用实际场景中观察到的一个特性来改进算法,今天我们将结合作者自己曾经写过的技术博客 [2],来从一个全新的角度探讨司乘匹配问题。
[1] Tenindra Abeywickrama, Victor Liang, and Kian-Lee Tan. 2021. Optimizing bipartite matching in real-world applications by incremental cost computation. Proc. VLDB Endow. 14, 7 (March 2021), 1150–1158
[2] https://engineering.grab.com/using-real-world-patterns-to-improve-matching

一、引例

在这里插入图片描述
图1. 司乘匹配场景示例

让我们从图1所示的简单匹配场景开始来介绍一些基础的概念,假设有三位司机(D1、D2 和 D3)和三位乘客(P1、P2 和 P3),乘客和司机是通过行驶时间来进行匹配的,找到行驶时间涉及计算从每位司机到每位乘客的最快路径,例如从 D1 到 P1、P2 和 P3 的虚线路径。为了找到最小总行驶时间的司乘分配方案,我们可以把问题表示为下面显示的二分图。在二分图中,乘客集合和司机集合分别构成二分图的两个集合,连接它们的边代表着最短路径,相对应的行驶时间如右侧矩阵所示,这个矩阵我们称它为成本矩阵。寻找两个集合间的最优分配也被称为解决最小权重二分匹配问题(也称为分配问题),一种常用来解决这个问题的算法叫Kuhn-Munkres(KM)算法(也称为匈牙利算法)。回忆一下,KM算法的原理是在不断迭代更新二分集合 𝑈(相应地,𝑉)的一组标签 l u l_u lu(或 l v l_v lv),以生成降低的成本 c r ( u , v ) = c ( u , v ) − l u − l v c_r(u,v)=c(u,v)-l_u-l_v cr(u,v)=c(u,v)lulv为零的边。如果在这些边之间存在完美匹配,那么这个匹配就是最小权重二分匹配问题的最优解。用KM算法来求解以上示例,我们会得到成本矩阵上标红的最优匹配方案,即 P 1 − D 1 , P 2 − D 3 , P 3 − D 2 P_1 -D_1, P_2 -D_3, P_3 -D_2 P1D1,P2D3,P3D2。然而到目前为止,我们都还没有涉及到和成本矩阵计算相关的事情,而事实证明,在实际场景中,这一步对计算性能有相当大的影响。那么接下来,我们就来讨论一下有关成本矩阵计算的影响。

二、成本矩阵的计算

在这里插入图片描述
图2. 针对不同m值成本矩阵计算与分配的时间比

我们发现在以往解决分配问题的研究里大多都假设成本矩阵是作为输入给定的,但在实际场景中,我们观察到计算成本矩阵所需要的时间实际上是非常值得关注的。首先,司乘匹配是一个连续的过程,成本会随着司机的移动和新的订单的接收而不断变化。这意味着即使是间隔几秒钟,都有可能需要重新计算一次成本矩阵。其次,寻找单个乘客和司机之间的最短路径就需要不低的算力,而我们需要为所有可能的司机乘客对进行此操作,由此可想算力上可能会面临的挑战。作者发现在实际问题中,计算成本矩阵所需的时间甚至比计算最优分配所需的时间更长!

我们先浅浅地来从时间复杂度来看一下为什么是如此。如果 m m m代表我们试图匹配的司机/乘客的数量,那么KM算法的时间复杂度为 O ( m 3 ) O(m^3) O(m3);如果 n n n代表道路网络中的顶点数,那么使用Dijkstra最短路径搜索算法计算成本矩阵的时间复杂度为 O ( m n l o g n ) O(mnlogn) O(mnlogn)。我们知道新加坡道路网络的节点数 n n n大约为400,000(对于更大的城市而言,这个数值更大),因此我们可以合理地期望在实际场景中(一般m小于1500), O ( m n l o g n ) O(mnlogn) O(mnlogn)将占主导地位。我们在新加坡的道路网络上进行了实验来验证这一点,如图2所示。在图2(a)中,我们可以看到当 m m m小于等于2500时,计算矩阵的时间主导了寻找最优匹配的时间。即使我们使用像Contraction Hierarchies这样更现代快速的方法来计算最快路径,这样的观察结果仍然成立,如图2(b)所示。这表明如果我们能够减少矩阵计算时间,整体的匹配效率就可以得到显著提高。

三、匹配的空间局部性

在这里插入图片描述
图3. 匹配的空间局部性场景示例

在研究乘客和司机的实际位置时,我们观察到了一个有趣的属性,我们将其称为“匹配的空间局部性”。我们发现,在最优匹配中,分配给每个司机的乘客是距离该司机最近的乘客之一(可能不是最近的)。这一点是非常直观的,因为乘客和司机是分布在整个城市的,而对于特定的司机来说,最优匹配不太可能出现在城市的另一边。

在图3中,我们可以看到一个展示这个属性的场景示例图,虽然这是一个理想化的示意图,但它也并没有太偏离实际情况。从所示的成本矩阵中,我们可以很容易地看出怎么样分配将提供最小的总行驶时间。现在,有了这样的直觉,我们想要考虑的问题是,我们到底有没有必要计算出完整的成本矩阵来找到最优匹配?比如,我们是否可以避免计算从 D3 到 P1 的成本,因为它们相隔太远,所以根本不太可能匹配?

四、改进后的KM算法

在这里插入图片描述
图4. 增量KM算法实现的框架

我们发现确实有一种方法可以利用匹配的空间局部性来减少成本计算的时间。作者提出了一种叫增量KM的算法,意思是仅在需要时才去计算成本,以有效的避免计算所有成本。修改过的KM算法采用了一种便捷的下界技术来实现这一点。我们用地标下界(Landmark Lower-Bounds, LLBs)作为最短路径的下界值,它所用到的核心思想其实就是三角不等式,不仅通俗易懂,还可以以较低的计算成本求出来。具体来讲,LLBs需要随机选择 𝑘 个“地标”顶点,并在离线预处理步骤中计算从每个地标到道路网络中所有顶点的距离并储存起来。在线上阶段,再用到任意地标顶点 𝑙 的距离以及三角不等式 L B l ( q , p ) = ∣ d ( l , q ) − d ( l , p ) ∣ ≤ d ( q , p ) LB_l(q,p)=|d(l,q)-d(l,p)| \leq d(q,p) LBl(q,p)=d(l,q)d(l,p)d(q,p)就可以计算出任意两个顶点 q q q p p p之间的下界距离。通过考虑所有 𝑘 个地标的最大下界 L B m a x ( q , p ) = max ⁡ l ∈ L ( ∣ d ( l , q ) − d ( l , p ) ∣ ) LB_{max}(q,p)=\max\limits_{l \in L}(|d(l,q)-d(l,p)|) LBmax(q,p)=lLmax(d(l,q)d(l,p)),我们发现即使对于较小的 𝑘 值,仍然可以计算出令人惊讶准确的最短路径下界。

除此之外,我们还用到数据库领域一个非常经典的概念k-最近邻搜索来实现每个司机 u i u_i ui的优先队列 Q i Q_i Qi,如图4所示。这些优先队列通过行驶时间的下界来检索最近的乘客,而优先队列的顶部则储存着所有尚未检索的乘客的行驶时间下界。KM算法可以用相关优先队列的下界来避免计算精确成本,然后照常运行。对于一些情况下下界对于KM计算最优匹配不够准确的问题,我们进而提出了一些改进规则。一旦触发了一条规则,我们就通过检索顶部元素并计算其精确成本来改进队列,这就是为什么我们称之为“增量”成本计算。如果你对具体细节感兴趣,可以在原文中去更深入地了解改进规则、算法的内部运作以及数学证明。

我们发现增量KM算法能够生成与原始KM算法完全相同的结果!它只是采用了一种乐观的增量方式完成,希望可以在不计算所有成本的情况下找到结果,这非常适用于我们打车问题中的匹配的空间局部性。我们不仅节约了大量计算精确成本的时间,也避免了计算那些距离很远的乘客的行驶时间(往往耗费更大的计算资源)。

五、实验结果

我们通过实验对比来验证所提出算法的实际性能。我们实现了两个版本的增量KM算法,它们分别在优先队列和所使用的最短路径算法的实现上有所不同。

  • IKM-DIJK:使用Dijkstra算法计算最短路径,优先队列即是从每个司机展开的Dijkstra搜索优先队列,这跟常规KM算法相比没有额外的花费。
  • IKM-GAC:使用最先进的下界技术COLT来实现优先队列和一种快速计算最短路径的方法G-tree。每个分配都必须构建COLT索引,这个会包含在所有运行时间中。

我们将提出的两个算法与使用Dijkstra和G-tree分别计算整个成本矩阵的常规KM算法进行比较并在新加坡真实的道路网络上进行了实验。除此之外,我们还用到了一个包括2018年12月的7天内的Grab打车订单。

性能评估:

我们首先选择一个以秒为单位大小为 W W W的窗口,然后在一个随机选择的大小为 W W W的窗口中对所有预订进行批量处理,并使用这些订单中的乘客和司机的位置来构建二分图集合。接下来,我们用每种算法去找到一个最优匹配,并在多个随机选择的窗口上对各个度量标准的结果取均值。

在这里插入图片描述
图5. 每种算法计算成本矩阵的平均比例 v.s. 窗口大小

在图5中,验证了我们提出的算法的确与其对应的方法相比计算了更少的精确成本(原始的KM算法计算了100%的矩阵)。

在这里插入图片描述
图6. 每种算法寻找最优分配的平均时间 v.s. 窗口大小

在图6中,我们可以看到每种算法的运行时间。图中的结果证实,减少精确成本的计算显著减少了超过一个数量级的运行时间,这也验证了节省的时间是大于任何添加的额外时间的。请注意,IKM-DIJK的改进本质上没有消耗额外的算力成本!另外值得注意的是,使用IKM-GAC可以实现非常低的运行时间。

在这里插入图片描述
图7. 每种算法支持的最大吞吐量 v.s. 窗口大小

在图7中,我们展示了每种算法支持的最大吞吐量,即在时间窗口 W W W内可以批量处理的乘客/司机的最大数量。如图所示,我们的算法可以支持明显更高的吞吐量。

六、总结

总的来说,计算分配成本确实对寻找最优分配的运行时间产生了显著影响。然而,我们发现通过利用实际分配问题中的匹配的空间局部性,可以通过修改KM算法以增量的方式运作,来避免计算非必要的精确成本。

而且,值得一提的是,我们提出的方法框架还可以适用于除了司乘匹配外其他用到分配问题的场景中。

参考文献:
[1] Tenindra Abeywickrama, Victor Liang, and Kian-Lee Tan. 2021. Optimizing bipartite matching in real-world applications by incremental cost computation. Proc. VLDB Endow. 14, 7 (March 2021), 1150–1158
[2] https://engineering.grab.com/using-real-world-patterns-to-improve-matching
[3] H. W. Kuhn. 1955. The Hungarian method for the assignment problem. Naval Research Logistics Quarterly 2, 1-2 (1955), 83–97
[4] Dijkstra, E.W. A note on two problems in connexion with graphs. Numer. Math. 1, 269–271 (1959)
[5] Robert Geisberger, Peter Sanders, Dominik Schultes, and Daniel Delling. 2008. Contraction Hierarchies: Faster and Simpler Hierarchical Routing in Road Networks. In WEA. 319–333
[6] Ruicheng Zhong, Guoliang Li, Kian-Lee Tan, Lizhu Zhou, and Zhiguo Gong. 2015. G-Tree: An Efficient and Scalable Index for Spatial Search on Road Networks. IEEE Trans. Knowl. Data Eng. 27, 8 (2015), 2175–2189
[7] Tenindra Abeywickrama, Muhammad Aamir Cheema, and Sabine Storandt. 2020. Hierarchical Graph Traversal for Aggregate k Nearest Neighbors Search in Road Networks. In ICAPS. 2–10

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/313574.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android开发中使用Coil

Coil - Android开源图像加载库 Coil是一个开源的图像加载库,用于在Android中显示网络或本地图像资源。 为什么我们使用Coil? 快速:Coil进行了许多优化,包括内存和磁盘缓存、内存中的图像降采样、自动暂停/取消请求等。轻量级&a…

C++每日一练(10):线性查找

题目描述 输入n个数和一个需要查找的目标数&#xff0c;进行线性查找。 输入 第一行输入n&#xff08;1<n<1000&#xff09;&#xff0c; 第二行输入n个整数&#xff0c; 第三行输入要查找的目标数t。 输出 输出查找到的目标数的排序号&#xff0c;若查不到则输出no。 输…

Linux 安装Jupyter notebook 并开启远程访问

文章目录 安装Python安装pip安装Jupyter启动Jupyter Notebook1. 生成配置文件2. 创建密码3. 修改jupyter notebook的配置文件4. 启动jupyter notebook5. 远程访问jupyter notebook 安装Python 确保你的系统上已经安装了Python。大多数Linux发行版都预装了Python。你可以在终端…

基于Java SSM框架实现房屋租赁合同系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现房屋租赁合同系统演示 摘要 在网络高速发展的时代&#xff0c;众多的软件被开发出来&#xff0c;给用户带来了很大的选择余地&#xff0c;而且人们越来越追求更个性的需求。在这种时代背景下&#xff0c;人们对房屋租赁系统越来越重视&#xff0c;更好的…

【2023年终总结】 | 时光之舟:乘载着回忆与希望穿越2023,抵达2024

文章目录 1 回忆2 希望 1 回忆 2023年对我来说是非常梦幻的一年&#xff0c;我在2023年初的时候确认去做AI方向&#xff0c;在这之前我尝试了前端开发&#xff0c;移动App开发&#xff0c;云FPGA等方向&#xff0c;但是感觉自己都不是很喜欢&#xff0c;然后就开始尝试新的方向…

软件测试/测试开发丨Python 模块与包 学习笔记

python的程序结构 组成&#xff1a; packagemodulefunction 模块 模块是在代码量变得相当⼤了之后&#xff0c;为了将需要重复使⽤的有组织的代码放在⼀起&#xff0c;这部分代码可以被其他程序引⽤&#xff0c;从⽽使⽤该模块⾥的函数等功能&#xff0c;引⽤的过程叫做导…

了解.NET 通用主机

写在前面 .NET 通用主机负责应用启动和生存期管理&#xff0c;主机是封装应用资源和生存期功能的对象&#xff0c;通用主机可用于其他类型的 .NET 应用程序&#xff0c;如控制台应用&#xff1b;.NET 通用主机基于类库Microsoft.Extensions.Hosting 来实现&#xff0c;本文记录…

WINDOWS 批量修改图片文件名称(流星程序集之二十)

博主家里有一台电脑&#xff0c;存放家庭全部的照片和视频&#xff0c;从智能手机和3G网络发展开始&#xff0c;家里的照片和视频越来越多&#xff0c;已经达到上万个文件。终于&#xff0c;博主找到一个方法整理和保存这些珍贵的数据资料。 一、按年代目录整理照片和视频 按年…

RFC7636-PKCE

前言 PKCE &#xff08;RFC 7636&#xff09; 是授权代码流的扩展&#xff0c;用于防止 CSRF 和授权代码注入攻击。 PKCE 不是客户端身份验证的一种形式&#xff0c;PKCE 不能替代客户端密码或其他客户端身份验证。即使客户端使用客户端密码或其他形式的客户端身份验证&#…

面向对象知识点

类和对象知识点梳理 1. 类和对象的概念 类是对一类事物的描述&#xff0c;是抽象的、概念上的定义。Java 中定义类的关键字是&#xff1a;class。 具有相同特征和行为的对象抽象成类&#xff0c;类描述了这一类对象的属性和方法&#xff1a; 属性&#xff08;成员变量&#x…

软件测试/测试开发丨接口测试之Postman 安装与使用

Postman 安装 官网下载地址 www.postman.com/downloads Postman 使用 发送get请求 新建请求 填写请求方式&#xff1a;GET 填写请求 URL&#xff1a; ceshiren.com/httpbin.ceshiren.com/get 填写请求参数&#xff1a; para_key para_value 发送 POST 请求 请求方式&…

Python数值型字符串校验(try异常拦截解析)

从键盘输入一行字符串&#xff0c;编写Python代码判定字符串是python“合法”数值。 (笔记模板由python脚本于2023年12月25日 18:00:52创建&#xff0c;本篇笔记适合熟悉Python符串基本数据类型的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.py…