我最近遇到了用于 python 的 pandas 库,根据 this benchmark,它执行非常快速的内存合并。它甚至比 R 中的 data.table 包(我选择的分析语言)还要快。
为什么 pandas
比 data.table
快这么多?是因为 python 比 R 具有固有的速度优势,还是有一些我不知道的权衡?有没有一种方法可以在 data.table
中执行内部和外部联接而不使用 merge(X, Y, all=FALSE)
和 merge(X, Y, all=TRUE)
?
https://i.stack.imgur.com/0pCvh.png
这是用于对各种软件包进行基准测试的 R code 和 Python code。
data.table
只是继承自 data.frame
,但它依赖于 C 代码。
set()
被添加到 data.table
中。与 :=
非常相似,但在循环时避免了 [.data.table
的小开销,因此与 matrix
一样快。因此,data.frame
可以 像矩阵一样被操纵。基准是 here。
pandas 更快的原因是因为我想出了一个更好的算法,它使用 a fast hash table implementation - klib 和 C/Cython 非常小心地实现,以避免 Python 解释器对不可矢量化部分的开销。我的演示文稿中详细描述了该算法:A look inside pandas design and development。
与 data.table
的比较实际上有点有趣,因为 R 的 data.table
的全部意义在于它包含用于各种列的预计算索引,以加速数据选择和合并等操作。在这种情况下(数据库连接),pandas 的 DataFrame 包含 没有用于合并的预计算信息,可以说这是一个“冷”合并。如果我存储了连接键的分解版本,连接会明显更快——因为分解是该算法的最大瓶颈。
我还应该补充一点,pandas 的 DataFrame 的内部设计比 R 的 data.frame(它只是内部数组的列表)更适合这些类型的操作。
当唯一字符串(levels)的数量很大时,Wes 似乎在 data.table
中发现了一个已知问题:10,000。
Rprof()
是否显示了调用 sortedmatch(levels(i[[lc]]), levels(x[[rc]])
所花费的大部分时间?这并不是真正的连接本身(算法),而是一个初步步骤。
最近的努力已经进入允许键中的字符列,这应该通过与 R 自己的全局字符串哈希表更紧密地集成来解决这个问题。 test.data.table()
已经报告了一些基准测试结果,但该代码尚未连接以将级别替换为级别匹配。
对于常规整数列,pandas 的合并速度是否比 data.table
快?这应该是一种隔离算法本身与因素问题的方法。
此外,data.table
考虑了 时间序列合并。两个方面:i) 多列 有序 键,例如 (id,datetime) ii) 快速流行连接 (roll=TRUE
) 也就是最后的观察结果。
我需要一些时间来确认,因为这是我第一次看到与 data.table
的比较。
2012 年 7 月发布的 data.table v1.8.0 的更新
当将 i 级别匹配到“因子”类型的列的 x 级别时,内部函数 sortedmatch() 被删除并替换为 chmatch()。当因子列的水平数很大(例如>10,000)时,这个初步步骤会导致(已知的)显着放缓。正如 Wes McKinney(Python 包 Pandas 的作者)所证明的那样,在加入四个这样的列的测试中加剧了这种情况。例如,匹配 100 万个字符串,其中 600,000 个是唯一的,现在从 16 秒减少到 0.5 秒。
在那个版本中还有:
现在允许在键中使用字符列,并且优先考虑因素。 data.table() 和 setkey() 不再强制字符为因子。因素仍然得到支持。实现 FR#1493、FR#1224 和(部分)FR#951。
新函数 chmatch() 和 %chin%,match() 和 %in% 用于字符向量的更快版本。使用了 R 的内部字符串缓存(没有构建哈希表)。它们比 ?chmatch 中的示例中的 match() 快约 4 倍。
截至 2013 年 9 月,data.table 在 CRAN 上是 v1.8.10,我们正在开发 v1.9.0。 NEWS 实时更新。
但正如我最初写的那样,上面:
data.table 考虑了时间序列合并。有两个方面:i)多列有序键,例如(id,datetime)ii)快速流行连接(roll = TRUE)也就是最后的观察结转。
因此,两个字符列的 Pandas equi join 可能仍然比 data.table 快。因为它听起来像是对合并的两列进行哈希处理。 data.table 不会散列密钥,因为它考虑了普遍的有序连接。 data.table 中的“键”实际上只是排序顺序(类似于 SQL 中的聚集索引;即,这就是数据在 RAM 中的排序方式)。例如,在列表中添加辅助键。
总之,这个包含超过 10,000 个唯一字符串的特殊两字符列测试突出显示的明显速度差异现在应该不会那么糟糕,因为已知问题已得到修复。
这个话题已经有两年的历史了,但是当人们搜索 Pandas 和 data.table 的比较时,这似乎是一个可能的落脚点
由于这两者都随着时间的推移而发展,我想在这里为感兴趣的用户发布一个相对较新的比较(从 2014 年开始):https://github.com/Rdatatable/data.table/wiki/Benchmarks-:-Grouping
想知道 Wes 和/或 Matt(顺便说一下,他们分别是 Pandas 和 data.table 的创建者并且都在上面发表过评论)是否也有任何新闻要添加到这里会很有趣。
- 更新 -
jangorecki 在下面发布的评论包含一个我认为非常有用的链接:https://github.com/szilard/benchm-databases
https://i.stack.imgur.com/dAnZO.png
此图描述了不同技术的聚合和连接操作的平均时间(较低 = 更快;比较最后更新于 2016 年 9 月)。这对我来说真的很有教育意义。
回到这个问题,R DT key
和 R DT
指的是 R 的 data.table 的键控/非键控风格,并且在这个基准测试中碰巧比 Python 的 Pandas (Py pandas
) 更快。
有很好的答案,特别是由问题所问的两种工具的作者提出的。马特的回答解释了问题中报告的情况,它是由错误引起的,而不是由合并算法引起的。第二天就修复了错误,已经超过 7 年了。
在我的回答中,我将为 data.table 和 pandas 提供一些最新的合并操作时间。请注意,不包括 plyr 和 base R 合并。
我介绍的时序来自 db-benchmark 项目,这是一个持续运行的可重现基准。它将工具升级到最新版本并重新运行基准脚本。它运行许多其他软件解决方案。如果您对 Spark、Dask 和其他少数人感兴趣,请务必查看链接。
截至目前...(仍有待实施:增加一个数据量和另外 5 个问题)
我们测试了 LHS 表的 2 种不同数据大小。对于这些数据大小中的每一个,我们运行 5 个不同的合并问题。
q1:整数上的 LHS 内连接 RHS-small q2:整数上的 LHS 内连接 RHS-medium q3:整数上的 LHS 外连接 RHS-medium q4:因子(分类)上的 LHS 内连接 RHS-medium q5:LHS 内连接 RHS-大整数
RHS 表有 3 种不同的尺寸
small 转换为 LHS/1e6 的大小
medium 转换为 LHS/1e3 的大小
big 转换为 LHS 的大小
在所有情况下,LHS 和 RHS 之间大约有 90% 的匹配行,并且在 RHS 连接列中没有重复(没有笛卡尔积)。
截至目前(2019 年 11 月 2 日运行)
pandas 0.25.3 于 2019 年 11 月 1 日发布 data.table 0.12.7 (92abb70) 于 2019 年 11 月 2 日发布
以下时间以秒为单位,用于 LHS 的两种不同数据大小。第 pd2dt
列添加了 pandas 比 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 |
+-----------+--------------+----------+--------+
GB 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 |
+-----------+--------------+----------+--------+
不定期副业成功案例分享
data.table
的结果似乎主要是由一个已修复的错误驱动的。您是否有机会重新运行基准测试并撰写更新的博客文章?