982

我有许多要从数据框中删除的列。我知道我们可以使用以下方法单独删除它们:

df$x <- NULL

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

另外,我知道我可以像这样使用整数索引删除列:

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

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

鉴于 R 的强大功能,我认为可能有比一一删除每一列更好的方法。

4

24 回答 24

1006

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

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(或不提及)将删除不必要的维度,因此返回一个带有 column 值的向量y

于 2011-01-05T14:40:25.807 回答
504

还有一个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))
于 2011-01-05T14:52:40.727 回答
240
within(df, rm(x))

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

within(df, rm(x, y))

或者,如果您正在处理data.tables(根据您如何在 data.table 中按名称删除列?):

dt[, x := NULL]   # Deletes column x by reference instantly.

dt[, !"x"]   # Selects all but x into a new data.table.

或多个变量

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

dt[, !c("x", "y")]
于 2013-09-28T22:28:56.747 回答
130

你可以这样使用%in%

df[, !(colnames(df) %in% c("x","bar","foo"))]
于 2011-01-05T14:40:26.917 回答
61

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"
于 2014-02-12T05:34:52.497 回答
45

如果要通过引用删除列并避免与之关联的内部复制,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.table也适用于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)
于 2012-11-14T01:02:41.563 回答
44

基于 grep() 将返回数字向量这一事实,有一个可能更强大的策略。如果您像我在我的一个数据集中所做的那样有一长串变量,一些以“.A”结尾的变量和其他以“.B”结尾的变量,您只想要以“.A”结尾的变量(以及对于与任一模式都不匹配的所有变量,请执行以下操作:

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

对于手头的情况,以 Joris Meys 为例,它可能没有那么紧凑,但它会是:

DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]
于 2011-01-05T21:50:03.730 回答
37

另一个dplyr答案。使用select(-column).

如果你的变量有一些通用的命名结构,你可以试试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

如果要在数据框中删除一系列变量,可以使用:. 例如,如果您想删除var2,var3和介于两者之间的所有变量,则只剩下var1:

df2 <- df1 %>% select(-c(var2:var3) )  
df2
#        var1
#1 0.75879754
#2 0.31168919
#3 0.03983268
于 2014-11-22T20:37:02.827 回答
32

Dplyr 解决方案

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

这是一个简单的、可重现的示例:

undesired <- c('mpg', 'cyl', 'hp')

mtcars <- mtcars %>%
  select(-one_of(undesired))

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

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

于 2018-01-31T11:46:06.723 回答
26

另一种可能:

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

或者

df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
于 2012-01-10T23:17:34.093 回答
23
DF <- data.frame(
  x=1:10,
  y=10:1,
  z=rep(5,10),
  a=11:20
)
DF

输出:

    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)

输出:

        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
于 2014-06-20T00:27:53.453 回答
22

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

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

这给出了一个数据框

subset(df, select=-y)

但这给出了一个向量

df[,-2]

