数据处理任务中,匹配处理是比较常见的操作。因此许多数据工具都有配备对应的匹配方法。比如:excel 的 vlookup,pandas 的 merge ,sql 的 join。
不过,如果要处理时序数据则不一样。比如下面的数据:
价格表格与持股量在时间上不是一一对应。
在 pandas 中,我们可以使用 merge_asof ,此函数在我的 pandas 专栏有详细讲解。
在标准 sql 中没有完全对应的工具,虽然我们可以通过不等式连接间接实现,不过会付出性能的代价,并且语句上也很难看懂。
今天,介绍一个在 DuckDB 中的解决方案。不仅非常容易理解,并且性能也远远超出传统实现
本文需要安装这些库: shell pip install pandas duckdb -U
以前我已经简单介绍过 DuckDB ,它非常适合与 pandas 联合使用,并且性能爆表。DuckDB 也内置了许多用于数据分析的特有方法。今天介绍的临近匹配同样如此。
使用之前的例子数据:
想一下,如果需要使用普通的表连接,我们大概会写出以下的 sql:
注意,上面的 sql 无法拿到正确结果,这是因为在不等式中,我们没有指定匹配的结束时间点,应该说我们无法指定。
下图是上述sql某一笔记录的寻找过程:
要使用标准 sql 实现此需求,必需得配合窗口函数,找出时间结束点才可以。
虽然上面的 sql 不对,但是语义上是非常符合我们的直觉。这就足够了。DuckDB 在此语义基础上,新增了 asof 关键字,即可完成需求:
为什么结果中的两只股票都少了一笔记录?熟悉 sql 表连接的小伙伴就很容易理解,上面使用的是交集连接,无法匹配的记录不会出现在结果中。
改用左连接,即可保留所有的左表记录:
不要以为这只是窗口函数 + 不等式连接的语法糖。DuckDB 中的 asof join 在官方性能测试中,比 窗口函数 + 不等式连接 实现方式,最高快了 500倍。
那么 pandas 的 merge asof 可以扔掉了吗?不。在 pandas 的 merge asof 中可以做到真正的临近匹配,也就是记录可以往上或往下,选择最近的方向进行匹配。有兴趣的小伙伴可以去查看 pandas 相关文档或 panda 专栏。