【问题标题】:Why were pandas merges in python faster than data.table merges in R in 2012?为什么 python 中的 pandas 合并比 2012 年 R 中的 data.table 合并更快?
【发布时间】:2012-02-17 23:42:04
【问题描述】:

我最近遇到了用于 python 的pandas 库,根据this benchmark,它执行非常快速的内存合并。它甚至比 R(我选择的分析语言)中的 data.table 包还要快。

为什么pandasdata.table 快这么多?是因为 python 比 R 具有固有的速度优势,还是有一些我不知道的权衡?有没有办法在data.table 中执行内部和外部联接而不诉诸merge(X, Y, all=FALSE)merge(X, Y, all=TRUE)

这是用于对各种包进行基准测试的R codePython code

【问题讨论】:

  • @JoshuaUlrich:IIRC data.table 只是继承自 data.frame,但它在底层依赖于 C 代码。
  • @Joshua “即使你在 C 中操作 data.frames 也很慢”是什么意思?那是相对于别的东西吗?慢什么?
  • @JoshuaUlrich 我刚刚注意到这条评论线索从未被搁置。所以澄清一下:set() 在讨论后不久被添加到data.table。与:= 非常相似,但在循环时避免了[.data.table 的小开销,因此与matrix 一样快。因此,data.frame 可以 像矩阵一样被操纵。基准是here
  • 我们能不能得到这个基准的更新版本,很明显这个基准实际上是一个边缘案例,现在已经修复了。鉴于我见过的所有基准测试都表明 data.table 更快,我想看看合并数是多少?
  • @statquant 我没有运行原始基准,但我真的很想看到 Wes 更新基准。

标签: python r join data.table pandas


【解决方案1】:

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(内部只是一个数组列表)更适合这些类型的操作。

【讨论】:

  • 当然,既然你已经在 python 中弄清楚了,它应该很容易翻译成 R ;)
  • 但是为什么会有人想要呢? :)
  • 嗯 ...也许是因为他们希望 R 中的数据操作更快?只是猜测:))
  • 嗨,Wes - 您对data.table 的结果似乎主要是由一个已修复的错误驱动的。您是否有机会重新运行基准测试并撰写更新的博文?
【解决方案2】:

当唯一字符串(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 更新

  • 内部函数 sortedmatch() 被移除并替换为 chmatch() 将 i 级别与“因子”类型的列的 x 级别匹配时。这 初步步骤导致(已知)显着放缓,当数字 因子列的水平数很大(例如 > 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的内部字符串缓存是 使用(没有建立哈希表)。它们的速度大约快 4 倍 比 ?chmatch 中的示例中的 match()。

截至 2013 年 9 月,data.table 在 CRAN 上是 v1.8.10,我们正在开发 v1.9.0。 NEWS 实时更新。


但正如我最初写的那样,上面:

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

因此,两个字符列的 Pandas equi join 可能仍然比 data.table 快。因为它听起来像是对合并的两列进行哈希处理。 data.table 不会散列密钥,因为它考虑了普遍的有序连接。 data.table 中的“键”实际上只是排序顺序(类似于 SQL 中的聚集索引;即,这就是数据在 RAM 中的排序方式)。清单上是添加辅助键,例如。

总之,这个包含超过 10,000 个唯一字符串的特殊两字符列测试突出显示的明显速度差异现在应该不会那么糟糕,因为已知问题已得到修复。

【讨论】:

  • 如果您为相当大的、真实的数据集提供测试用例,我很乐意运行基准测试。也非常欢迎你。实际上,我还没有优化整数连接键案例的代码(把它放在我的待办事项列表上!),但是你可以期待比字符串案例更好的性能,因为链接演示文稿中的哈希表研究。
  • 我没有使用这两个库中的任何一个,但很高兴看到 R 方面以 Matthew Dowle 的形式做出了建设性的回应。
  • 这里是一些 Rprof 结果pastie.org/3258362。看起来有 20-40% 的时间花在 sortedmatch 上,具体取决于连接类型。下次将不得不查看整数列——我做了一个 pandas GitHub 问题来提醒我优化这种情况 (github.com/wesm/pandas/issues/682)
  • @AndyHayden 前段时间进行了改进。我将在 NEWS 项目中进行编辑。 Wes 选择了一项针对该已知问题的特定测试(等于加入两个字符列)。如果他选择整数列,情况会有所不同。如果他在会议上展示基准之前给了我一个提示,那么我可以告诉他更多关于已知问题的信息。
【解决方案3】:

这个话题已经有两年的历史了,但是当人们搜索 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

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

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

【讨论】:

【解决方案4】:

有很好的答案,特别是问题所涉及的两种工具的作者。 马特的回答解释了问题中报告的情况,它是由错误引起的,而不是由合并算法引起的。第二天就修复了错误,早在 7 年前就已经修复了。

在我的回答中,我将为 data.table 和 pandas 提供一些最新的合并操作时间。请注意,不包括 plyr 和 base R 合并。

我介绍的时间来自db-benchmark 项目,这是一个持续运行的可重现基准。它将工具升级到最新版本并重新运行基准脚本。它运行许多其他软件解决方案。如果您对 Spark、Dask 和其他少数人感兴趣,请务必查看链接。


截至目前...(仍有待实施:增加一个数据量和 5 个问题)

我们测试了 LHS 表的 2 种不同数据大小。
对于这些数据大小中的每一个,我们都会运行 5 个不同的合并问题。

q1:LHS 内连接 RHS-small 整数
q2:LHS 内连接 RHS-medium on integer
q3:LHS outer 在整数上加入 RHS-medium
q4:LHS 内连接 RHS-medium 关于因素(分类)
q5: LHS 内连接 RHS-big on integer

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 |
+-----------+--------------+----------+--------+
  • 5 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 的 R vs python 实现添加一列?
  • 我觉得去网站看看就好了,即使是看 R dt vs pandas。而且 pyDT 真的不是原始问题的一部分。
猜你喜欢
  • 2018-08-25
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
  • 1970-01-01
  • 2018-03-30
  • 1970-01-01
  • 2016-02-01
  • 2021-06-19
相关资源
最近更新 更多