2012年,为什么 python 中的熊猫合并速度快于 R 中的 data.table 合并速度?

我最近遇到了 python 的 熊猫库,根据 这个基准,它执行非常快的内存合并。它甚至比 R (我用于分析的首选语言)中的 Data.table包还要快。

为什么 pandasdata.table快那么多?是因为 Python 比 R 有一个固有的速度优势,还是有一些我没有意识到的权衡?有没有一种方法可以在 data.table中执行内部和外部连接,而不必求助于 merge(X, Y, all=FALSE)merge(X, Y, all=TRUE)

Comparison

下面是 R 代码Python 代码,用于对各种软件包进行基准测试。

20632 次浏览

熊猫比较快的原因是我提出了一个更好的算法,这个算法使用 一个快速哈希表实现-klib和 C/Cython非常小心地实现,以避免不可向量化部分的 Python 解释器开销。该算法在我的演示文稿 熊猫设计与开发一览中有详细描述。

data.table的比较实际上有一点有趣,因为 R 的 data.table的全部意义在于它包含用于各种列的 预先计算的索引,以加速诸如数据选择和合并之类的操作。在这种情况下(数据库联接) ,熊猫的 DataFrame 包含用于合并的 没有预先计算好的信息,所以可以说这是一个“冷”合并。如果我已经存储了连接键的因子分解版本,那么连接会快得多——因为因子分解是这种算法的最大瓶颈。

我还应该补充一点,大熊猫的 DataFrame 的内部设计比 R 的 data.frame (它只是一个内部数组列表)更适合这类操作。

当唯一字符串(水平)的数量很大时,Wes 似乎已经在 data.table中发现了一个已知的问题: 10,000。

Rprof()是否揭示了大部分的时间花费在呼叫 sortedmatch(levels(i[[lc]]), levels(x[[rc]])?这实际上不是连接本身(算法) ,而是一个初步步骤。

最近的努力是允许键中有字符列,这应该通过更紧密地与 R 自己的全局字符串哈希表集成来解决这个问题。test.data.table()已经报告了一些基准测试结果,但是还没有将代码连接起来,以替换与级别匹配的级别。

对于常规整数列,熊猫合并是否比 data.table快?这应该是一种隔离算法本身和因素问题的方法。

此外,data.table还考虑了 时间序列合并时间序列合并。两个方面: i)多列 命令键,如(id,datetime) ii)快速流行的联接(roll=TRUE)又名最后的观察结果。

我需要一些时间来确认,因为这是我第一次看到与 data.table的比较。


2012年7月发布的 data.table v1.8.0更新

  • 内部函数 sortedmatch ()被删除并替换为 chmatch () 当匹配“ factor”类型的列的 i 级别到 x 级别时 初步步骤是造成(已知)显著放缓时,数字 因素列的水平较高(例如 > 10,000) 正如韦斯•麦金尼(Wes McKinney)所证明的那样,我们对四根这样的柱子进行了连接测试 (Python 包 Pandas 的作者)匹配100万个字符串 例如,其中60万是唯一的,现在从16秒减少到0.5秒。

在那份新闻稿中还提到:

  • 现在允许在键中使用字符列,并且首选 Table ()和 setkey ()不再强制字符 因素。因素仍然得到支持。实施 FR # 1493,FR # 1224 以及(部分) FR # 951

  • 新函数 chmatch ()和% chin% ,match ()的更快版本 字符向量为% 。 R 的内部字符串缓存为 使用(没有哈希表建立)。他们大约4倍的速度 在? chmatch 中的示例中,除了 match ()之外,还有更多的内容。

截至2013年9月,data.table 在 CRAN 上的版本是 v1.8.10,我们正在开发 v1.9.0。


但正如我最初所写的那样:

data.table考虑的是 时间序列合并时间序列合并,有两个方面: i) 多列 命令键,如(id,datetime) ii)快速流行 加入(roll=TRUE) ,也就是最后的观察结果。

因此,两个字符列的 Pandas equi 连接可能仍然比 data.table 快。因为它听起来像是两列合并后的哈希表。Table 不对键进行哈希,因为它考虑到了主流的有序连接。Table 中的“键”实际上就是排序顺序(类似于 SQL 中的聚集索引; 也就是说,这就是数据在 RAM 中的排序方式)。例如,在列表中添加辅助键。

