提问



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


df$x <- NULL


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


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


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


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


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

最佳参考


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


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值的向量。

其它参考1


还有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))

其它参考2


within(df, rm(x))


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


within(df, rm(x, y))


或者如果您正在处理data.table s(根据如何在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.table(安装说明)的开发版本中,不再需要with = FALSE:[81]


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

其它参考3


您可以像这样使用%in%:


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

其它参考4


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"

其它参考5


如果要通过引用删除列并避免与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)

其它参考6


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


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


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


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

其它参考7


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


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


这给出了一个数据框


subset(df, select=-y)


但这给了一个矢量


df[,-2]


?[都解释了这一点,但并不是完全预期的行为。至少对我而言......

其它参考8


另一种可能性


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


要么


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

其它参考9


另一个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

其它参考10


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

其它参考11


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


我喜欢这个,因为它直观,阅读和理解没有注释,并且对于在数据框中改变位置的列具有鲁棒性。它还遵循使用-去除元素的矢量化习语。

其它参考12


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


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

其它参考13


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


BBmisc::dropNamed(df, "x")


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


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

其它参考14


我怀疑这会引起很多关注,但是如果你有一个要删除的列列表,并且你想在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[82]

其它参考15


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


df[,-which(names(df) == "COLUMN_NAME")]

其它参考16


一些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 

其它参考17


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


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")


[83]