【问题标题】:Time difference between different subsetting methods for data.frame and matrix objectsdata.frame 和 matrix 对象的不同子集方法之间的时间差异
【发布时间】:2018-02-21 00:05:19
【问题描述】:

考虑以下基准(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] 方式和data.frame 的df$colname[i] (但似乎没有太大区别)似乎是最省时的,但是有什么一般原因我们应该更喜欢任何方法有哪些?

【问题讨论】:

  • 并不总是建议对 data.frame 进行 $-extraction。它仅供交互使用。您可以添加df[["V80"]]df[[80]] 提取方法。
  • 只使用对您的特定矩阵/data.frame 最快的那个(假设子设置的速度甚至是代码的阻塞部分)。通常最好做一个子集操作[],而不是两个[][]。您有不同的选项,因此您可以选择哪一个更具可读性或使您的代码更易于理解。

标签: r matrix dataframe


【解决方案1】:

主要原因在于矩阵和data.frames背后的R数据结构。矩阵基本上是一个对象,具有行号 x 列号(主要是数字)条目(在 R 的默认情况下,矩阵不是稀疏的)和维度属性。因此,您的前 2 个命令

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

再次提取矩阵,R 不仅为其分配值,而且为创建新矩阵对象而不是作为 R 的默认对象的简单向量分配维度。

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

df[5000:7000, 80]

提取第 80 列的向量,然后从中提取 5000-7000 位置的值。对于 R 来说,向量比矩阵对象更容易处理,因此要快得多。

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

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

从数据帧中,您可以获得另一个 data.frame/list,而矩阵仍然返回一个矩阵,该矩阵仍然比列表处理得更快。

【讨论】:

    猜你喜欢
    • 2019-06-28
    • 1970-01-01
    • 2014-10-05
    • 1970-01-01
    • 2013-07-12
    • 1970-01-01
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多