Pandas都败下阵来,python数据处理临近匹配,又多了一个选择

2023-11-23 14:56:05 浏览数 (2)

前言

数据处理任务中,匹配处理是比较常见的操作。因此许多数据工具都有配备对应的匹配方法。比如: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 表连接的小伙伴就很容易理解,上面使用的是交集连接,无法匹配的记录不会出现在结果中。

改用左连接,即可保留所有的左表记录:

  • 显然,无法匹配的记录,由于持股量为 null,所以计算结果也是 null

不要以为这只是窗口函数 不等式连接的语法糖。DuckDB 中的 asof join 在官方性能测试中,比 窗口函数 不等式连接 实现方式,最高快了 500倍。

那么 pandas 的 merge asof 可以扔掉了吗?不。在 pandas 的 merge asof 中可以做到真正的临近匹配,也就是记录可以往上或往下,选择最近的方向进行匹配。有兴趣的小伙伴可以去查看 pandas 相关文档或 panda 专栏。

0 人点赞