我需要从包含几百列的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
显然这仍然有效,但似乎不是一个非常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
但是我必须构建一个笨重的列表。
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
但如果subset
复制整个data.table
,那么真正重要的是内存。
答案 0 :(得分:9)
如果您想永久删除该列,请使用:= NULL
dat[, z := NULL]
如果要将列作为字符串删除,请使用()
强制将评估作为字符串,而不是字符名称。
toDrop <- c('z')
dat[, (toDrop) := NULL]
如果您想限制.SD
中列的可用性,可以传递.SDcols
参数
dat[,lapply(.SD, somefunction) , .SDcols = setdiff(names(dat),'z')]
但是,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
应该基本上是即时的,如果永久删除列。
答案 1 :(得分:1)
我认为这就是你要找的东西。
dat[, !c("z"), with = FALSE]
以下是编辑中大量数据的基准。
Unit: milliseconds
expr min lq median uq max neval
subset(dat, select = c(-z)) 53.37435 56.82514 61.81279 100.3458 339.1400 100
dat[, list(x, y)] 191.46678 354.39905 412.06421 451.3933 678.3981 100
dat[, !c("z"), with = FALSE] 53.49184 57.31756 62.15506 112.7063 398.0107 100