【问题标题】:R: Why is the [[ ]] approach for subsetting a list faster than using $?R:为什么 [[ ]] 方法对列表进行子集化比使用 $ 更快?
【发布时间】:2013-05-13 20:44:12
【问题描述】:

我一直在从事一些需要我进行大量列表子集化的项目,在分析代码时,我意识到对象[["nameHere"]] 对列表子集化的方法通常比 object$ 快nameHere 方法。

例如,如果我们创建一个包含命名组件的列表:

a.long.list <- as.list(rep(1:1000))
names(a.long.list) <- paste0("something",1:1000)

为什么会这样:

system.time (
for (i in 1:10000) {
    a.long.list[["something997"]]
}
)


user  system elapsed 
0.15    0.00    0.16 

比这更快:

system.time (
    for (i in 1:10000) {
        a.long.list$something997
    }
)

user  system elapsed 
0.23    0.00    0.23 

我的问题只是这种行为是否普遍适用,我应该尽可能避免使用 $ 子集,还是最有效的选择取决于其他一些因素?

【问题讨论】:

  • +1。我怀疑它与 $ 符号的部分匹配有关。假设你有my_list &lt;- list("a" = 1, "ace" = 2)。如果你尝试my_list$ac,它会得到ace,但如果你尝试my_list[["ac"]],它什么也找不到。
  • 不排除部分匹配理论,但我希望完整的答案将包括为什么在 OP 的示例中将 exact = FALSE 添加到 [[ 不会降低性能。
  • 似乎值得一提的是$[[ 是由两个完全不同的C 函数实现的(都在src/main/subset.c 中)。对于$,相关函数是do_subset3,它又调用R_subset3_dflt[[ 使用另一个函数do_subset2,它又调用do_subset2_dflt
  • do_subset2 前面的注释简单地指出:“[[ 子集运算符。它需要很快。”
  • 还可能值得一提的是 R 3.0.0 中的最新更改之一:“在数据帧上使用 $ 运算符时的部分匹配现在会引发警告,并且将来可能会失效。如果部分匹配是打算用 foo[["bar", exact = FALSE]] 替换 foo$bar。"

标签: performance r list subset


【解决方案1】:

函数[[首先通过所有元素尝试精确匹配,然后尝试进行部分匹配。 $ 函数依次尝试对每个元素进行完全匹配和部分匹配。如果你执行:

system.time (
    for (i in 1:10000) {
     a.long.list[["something9973", exact=FALSE]]
     }
)

也就是说,你正在运行一个没有完全匹配的部分匹配,你会发现$实际上稍微快了一点。

【讨论】:

  • 我认为这回答了 Flodel 关于为什么添加 exact = FALSE 不会降低性能的澄清问题。无论如何,我现在确信在速度很重要的编程环境中,最好使用 [[ 除非很有可能需要部分匹配(这通常会在我的程序中产生错误而不是解决问题)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-02
  • 1970-01-01
  • 2013-09-09
  • 1970-01-01
  • 2018-02-01
  • 2015-02-13
  • 2014-10-12
相关资源
最近更新 更多