这一切都在中进行了解释,?[但这并不是完全预期的行为。好吧,至少对我来说不是……

于 2013-05-02T18:42:27.023 回答
19

这是一种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()

我喜欢这个,因为它在没有注释的情况下易于阅读和理解,并且对数据框中的列位置变化具有鲁棒性。它还遵循矢量化的习惯用法 using -to remove elements。

于 2014-08-27T17:01:54.847 回答
15

我一直认为必须有一个更好的成语,但是对于按名称减去列,我倾向于执行以下操作:

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
于 2011-01-05T17:21:58.217 回答
12

dropNamed()Bernd Bischl 的BBmisc包中调用了一个函数来执行此操作。

BBmisc::dropNamed(df, "x")

优点是它避免了重复数据框参数,因此适合管道输入magrittr(就像dplyr方法一样):

df %>% BBmisc::dropNamed("x")
于 2014-12-04T14:06:22.450 回答
9

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

df[,-which(names(df) == "COLUMN_NAME")]
于 2016-10-25T22:57:20.200 回答
9

除了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 

如果您需要删除数据框中可能存在或不存在的列,这里有一个轻微的扭曲,使用select_if()它与 using 不同,如果列名称不存在,one_of()则不会引发警告。Unknown columns:在此示例中,“bad_column”不是数据框中的列:

starwars %>% 
  select_if(!names(.) %in% c('height', 'mass', 'bad_column'))
于 2018-07-02T21:34:29.690 回答
4

提供要删除的数据框和一串逗号分隔的名称:

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

用法

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

在此处输入图像描述

于 2018-06-15T16:51:02.373 回答
2

按数据框中的列名删除和删除列。

A <- df[ , c("Name","Name1","Name2","Name3")]
于 2021-11-02T19:03:48.760 回答
1

使用 查找要删除的列的索引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
于 2018-08-03T17:44:13.330 回答
1

如果你有一个大data.frame的内存使用率低[ . . . 或删除 a的列,rm目前within(R 3.6.2)使用更多内存 - 除了手册提示以交互方式使用之外。data.framesubsetsubset

getData <- function() {
  n <- 1e7
  set.seed(7)
  data.frame(a = runif(n), b = runif(n), c = runif(n), d = runif(n))
}

DF <- getData()
tt <- sum(.Internal(gc(FALSE, TRUE, TRUE))[13:14])
DF <- DF[setdiff(names(DF), c("a", "c"))] ##
#DF <- DF[!(names(DF) %in% c("a", "c"))] #Alternative
#DF <- DF[-match(c("a","c"),names(DF))]  #Alternative
sum(.Internal(gc(FALSE, FALSE, TRUE))[13:14]) - tt
#0.1 MB are used

DF <- getData()
tt <- sum(.Internal(gc(FALSE, TRUE, TRUE))[13:14])
DF <- subset(DF, select = -c(a, c)) ##
sum(.Internal(gc(FALSE, FALSE, TRUE))[13:14]) - tt
#357 MB are used

DF <- getData()
tt <- sum(.Internal(gc(FALSE, TRUE, TRUE))[13:14])
DF <- within(DF, rm(a, c)) ##
sum(.Internal(gc(FALSE, FALSE, TRUE))[13:14]) - tt
#0.1 MB are used

DF <- getData()
tt <- sum(.Internal(gc(FALSE, TRUE, TRUE))[13:14])
DF[c("a", "c")]  <- NULL ##
sum(.Internal(gc(FALSE, FALSE, TRUE))[13:14]) - tt
#0.1 MB are used
于 2019-12-16T11:56:06.263 回答
0

另一个尚未发布的data.table.SD选项是使用特殊动词,它代表数据的子集。与.SDcols参数一起,您可以按名称或索引选择/删除列。

require(data.table)
# data
dt = data.table(
  A = LETTERS[1:5],
  B = 1:5,
  C = rep(TRUE, 5)
)
# delete B
dt[ , .SD, .SDcols =! 'B' ]
# delete all matches (i.e. all columns)
cols = grep('[A-Z]+', names(dt), value = TRUE)
dt[ , .SD, .SDcols =! cols ]

可以在此处找到data.table中此类任务的所有选项的摘要

于 2021-08-12T10:27:31.943 回答
0

有很多方法可以做...

选项1:

df[ , -which(names(df) %in% c("name1","name2"))]

选项 2:

df[!names(df) %in% c("name1", "name2")]

选项 3:

subset(df, select=-c(name1,name2))
于 2021-10-24T06:44:20.427 回答
0
df <- data.frame(
+   a=1:5,
+   b=6:10,
+   c=rep(22,5),
+   d=round(runif(5)*100, 2),
+   e=round(runif(5)*100, 2),
+   f=round(runif(5)*100, 2),
+   g=round(runif(5)*100, 2),
+   h=round(runif(5)*100, 2)
+ )
> df
  a  b  c     d     e     f     g     h
1 1  6 22 76.31 39.96 66.62 72.75 73.14
2 2  7 22 53.41 94.85 96.02 97.31 85.32
3 3  8 22 98.29 38.95 12.61 29.67 88.45
4 4  9 22 20.04 53.53 83.07 77.50 94.99
5 5 10 22  5.67  0.42 15.07 59.75 31.21

> # remove cols: d g h
> newDf <- df[, c(1:3, 5), drop=TRUE]
> newDf
  a  b  c     e
1 1  6 22 39.96
2 2  7 22 94.85
3 3  8 22 38.95
4 4  9 22 53.53
5 5 10 22  0.42
于 2021-11-29T21:44:22.160 回答