【问题标题】:How do you delete a column by name in data.table?如何在 data.table 中按名称删除列?
【发布时间】:2012-03-01 10:11:54
【问题描述】:

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

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 对象,它就不再起作用了。

【问题讨论】:

  • 将data.table命名为dt而不是df3会更清楚...

标签: r data.table


【解决方案1】:

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

# 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"]  

虽然如果您真的想从 df3 中删除列 "foo"(而不是仅打印 df3 减去列 "foo" 的视图),您真的想改用方法 1。

(请注意,如果您使用依赖于grep()grepl() 的方法,则需要设置pattern="^foo$" 而不是"foo",如果您不希望列名称为"fool" 和@ 987654335@(即包含foo作为子字符串的那些)也将被匹配和删除。)

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

接下来的两个习惯用法也可以使用——如果df3 包含与"foo" 匹配的列——但如果不匹配,则会以一种可能出乎意料的方式失败。例如,如果您使用其中任何一个来搜索不存在的列 "bar",您最终会得到一个零行 data.table。

因此,它们确实最适合交互式使用,例如,希望显示一个 data.table 减去名称包含子字符串 "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]

【讨论】:

  • 查看我对 OP 关于-grep!grepl 的评论。
  • @JoshuaUlrich -- 好点。我最初尝试了grepl(),但它不起作用,因为 data.table 列不能被逻辑向量索引。但我现在意识到grepl() 可以通过用which() 包装来工作,这样它就会返回一个整数向量。
  • 我不知道如何使用data.table 进行索引,但是将其包装在which 中很聪明!
  • 我也不知道data.table;添加FR#1797。但是,方法 1(几乎)无限比其他方法快。方法 1 通过引用删除列,根本没有副本。对于任何大小的 data.table,我怀疑您是否会超过 0.005 秒。相反,如果表接近 50% 的 RAM,其他表可能根本无法工作,因为它们会复制除要删除的表之外的所有表。
  • @user3969377 如果要根据字符变量的内容删除列,只需将其括在括号中即可。 IE。 df[,(afoo):=NULL]
【解决方案2】:

您也可以为此使用set,这样可以避免[.data.table 在循环中的开销:

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

【讨论】:

  • data.table 1.11.8中,如果要按列名做,可以直接做rm.col = c("a","b")dt[, (rm.col):=NULL]
【解决方案3】:

我只是以数据框的方式来做:

DT$col = NULL

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

更新:如果您的 DT 非常大,这不是最好的方法,因为使用 $&lt;- 运算符会导致对象复制。所以更好用:

DT[, col:=NULL]

【讨论】:

    【解决方案4】:

    如果您在数据表中有许多单独的列要删除并且您希望避免输入所有列名#careadviced

    ,这是一个非常简单的选项
    dt <- dt[, -c(1,4,6,17,83,104)]
    

    这将改为根据列号删除列。

    显然效率不高,因为它绕过了 data.table 的优势,但如果您使用的行数少于 500,000 行,它就可以正常工作

    【讨论】:

      【解决方案5】:

      假设您的 dt 包含列 col1col2col3col4col5coln

      删除其中的一个子集:

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

      【讨论】:

      • 这应该是评论
      • 这就是“bquote”函数的作用
      【解决方案6】:

      这是一种在给定列名的情况下要将 # 列设置为 NULL 的方法 供您使用的功能:)

      deleteColsFromDataTable <- function (train, toDeleteColNames) {
      
             for (myNm in toDeleteColNames)
      
             train <- train [,(myNm):=NULL]
      
             return (train)
      }
      

      【讨论】:

        【解决方案7】:
        DT[,c:=NULL] # remove column c
        

        【讨论】:

          【解决方案8】:

          对于 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的版本没有逗号?

          A.由于 data.frames 存储为列列表,因此您可以跳过逗号。您也可以添加它,但是您需要将它们分配到NULLs、DF[, c("col1", "col2", "col3")] &lt;- list(NULL) 的列表中。

          【讨论】:

          • @Arun 我想不出data.frames 的行和列会被切换的任何情况。那是不合逻辑的。
          • @Arun 我给你加了标签是因为你的第一条评论让你觉得有时你可能会打电话给DF[column,row],所以我只是想看看是否真的有发生这种情况的情况。跨度>
          • 更新了答案以删除一个错字。
          猜你喜欢
          • 1970-01-01
          • 2011-07-11
          • 1970-01-01
          • 2016-10-15
          • 2017-07-03
          • 1970-01-01
          • 2023-03-27
          相关资源
          最近更新 更多