用于在data.table中删除单个列的习惯用法

Ari*_*man 6 r data.table

我需要从包含几百列的data.frame中删除一列.

有了data.frame,我会习惯性subset地做到这一点:

> dat <- data.table( data.frame(x=runif(10),y=rep(letters[1:5],2),z=runif(10)),key='y' )
> subset(dat,select=c(-z))
            x y
 1: 0.1969049 a
 2: 0.7916696 a
 3: 0.9095970 b
 4: 0.3529506 b
 5: 0.4923602 c
 6: 0.5993034 c
 7: 0.1559861 d
 8: 0.9929333 d
 9: 0.3980169 e
10: 0.1921226 e
Run Code Online (Sandbox Code Playgroud)

显然这仍然有效,但它似乎不是一个非常类似data.table的习语.我可以手动构建一个我想保留的列名列表,这似乎更像一些data.table:

> dat[,list(x,y)]
            x y
 1: 0.1969049 a
 2: 0.7916696 a
 3: 0.9095970 b
 4: 0.3529506 b
 5: 0.4923602 c
 6: 0.5993034 c
 7: 0.1559861 d
 8: 0.9929333 d
 9: 0.3980169 e
10: 0.1921226 e
Run Code Online (Sandbox Code Playgroud)

但后来我必须构建这样一个笨重的列表.

subset方便地放下一两列的正确方法,还是会导致性能下降?如果没有,有什么更好的方法?

编辑

基准:

> dat <- data.table( data.frame(x=runif(10^7),y=rep(letters[1:10],10^6),z=runif(10^7)),key='y' )
> microbenchmark( subset(dat,select=c(-z)), dat[,list(x,y)] )
Unit: milliseconds
                         expr       min        lq    median        uq      max
1           dat[, list(x, y)] 102.62826 167.86793 170.72847 199.89789 792.0207
2 subset(dat, select = c(-z))  33.26356  52.55311  53.53934  55.00347 180.8740
Run Code Online (Sandbox Code Playgroud)

但真的可能更重要的是内存,如果subset复制整个data.table.

mne*_*nel 9

如果您想要永久使用删除列 := NULL

dat[, z := NULL]
Run Code Online (Sandbox Code Playgroud)

如果您要将列作为字符串用于()强制评估作为字符串而不是字符名称.

toDrop <- c('z')

dat[, (toDrop) := NULL]
Run Code Online (Sandbox Code Playgroud)

如果要限制列的可用性.SD,可以传递.SDcols参数

dat[,lapply(.SD, somefunction) , .SDcols = setdiff(names(dat),'z')]
Run Code Online (Sandbox Code Playgroud)

但是,data.table检查j参数并只获取您使用的列.见FAQ 1.12

当您编写X [Y,sum(foo*bar)]时,data.table会自动检查j表达式以查看它使用的列.

并且不会尝试加载所有数据.SD(除非您.SD在通话中j)


subset.data.table 正在处理呼叫并最终进行评估 dat[, c('x','y'), with=FALSE]

使用:= NULL应该基本上是瞬时的,如何永久删除列.

  • mnel说:"使用`()`强制评估作为一个字符串"......我一直试图弄清楚如何做几周.这个小小的提示值得它自己的问答. (2认同)