2017-09-12 30 views
5

考虑以下基准(Windows机器R上3.4.1):时差对象

library(rbenchmark) 

mtx <- matrix(runif(1e8), ncol = 100) 
df <- as.data.frame(mtx) 

colnames(mtx) <- colnames(df) <- paste0("V", 1:100) 

benchmark(
    mtx[5000:7000, 80], 
    mtx[5000:7000, "V80"], 
    mtx[, "V80"][5000:7000], 
    mtx[, "V80", drop = FALSE][5000:7000, ], 
    mtx[5000:7000, , drop = FALSE][, "V80"], 
    #mtx$V80[5000:7000], # does not apply 
    replications = 5000 
) 

##          test replications elapsed relative user.self sys.self user.child sys.child 
## 4 mtx[, "V80", drop = FALSE][5000:7000, ]   5000 64.71 588.273  47.44 16.61   NA  NA 
## 3     mtx[, "V80"][5000:7000]   5000 72.15 655.909  52.90 18.18   NA  NA 
## 2     mtx[5000:7000, "V80"]   5000 0.11 1.000  0.11  0.00   NA  NA 
## 5 mtx[5000:7000, , drop = FALSE][, "V80"]   5000 7.47 67.909  5.89  1.47   NA  NA 
## 1      mtx[5000:7000, 80]   5000 0.13 1.182  0.12  0.00   NA  NA 

benchmark(
    df[5000:7000, 80], 
    df[5000:7000, "V80"], 
    df[, "V80"][5000:7000], 
    df[, "V80", drop = FALSE][5000:7000, ], 
    df[5000:7000, , drop = FALSE][, "V80"], 
    df$V80[5000:7000], 
    replications = 5000 
) 

##          test replications elapsed relative user.self sys.self user.child sys.child 
## 6      df$V80[5000:7000]   5000 0.13 1.000  0.12  0.00   NA  NA 
## 4 df[, "V80", drop = FALSE][5000:7000, ]   5000 0.33 2.538  0.33  0.00   NA  NA 
## 3     df[, "V80"][5000:7000]   5000 0.17 1.308  0.17  0.00   NA  NA 
## 2     df[5000:7000, "V80"]   5000 0.15 1.154  0.16  0.00   NA  NA 
## 5 df[5000:7000, , drop = FALSE][, "V80"]   5000 13.63 104.846  12.91  0.39   NA  NA 
## 1      df[5000:7000, 80]   5000 0.19 1.462  0.17  0.00   NA  NA 

的时间差是相当惊人的。这是为什么?什么是建议子集的方式,为什么?考虑到基准,矩阵的mtx[i, colname]方式和df$colname[i](但它似乎没有太大的差别)data.frame似乎是最省时间的,但是有什么一般原因为什么我们应该更喜欢任何方法吗?

+1

并不总是推荐data.frame的$ -extraction。它仅用于交互式使用。您可以添加'df [[“V80”]]和'df [[80]]'提取方法。 –

+0

只要使用哪一个是最快的为您的特定矩阵/ data.frame(假设子设置的速度甚至是代码的阻塞部分)。它通常更好的做一个子集操作'[]'而不是两个[] []'。你有不同的选择,所以你可以选择哪一个更具可读性或使你的代码更易于理解。 – MrFlick

回答

1

主要原因在于矩阵和data.frames后面的R数据结构。矩阵基本上是一个具有rownumber x columnnumber(主要是数字)条目(由R的默认矩阵不稀疏)和维属性的对象。出于这个原因,你的第一个2个命令

mtx[5000:7000, 80], 
mtx[5000:7000, "V80"] 

再次提取矩阵,其中:R不能只分配值,而且尺寸创建新的Matrix对象简单的载体,其为R的默认对象来代替。

另一方面,R中的data.frame通过定义是一种特殊类型的列表对象,其中每个列对象的长度必须相同,而列可以包含不同类型的变量(数字,字符串等)。矩阵只能包含单个类型的变量,默认情况下这是最常用的变量。因此,

df[5000:7000, 80] 

提取第80列的向量,然后提取出位置5000-7000之外的值。 R比矩阵对象更容易处理矢量,因此速度要快得多。

但是,如果选择drop = FALSE,则强制R在选择第80列时不能使用简单的矢量对象,而应将其视为data.frame/list对象。列表是R对象中最通用和最灵活的类型,因为它们的大小和条目没有限制,但是这样做的代价是它们最难以处理,并且比较时可以观察到

mtx[5000:7000, , drop = FALSE][, "V80"] 
df[5000:7000, , drop = FALSE][, "V80"] 

从数据框中获得另一个data.frame/list,而矩阵仍然返回比列表处理速度更快的矩阵。