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

Mai*_*ura 182 r data.table

为了摆脱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))] 
Run Code Online (Sandbox Code Playgroud)

但是一旦它被转换为一个data.table对象,这就不再适用了.

Jos*_*ien 263

以下任何一项都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]
Run Code Online (Sandbox Code Playgroud)

data.table还支持以下语法:

## Method 3 (could then assign to df3, 
df3[, !"foo"]  
Run Code Online (Sandbox Code Playgroud)

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

(请注意,如果您使用的方法依赖于grep()或者grepl(),您需要设置pattern="^foo$",而不是"foo",如果你不希望与喜欢的名字列"fool""buffoon"(即包含这些foo作为子)也被匹配和删除.)

不太安全的选择,适合交互式使用:

接下来的两个习语也会起作用 - 如果df3包含列匹配"foo" - 但如果不匹配则会以可能意外的方式失败.例如,如果您使用其中任何一个来搜索不存在的列"bar",则最终会得到一个零行data.table.

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

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

  • 关于`data.table`我也不知道; 添加[FR#1797](https://r-forge.r-project.org/tracker/index.php?func=detail&aid=1797&group_id=240&atid=978).但是,方法1(几乎)无限期地比其他方法更快.方法1通过引用删除列,完全没有副本.对于任何大小的数据,我都怀疑你在0.005秒以上.相反,如果表格接近50%的RAM,那么其他的可能根本不起作用,因为它们会复制除删除之外的所有内容. (6认同)
  • 请参阅我对OP的评论,关于`-grep`与`!grepl`. (2认同)
  • @JoshuaUlrich——好点。我最初尝试了“grepl()”,但它不起作用,因为 data.table 列无法通过逻辑向量进行索引。但我现在意识到可以通过用“which()”包装“grepl()”来使其工作,以便它返回一个整数向量。 (2认同)

Ari*_*man 29

您也可以使用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
Run Code Online (Sandbox Code Playgroud)

如果你想按列名做,which(colnames(dt) %in% c("a","c","e"))应该适用j.

  • 在`data.table` 1.11.8中,如果要按列名来做,可以直接做`rm.col = c("a","b")`和`dt[,(rm.col) :=NULL]` (2认同)

msp*_*msp 17

我只是在数据框中这样做:

DT$col = NULL
Run Code Online (Sandbox Code Playgroud)

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

更新:如果你的DT非常大,不是最好的方法,因为使用$<-操作符会导致对象复制.这样更好用:

DT[, col:=NULL]
Run Code Online (Sandbox Code Playgroud)


SJD*_*JDS 5

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

dt <- dt[, -c(1,4,6,17,83,104)]
Run Code Online (Sandbox Code Playgroud)

这将根据列号删除列。

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