不同 data.frame 修改操作之间的效率差异

Efficiency discrepancies between different data.frame modification operations

我观察到 R 中 data.frame 修改的效率存在以下差异:

microbenchmark::microbenchmark(
  mtcars$mpg[1] <- 0, 
  mtcars[["mpg"]][1] <- 0, 
  mtcars[1,"mpg"] <- 0
)
Unit: microseconds
                    expr    min     lq     mean  median      uq    max neval
      mtcars$mpg[1] <- 0  4.400  4.801  5.16010  5.0020  5.3005 14.001   100
 mtcars[["mpg"]][1] <- 0  9.600 10.201 11.08797 10.5010 10.8015 61.001   100
   mtcars[1, "mpg"] <- 0 12.702 13.451 14.28102 13.8015 14.1020 47.701   100

此外,使用 $ 的第一种方法似乎比 [[[ 扩展得更好,后者似乎在线性时间内工作。

f <- function(nrow){
  df <- mtcars[sample(1:32,nrow,TRUE), ]
  microbenchmark::microbenchmark(
    df$mpg[1] <- 0, 
    df[["mpg"]][1] <- 0, 
    df[1,"mpg"] <- 0
  )
}

> f(1e5)
Unit: microseconds
                expr     min       lq      mean   median       uq     max neval
      df$mpg[1] <- 0   4.801   5.7505  41.92301   6.5505  12.2515 253.501   100
 df[["mpg"]][1] <- 0 140.401 146.4510 162.82191 154.8005 165.3005 267.400   100
   df[1, "mpg"] <- 0 144.801 151.5005 167.17197 159.9010 171.7010 277.102   100
> f(1e6)
Unit: microseconds
                expr     min       lq     mean   median        uq     max neval
      df$mpg[1] <- 0   5.601   10.551  733.995   18.251  918.6015 36519.5   100
 df[["mpg"]][1] <- 0 908.402 1013.052 2420.035 1278.751 1704.5505 52940.7   100
   df[1, "mpg"] <- 0 846.401 1018.101 2356.817 1332.900 1628.1510 57710.4   100

是什么导致了这种行为?我读过的大多数 R 文本似乎都将 mtcars$mpgmtcars[["mpg"]] 视为可互换的,因此它们修改不同的事实非常令人困惑。

编辑:我 运行 基于下面 Karolis 的回答的快速基准测试。方法 [[.data.frame 似乎是罪魁祸首。如果将 data.frame 强制转换为 list.

,则性能具有可比性
> mtlist <- as.list(mtcars)
> microbenchmark::microbenchmark(
+   mtlist$mpg[1] <- 1,
+   mtlist[["mpg"]][1] <- 1
+ )
Unit: nanoseconds
                    expr min  lq    mean median     uq   max neval
      mtlist$mpg[1] <- 1 801 900 1045.96    901 1051.0  5501   100
 mtlist[["mpg"]][1] <- 1 701 801 1191.16    851  951.5 19401   100 

没有 $.data.frame 运算符 - 因此使用列表的 $ 代替。

`$.data.frame`
Error: object '$.data.frame' not found

虽然[.data.frame[[.data.frame都是用R代码实现的函数。

`[.data.frame`
function...

`[[.data.frame`
function...

您还可以在 help('[.data.frame') 中阅读相关内容:

> [...] There is no ‘data.frame’ method for ‘$’, so ‘x$name’ uses the
  default method which treats ‘x’ as a list [...]