编写与 data.frame 和 data.table 兼容的代码
子集化语法的差异
除了 data.frame
,matrix
和(2D)array
之外,data.table
是 R 中可用的几种二维数据结构之一。所有这些类都使用非常相似但不完全相同的语法进行子集化,即 A[rows, cols]
模式。
考虑存储在 matrix
,data.frame
和 data.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.frame
和 data.table
一起使用。也许你被迫使用 data.frame
,或者你可能需要分享一些你不知道将如何使用的代码。因此,为方便起见,有一些实现这一目标的主要策略:
- 使用对两个类都行为相同的语法。
- 使用与最短语法相同的常用函数。
- 强制
data.table
表现为data.frame
(例如:调用特定方法print.data.frame
)。 - 把它们视为
list
,它们最终是。 - 在做任何事情之前将表转换为
data.frame
(如果它是一个巨大的表,那就糟糕了)。 - 如果依赖关系不是问题,请将表转换为
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.frame
有 row.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)