编写与 data.frame 和 data.table 兼容的代码

子集化语法的差异

除了 data.framematrix 和(2D)array 之外,data.table 是 R 中可用的几种二维数据结构之一。所有这些类都使用非常相似但不完全相同的语法进行子集化,即 A[rows, cols] 模式。

考虑存储在 matrixdata.framedata.table 中的以下数据:

ma <- matrix(rnorm(12), nrow=4, dimnames=list(letters[1:4], c('X', 'Y', 'Z')))
df <- as.data.frame(ma)
dt <- as.data.table(ma)

ma[2:3]  #---> returns the 2nd and 3rd items, as if 'ma' were a vector (because it is!)
df[2:3]  #---> returns the 2nd and 3rd columns
dt[2:3]  #---> returns the 2nd and 3rd rows!

如果你想确定将返回什么,最好是明确的

要获取特定,只需在范围后添加逗号:

ma[2:3, ]  # \
df[2:3, ]  #  }---> returns the 2nd and 3rd rows
dt[2:3, ]  # /

但是,如果要对进行子集,则某些情况的解释会有所不同。所有三个都可以是相同的子集,其中整数或字符索引存储在变量中。

ma[, 2:3]          #  \
df[, 2:3]          #   \
dt[, 2:3]          #    }---> returns the 2nd and 3rd columns
ma[, c("Y", "Z")]  #   /
df[, c("Y", "Z")]  #  /
dt[, c("Y", "Z")]  # /

但是,它们对于不带引号的变量名称有所不同

mycols <- 2:3
ma[, mycols]                # \
df[, mycols]                #  }---> returns the 2nd and 3rd columns
dt[, mycols, with = FALSE]  # /

dt[, mycols]                # ---> Raises an error

在最后一种情况下,mycols 被评估为列的名称。因为 dt 找不到名为 mycols 的列,所以会引发错误。

注意:对于 data.table 软件包 priorto 1.9.8 的版本,此行为略有不同。列索引中的任何内容都将使用 dt 作为环境进行评估。所以 dt[, 2:3]dt[, mycols] 都会返回向量 2:3。第二种情况不会引发错误,因为变量 mycols 确实存在于父环境中。

保持与 data.frame 和 data.table 兼容的策略

写代码的原因有很多,保证与 data.framedata.table 一起使用。也许你被迫使用 data.frame,或者你可能需要分享一些你不知道将如何使用的代码。因此,为方便起见,有一些实现这一目标的主要策略:

  1. 使用对两个类都行为相同的语法。
  2. 使用与最短语法相同的常用函数。
  3. 强制 data.table 表现为 data.frame(例如:调用特定方法 print.data.frame)。
  4. 把它们视为 list,它们最终是。
  5. 在做任何事情之前将表转换为 data.frame(如果它是一个巨大的表,那就糟糕了)。
  6. 如果依赖关系不是问题,请将表转换为 data.table

**子集行。**它很简单,只需使用 [, ] 选择器,逗号:

A[1:10, ]
A[A$var > 17, ]  # A[var > 17, ] just works for data.table

**子集列。**如果你想要一个列,请使用 $[[ ]] 选择器:

A$var
colname <- 'var'
A[[colname]]
A[[1]]

如果你想要一个统一的方法来获取多个列,那么有必要提出一些建议:

B <- `[.data.frame`(A, 2:4)

# We can give it a better name
select <- `[.data.frame`
B <- select(A, 2:4)
C <- select(A, c('foo', 'bar'))

**子集’已编入索引’行。**虽然 data.framerow.names,但 data.table 有其独特的 key 功能。最好的办法是完全避免使用 row.names,并在可能的情况下利用 data.table 的现有优化。

B <- A[A$var != 0, ]
# or...
B <- with(A, A[var != 0, ])  # data.table will silently index A by var before subsetting

stuff <- c('a', 'c', 'f')
C <- A[match(stuff, A$name), ]  # really worse than: setkey(A); A[stuff, ]

**获取 1 列表,获取行作为向量。**到目前为止,我们所看到的很容易:

B <- select(A, 2)    #---> a table with just the second column
C <- unlist(A[1, ])  #---> the first row as a vector (coerced if necessary)