几种方法可以访问数据框中的特定元素,使用括号([ ]
(和美元符号($
(的各种组合。在时间敏感的函数中,使用哪一个可能很重要?
对一些可能的组合进行基准测试:
library(microbenchmark)
df <- data.frame(a=1:6,b=1:6,c=1:6,d=1:6,e=1:6,f=1:6)
microbenchmark(df$c[3],
df[3,]$c,
df[3,3],
df[3,][3],
df[3,][[3]],
df[,3][3],
times=1e3)
产生以下计时:
Unit: microseconds
expr min lq mean median uq max neval
df$c[3] 9.836 11.4505 14.03068 12.2015 12.9280 1252.854 1000
df[3, ]$c 77.204 89.5750 100.18752 92.2445 98.6395 1351.521 1000
df[3, 3] 15.719 18.9850 21.04074 19.6010 20.7400 82.519 1000
df[3, ][3] 88.599 100.5920 110.59009 104.0415 110.5435 409.050 1000
df[3, ][[3]] 75.856 87.2200 98.67104 89.9360 96.1695 1391.299 1000
df[, 3][3] 11.639 13.4225 14.77493 13.9510 14.6905 55.172 1000
我们看到df$c[3]
最快的地方,紧随其后的是df[,3][3]
.其他人要慢得多。
在时间敏感的应用程序中,我经常使用数据表而不是帧,因为排序和子集操作通常要快得多。但是,寻址操作可能会慢得多,正如我们看到的,如果我们对data.table
重复上述操作:
library(data.table)
dt <- as.data.table(df)
microbenchmark(dt$c[3],
dt[3,]$c,
dt[3,3],
dt[3,][[3]],
times=1e3)
Unit: microseconds
expr min lq mean median uq max neval
dt$c[3] 9.503 11.4020 14.90066 12.6820 13.8950 1336.407 1000
dt[3, ]$c 417.756 437.0495 480.26532 448.8625 463.6350 2909.038 1000
dt[3, 3] 205.115 218.9590 238.78000 227.9575 239.1265 1554.503 1000
dt[3, ][[3]] 414.378 435.2115 470.76853 447.1505 461.3310 1906.432 1000
我的问题是:$[ ]
是否保证始终是最快的寻址方法,或者这是否取决于数据框(或表(、平台 (OS( 或构建版本中的数据类型等因素? 如果有人能解释时间差异背后的原因,和/或各种方法的优缺点,那也是有用的。
更新
按照 42的答案中的建议,在这里使用更多的行和来自 42 的额外语法选项以及 A.Webb 的评论中的其他语法选项重复测试,他建议 df[[3,3]] 作为最快的。(注意:我也尝试了相同的测试,但访问了更高的行号,但时间似乎与选择哪一行无关(。
df <- data.frame(a=1:1000,b=1:1000,c=1:1000,d=1:1000,e=1:1000,f=1:1000)
Unit: microseconds
expr min lq mean median uq max neval
df$c[3] 8.314 9.7610 12.870667 10.6260 12.0950 1250.339 1000
df[["c"]][3] 6.932 8.0670 9.652672 8.7075 9.9445 26.512 1000
(df[3, ])$c 72.395 77.2390 90.893724 79.8320 95.8540 256.082 1000
df[3, 3] 14.871 16.2625 19.377482 17.1180 20.1720 47.720 1000
df[3, ][3] 82.446 86.7680 102.462603 89.9660 107.7965 232.685 1000
df[3, ][[3]] 70.559 75.2140 93.581394 78.3385 93.4235 1507.933 1000
df[, 3][3] 9.933 11.4770 13.430309 12.1090 14.0900 38.213 1000
df[[3, 3]] 6.465 7.8355 9.236773 8.4500 9.6355 29.833 1000
所以看起来 df[[i,j]] 是最快的,紧随其后的是 df[["colname"]][j]。使用其中哪一个可能取决于您是否需要使用列名或数字。
如果我们可以假设所有平台和所有数据类型始终如此,那么问题仍然悬而未决。
正如我的评论中所述,df$c[3]
实际上被解析为 '[['(df, 'c')[3]
,因此跳过解析过程会导致更快的执行也就不足为奇了。data.table 比较大多是非等效的,除非使用 $
它不是真正的 data.table 函数。
Unit: microseconds
expr min lq mean median uq max neval cld
df$c[3] 16.035 16.8245 17.63600 17.3090 17.9400 31.158 1000 ab
df[["c"]][3] 13.008 13.9090 14.60883 14.2775 14.8355 121.634 1000 a
(df[3, ])$c 137.376 140.4895 143.57778 141.6055 143.8310 175.180 1000 d
df[3, 3] 29.316 30.5715 31.25617 30.9040 31.3165 49.764 1000 c
df[3, ][3] 156.524 159.4180 167.99243 160.3910 162.3120 2636.693 1000 e
df[3, ][[3]] 134.975 137.3945 142.92265 138.3810 140.2370 2675.090 1000 d
df[, 3][3] 20.108 21.2860 21.94357 21.5810 21.8640 59.057 1000 b
我承认对我编写的代码感到惊讶:'[['(df, 'c')[3],
未解析为df[["c"]][3]
,并且对某些结果感到困惑,但一般规则是先选择列,然后在结果向量中的位置通常要快得多。
另外:这需要使用较大的对象进行测试。 有行>>列的那些