首页 文章

按名称删除数据框列

提问于
浏览
716

我有一些列要从数据框中删除 . 我知道我们可以使用以下内容单独删除它们:

df$x <- NULL

但我希望用更少的命令来做到这一点 .

另外,我知道我可以使用整数索引来删除列,如下所示:

df <- df[ -c(1, 3:6, 12) ]

但我担心我的变量的相对位置可能会改变 .

考虑到R的强大程度,我认为可能有一种更好的方法,就是逐一删除每一列 .

19 回答

  • 129

    这是一个 dplyr 方式:

    #df[ -c(1,3:6, 12) ]  # original
    df.cut <- df %>% select(-col.to.drop.1, -col.to.drop.2, ..., -col.to.drop.6)  # with dplyr::select()
    

    我喜欢这个,因为没有注释就可以直观地阅读和理解,并且可以在数据框中更改位置 . 它还遵循使用 - 去除元素的矢量化习语 .

  • 18

    使用 which 查找要删除的列的索引 . 给这些索引一个负号( *-1 ) . 然后对这些值进行子集化,这将从数据帧中删除它们 . 这是一个例子 .

    DF <- data.frame(one=c('a','b'), two=c('c', 'd'), three=c('e', 'f'), four=c('g', 'h'))
    DF
    #  one two three four
    #1   a   d     f    i
    #2   b   e     g    j
    
    DF[which(names(DF) %in% c('two','three')) *-1]
    #  one four
    #1   a    g
    #2   b    h
    
  • 36

    出于兴趣,这标志着R的奇怪的多语法不一致之一 . 例如,给定一个两列数据框:

    df <- data.frame(x=1, y=2)
    

    这给出了一个数据框

    subset(df, select=-y)
    

    但这给了一个矢量

    df[,-2]
    

    这在 ?[ 中都有解释,但并不是完全预期的行为 . 好吧,至少不是我...

  • 1

    另一个 dplyr 回答 . 如果您的变量有一些共同的命名结构,您可以尝试 starts_with() . 例如

    library(dplyr)
    df <- data.frame(var1 = rnorm(5), var2 = rnorm(5), var3 = rnorm (5), 
                     var4 = rnorm(5), char1 = rnorm(5), char2 = rnorm(5))
    df
    #        var2      char1        var4       var3       char2       var1
    #1 -0.4629512 -0.3595079 -0.04763169  0.6398194  0.70996579 0.75879754
    #2  0.5489027  0.1572841 -1.65313658 -1.3228020 -1.42785427 0.31168919
    #3 -0.1707694 -0.9036500  0.47583030 -0.6636173  0.02116066 0.03983268
    df1 <- df %>% select(-starts_with("char"))
    df1
    #        var2        var4       var3       var1
    #1 -0.4629512 -0.04763169  0.6398194 0.75879754
    #2  0.5489027 -1.65313658 -1.3228020 0.31168919
    #3 -0.1707694  0.47583030 -0.6636173 0.03983268
    

    如果要在数据框中删除一系列变量,可以使用 : . 例如,如果你想删除 var2var3 和其间的所有变量,你只需要留下 var1

    df2 <- df1 %>% select(-c(var2:var3) )  
    df2
    #        var1
    #1 0.75879754
    #2 0.31168919
    #3 0.03983268
    
  • 381

    另一种解决方案,如果您不想使用上面的@ hadley:如果“COLUMN_NAME”是您要删除的列的名称:

    df[,-which(names(df) == "COLUMN_NAME")]
    
  • 770
    within(df, rm(x))
    

    可能是最简单的,或多个变量:

    within(df, rm(x, y))
    

    或者如果你正在处理 data.table s(每How do you delete a column by name in data.table?):

    dt[, x := NULL]   # deletes column x by reference instantly
    
    dt[, !"x", with=FALSE]   # selects all but x into a new data.table
    

    或多个变量

    dt[, c("x","y") := NULL]
    
    dt[, !c("x", "y"), with=FALSE]
    

    data.tableinstallation instructions)的开发版本中,不再需要 with = FALSE

    dt[ , !"x"]
    dt[ , !c("x", "y")]
    
  • 35

    还有 subset 命令,如果您知道所需的列,则非常有用:

    df <- data.frame(a = 1:10, b = 2:11, c = 3:12)
    df <- subset(df, select = c(a, c))
    

    @hadley评论后更新:要删除列a,c,您可以执行以下操作:

    df <- subset(df, select = -c(a, c))
    
  • 16

    我一直认为必须有一个更好的习语,但是为了按名称减去列,我倾向于做以下事情:

    df <- data.frame(a=1:10, b=1:10, c=1:10, d=1:10)
    
    # return everything except a and c
    df <- df[,-match(c("a","c"),names(df))]
    df
    
  • 18

    您可以像这样使用 %in%

    df[, !(colnames(df) %in% c("x","bar","foo"))]
    
  • 95

    除了 select(-one_of(drop_col_names)) 在前面的答案中演示之外,还有一些 dplyr 选项用于使用 select() 删除列,这些选项不涉及定义所有特定的列名称(使用dplyr starwars样本数据用于列名中的某些变体):

    library(dplyr)
    starwars %>% 
      select(-(name:mass)) %>%        # the range of columns from 'name' to 'mass'
      select(-contains('color')) %>%  # any column name that contains 'color'
      select(-starts_with('bi')) %>%  # any column name that starts with 'bi'
      select(-ends_with('er')) %>%    # any column name that ends with 'er'
      select(-matches('^f.+s$')) %>%  # any column name matching the regex pattern
      select_if(~!is.list(.)) %>%     # not by column name but by data type
      head(2)
    
    # A tibble: 2 x 2
    homeworld species
      <chr>     <chr>  
    1 Tatooine  Human  
    2 Tatooine  Droid
    
  • 2
    DF <- data.frame(
      x=1:10,
      y=10:1,
      z=rep(5,10),
      a=11:20
    )
    DF
    

    Output:

    x  y z  a
    1   1 10 5 11
    2   2  9 5 12
    3   3  8 5 13
    4   4  7 5 14
    5   5  6 5 15
    6   6  5 5 16
    7   7  4 5 17
    8   8  3 5 18
    9   9  2 5 19
    10 10  1 5 20
    

    DF[c("a","x")] <- list(NULL)
    

    Output:

    y z
        1  10 5
        2   9 5
        3   8 5
        4   7 5
        5   6 5
        6   5 5
        7   4 5
        8   3 5    
        9   2 5
        10  1 5
    
  • 19

    提供 data framecomma separated names 字符串以删除:

    remove_features <- function(df, features) {
      rem_vec <- unlist(strsplit(features, ', '))
      res <- df[,!(names(df) %in% rem_vec)]
      return(res)
    }
    

    Usage

    remove_features(iris, "Sepal.Length, Petal.Width")
    
  • 41

    基于grep()将返回数字向量这一事实,可能有更强大的策略 . 如果你在我的一个数据集中有一长串变量,那么一些变量以“.A”结尾,而另一些以“.B”结尾,你只想要以“.A”结尾的变量(沿着如果所有变量都不匹配任何模式,请执行以下操作:

    dfrm2 <- dfrm[ , -grep("\\.B$", names(dfrm)) ]
    

    对于手头的情况,使用Joris Meys示例,它可能不那么紧凑,但它将是:

    DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]
    
  • 11

    list(NULL)也有效:

    dat <- mtcars
    colnames(dat)
    # [1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear"
    # [11] "carb"
    dat[,c("mpg","cyl","wt")] <- list(NULL)
    colnames(dat)
    # [1] "disp" "hp"   "drat" "qsec" "vs"   "am"   "gear" "carb"
    
  • 6

    另一种可能性

    df <- df[, setdiff(names(df), c("a", "c"))]
    

    要么

    df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
    
  • 0

    在Bernd Bischl的 BBmisc 包中有一个名为 dropNamed() 的函数就是这样做的 .

    BBmisc::dropNamed(df, "x")
    

    优点是它避免重复数据框参数,因此适用于 magrittr 中的管道(就像 dplyr 方法一样):

    df %>% BBmisc::dropNamed("x")
    
  • 10

    Dplyr Solution

    我怀疑这会引起很多关注,但是如果你有一个要删除的列列表,并且你想在 dplyr 链中执行它,我在 select 子句中使用 one_of()

    这是一个简单,可重复的示例:

    undesired <- c('mpg', 'cyl', 'hp')
    
    mtcars %>%
      select(-one_of(undesired))
    

    可以通过运行 ?one_of 或此处找到文档:

    http://genomicsclass.github.io/book/pages/dplyr_tutorial.html

  • 19

    您可以使用简单的名称列表:

    DF <- data.frame(
      x=1:10,
      y=10:1,
      z=rep(5,10),
      a=11:20
    )
    drops <- c("x","z")
    DF[ , !(names(DF) %in% drops)]
    

    或者,您也可以列出要保留的列表并按名称引用它们:

    keeps <- c("y", "a")
    DF[keeps]
    

    编辑:对于那些仍然不熟悉索引函数的 drop 参数的人,如果要将一列保留为数据框,则执行以下操作:

    keeps <- "y"
    DF[ , keeps, drop = FALSE]
    

    drop=TRUE (或不提及它)将丢弃不必要的维度,因此返回具有列 y 的值的向量 .

  • 10

    如果要通过引用删除列并避免与 data.frames 关联的内部复制,则可以使用 data.table 包和函数 :=

    您可以将字符向量名称传递到 := 运算符的左侧,将 NULL 作为RHS传递 .

    library(data.table)
    
    df <- data.frame(a=1:10, b=1:10, c=1:10, d=1:10)
    DT <- data.table(df)
    # or more simply  DT <- data.table(a=1:10, b=1:10, c=1:10, d=1:10) #
    
    DT[, c('a','b') := NULL]
    

    如果要将名称预定义为字符向量在调用 [ 之外,在 (){} 中包装对象的名称,以强制在调用范围内评估LHS,而不是在 DT 范围内的名称 .

    del <- c('a','b')
    DT <- data.table(a=1:10, b=1:10, c=1:10, d=1:10)
    DT[, (del) := NULL]
    DT <-  <- data.table(a=1:10, b=1:10, c=1:10, d=1:10)
    DT[, {del} := NULL]
    # force or `c` would also work.
    

    你也可以使用 set ,这可以避免 [.data.tableand also works for data.frames! 的开销

    df <- data.frame(a=1:10, b=1:10, c=1:10, d=1:10)
    DT <- data.table(df)
    
    # drop `a` from df (no copying involved)
    
    set(df, j = 'a', value = NULL)
    # drop `b` from DT (no copying involved)
    set(DT, j = 'b', value = NULL)
    

相关问题