如何在data.table中按名称删除列?


194

要摆脱a中名为“ foo”的列data.frame,我可以这样做:

df <- df[-grep('foo', colnames(df))]

但是,一旦df转换为data.table对象,便无法删除列。

例:

df <- data.frame(id = 1:100, foo = rnorm(100))
df2 <- df[-grep('foo', colnames(df))] # works
df3 <- data.table(df)
df3[-grep('foo', colnames(df3))] 

但是一旦将其转换为data.table对象,它将不再起作用。


2
命名data.table dt而不是df3... 会更加清楚
PatrickT

Answers:


283

以下任何一项都会foo从data.table中删除列df3

# Method 1 (and preferred as it takes 0.00s even on a 20GB data.table)
df3[,foo:=NULL]

df3[, c("foo","bar"):=NULL]  # remove two columns

myVar = "foo"
df3[, (myVar):=NULL]   # lookup myVar contents

# Method 2a -- A safe idiom for excluding (possibly multiple)
# columns matching a regex
df3[, grep("^foo$", colnames(df3)):=NULL]

# Method 2b -- An alternative to 2a, also "safe" in the sense described below
df3[, which(grepl("^foo$", colnames(df3))):=NULL]

data.table还支持以下语法:

## Method 3 (could then assign to df3, 
df3[, !"foo"]  

但如果你实际上想删除列"foo"df3(而不是仅仅打印的视图df3负列"foo"),你真的要使用方法1代替。

(请注意,如果您使用依赖于grep()或的方法,并且您不希望将名称类似和的列(即包含子字符串的列)也进行匹配和删除,则grepl()需要设置pattern="^foo$"而不是。)"foo""fool""buffoon"foo

安全性较低的选项,适合交互式使用:

接下来的两个惯用法也将起作用- 如果df3包含匹配的列"foo" -但如果不匹配则将以可能无法预期的方式失败。例如,如果使用它们中的任何一个来搜索不存在的列"bar",那么最终将得到零行的data.table。

因此,它们确实最适合用于交互式使用,例如可能想要显示一个data.table减去名称包含substring的任何列"foo"。出于编程目的(或者如果您想从中df3而不是从其副本中真正删除该列),方法1、2a和2b确实是最佳选择。

# Method 4:
df3[, .SD, .SDcols = !patterns("^foo$")]

最后,有一些使用的方法with=FALSE,尽管data.table逐渐不再使用此参数,因此现在不鼓励您避免使用它。在此处显示,因此您知道该选项确实存在,以防您确实需要它:

# Method 5a (like Method 3)
df3[, !"foo", with=FALSE] 
# Method 5b (like Method 4)
df3[, !grep("^foo$", names(df3)), with=FALSE]
# Method 5b (another like Method 4)
df3[, !grepl("^foo$", names(df3)), with=FALSE]

2
请参阅我对OP关于-grepvs的评论!grepl
约书亚·乌尔里希

1
@JoshuaUlrich-好点 我grepl()最初尝试过,但是没有用,因为data.table列不能由逻辑向量索引。但是我现在意识到,grepl()可以通过使用对其进行包装来使其工作which(),以便它返回整数向量。
2012年

1
我不知道与索引有关data.table,但是将其包装起来which很聪明!
约书亚·乌尔里希

6
我也不知道那data.table件事。添加了FR#1797。但是,方法1(几乎)比其他方法无限快。方法1通过引用删除该列,根本没有任何副本。我怀疑对于任何大小的data.table,它是否都超过0.005秒。相反,如果表接近RAM的50%,则其他表可能根本无法工作,因为它们会复制除要删除的表以外的所有表。
Matt Dowle'2

1
@ user3969377如果要基于字符变量的内容删除列,只需将其括在括号中即可。就是 df [,(afoo):= NULL]
院长MacGregor

31

您也可以使用set它来避免[.data.tablein循环的开销:

dt <- data.table( a=letters, b=LETTERS, c=seq(26), d=letters, e=letters )
set( dt, j=c(1L,3L,5L), value=NULL )
> dt[1:5]
   b d
1: A a
2: B b
3: C c
4: D d
5: E e

如果要按列名进行操作,which(colnames(dt) %in% c("a","c","e"))则应适用于j


2
data.table1.11.8,如果要通过列名做到这一点,就可以直接做rm.col = c("a","b")dt[, (rm.col):=NULL]
杜乔一个

20

我只是以某种方式在数据帧中进行操作:

DT$col = NULL

工作迅速,据我所知不会造成任何问题。

更新:如果您的DT很大,则不是最佳方法,因为使用$<-运算符将导致对象复制。所以更好地使用:

DT[, col:=NULL]

8

如果您要在数据表中删除许多单独的列并且要避免输入所有列名称,请使用非常简单的方法#careadviced

dt <- dt[, -c(1,4,6,17,83,104)]

这将根据列号删除列。

显然,它效率不高,因为它绕过了data.table的优点,但是如果您处理的行数少于500,000行,则可以正常工作


4

假设你有DT列col1col2col3col4col5coln

要删除其中的一部分:

vx <- as.character(bquote(c(col1, col2, col3, coln)))[-1]
DT[, paste0(vx):=NULL]

这应该是评论
Sachila Ranawaka '17

-2

当您想将#列设置为NULL时,这是一种方法,因为它们的列名是您使用的函数:)

deleteColsFromDataTable <- function (train, toDeleteColNames) {

       for (myNm in toDeleteColNames)

       train <- train [,(myNm):=NULL]

       return (train)
}


-7

对于data.table,将列分配为NULL会将其删除:

DT[,c("col1", "col1", "col2", "col2")] <- NULL
^
|---- Notice the extra comma if DT is a data.table

...相当于:

DT$col1 <- NULL
DT$col2 <- NULL
DT$col3 <- NULL
DT$col4 <- NULL

data.frame的等效项是:

DF[c("col1", "col1", "col2", "col2")] <- NULL
      ^
      |---- Notice the missing comma if DF is a data.frame

问:为什么data.table的版本中没有逗号,而data.frame的版本中没有逗号?

答:由于data.frames是作为列的列表存储的,因此可以跳过逗号。你也可以添加进来,但是,你需要将它们分配到列表NULLS, DF[, c("col1", "col2", "col3")] <- list(NULL)


@Arun我想不出data.frames行和列之间切换的任何情况。那是不合逻辑的。
duHaas 2014年

@Arun我标记了您,因为您的第一个评论使您似乎有时会打电话给DF[column,row]我,所以我只是想看看是否确实有发生这种情况的实例。
duHaas 2014年

更新了答案以消除错字。
Contango'4
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.