总而言之,这个特殊的两字符列测试突出显示了超过10,000个唯一字符串的明显速度差异,现在应该没有那么糟糕了,因为已经解决了已知的问题。

这个话题已经有两年的历史了,但是当人们搜索“熊猫”和“数据表”的比较时,这个话题似乎是个不错的选择

由于这两者都随着时间的推移发生了变化,我想在这里为感兴趣的用户发布一个相对较新的比较(从2014年开始) : https://github.com/Rdatatable/data.table/wiki/Benchmarks-:-Grouping

我很想知道 Wes 和/或 Matt (顺便说一下,他们分别是熊猫和 data.table 的创建者,并且都在上面发表了评论)是否也有什么新闻要添加到这里。

——更新——

下面由 jangorecki 发表的评论包含一个我认为非常有用的链接: https://github.com/szilard/benchm-databases

https://github.com/szilard/benchm-databases/blob/master/plot.png

这个图表描述了不同技术的聚合和连接操作的平均时间(更低 = 更快; 比较最近一次更新是在2016年9月)。对我来说真的很有教育意义。

回到这个问题,R DT keyR DT引用了 R 的 data.table 的键控/非键控风格,并且在这个基准测试中比 Python 的 Pandas (Py pandas)更快。

这两个工具的作者都给出了很好的答案。 Matt 的回答解释了问题中提到的情况,那是一个错误引起的,而不是合并算法。第二天就修好了,已经是七年前的事了。

在我的回答中,我将提供一些关于 data.table 和 anda 合并操作的最新时间。注意,不包括 plyr 和 baseR merge。

我提出的时间是来自 基准项目,一个持续运行的可重复性基准。它将工具升级到最新版本,并重新运行基准测试脚本。它运行许多其他的软件解决方案。如果你对 Spark 感兴趣,Dask 和其他一些人一定要检查链接。


到目前为止... (还有待实现: 一个数据大小和5个问题)

我们测试了 LHS 表的两种不同的数据大小。
对于每个数据大小,我们运行5个不同的合并问题。

Q1: 整数上的 LHS 内连接 RHS-很小
Q2: LHS 内连接 RHS-介质对整数
Q3: LHS 外面加入 RHS-介质整数
问题4: LHS 内部加入 RHS-介于 因子(分类)
Q5: LHS 内连接 RHS-很大对整数

RHS 表有3种不同的尺寸

  • Small 表示 LHS/1e6的大小
  • 中等 表示 LHS/1e3的大小
  • Big 表示 LHS 的大小

在所有情况下,LHS 和 RHS 之间约有90% 的匹配行,而且在 RHS 连接列中没有重复行(没有笛卡儿积)。


截至目前(2019年11月2日运行)

大熊猫0.25.3于2019年11月1日发布
表0.12.7(92abb70)

对于 LHS 的两种不同数据大小,以下计时以秒为单位。列 pd2dt添加了字段存储比率,即大熊猫比 data.table 慢多少倍。

  • 0.5 GB LHS 数据
+-----------+--------------+----------+--------+
| question  |  data.table  |  pandas  |  pd2dt |
+-----------+--------------+----------+--------+
| q1        |        0.51  |    3.60  |      7 |
| q2        |        0.50  |    7.37  |     14 |
| q3        |        0.90  |    4.82  |      5 |
| q4        |        0.47  |    5.86  |     12 |
| q5        |        2.55  |   54.10  |     21 |
+-----------+--------------+----------+--------+
  • 5GB LHS 数据
+-----------+--------------+----------+--------+
| question  |  data.table  |  pandas  |  pd2dt |
+-----------+--------------+----------+--------+
| q1        |        6.32  |    89.0  |     14 |
| q2        |        5.72  |   108.0  |     18 |
| q3        |       11.00  |    56.9  |      5 |
| q4        |        5.57  |    90.1  |     16 |
| q5        |       30.70  |   731.0  |     23 |
+-----------+--------------+----------+--------+