按名称删除数据框列

Bti*_*rt3 807 r dataframe r-faq

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

df$x <- NULL
Run Code Online (Sandbox Code Playgroud)

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

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

df <- df[ -c(1, 3:6, 12) ]
Run Code Online (Sandbox Code Playgroud)

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

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

Jor*_*eys 855

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

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

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

keeps <- c("y", "a")
DF[keeps]
Run Code Online (Sandbox Code Playgroud)

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

keeps <- "y"
DF[ , keeps, drop = FALSE]
Run Code Online (Sandbox Code Playgroud)

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

  • 子集函数效果更好,因为它不会将具有一列的数据帧转换为向量 (13认同)
  • @lindelof否.它可以,但是如果你只选择一个列,你必须添加drop = FALSE以防止R将数据帧转换为向量.不要忘记数据框是列表,因此列表选择(像我一样的一维)可以很好地工作并始终返回一个列表.或者在这种情况下是数据框,这就是我喜欢使用它的原因. (6认同)
  • @AjayOhri是的,它会的.如果没有逗号,则使用"列表"选择方式,这意味着即使提取单个列,您仍然会返回一个数据框.如果您像使用"矩阵"方式一样,您应该知道,如果您只选择一个列,则会得到一个向量而不是数据框.为避免这种情况,您需要添加drop = FALSE.正如我的回答和你上面的评论所解释的...... (6认同)
  • @ mut1na检查索引函数的参数drop = FALSE. (2认同)
  • 不应该是`DF [,keep]`而不是`DF [keep]`? (2认同)

Pra*_*ani 422

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

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

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

df <- subset(df, select = -c(a, c))
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您不应在其他函数中使用`subset`. (10认同)
  • @prasad,请参阅下面的@joris答案.没有任何子集标准的子集有点矫枉过正.试试简单:`df [c("a","c")]` (4认同)
  • @hadley这个`select = -b`似乎不起作用? (4认同)
  • 我真的希望R` subset`函数有一个像"allbut = FALSE"这样的选项,它在设置为TRUE时"反转"选择,即保留所有列*除了*select`列表中的那些列. (3认同)
  • @mac http://stackoverflow.com/questions/12850141/programming-safe-version-of-subset-to-evaluate-its-condition-while-Called-from/12852005#12852005 (2认同)

Max*_*nis 170

within(df, rm(x))
Run Code Online (Sandbox Code Playgroud)

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

within(df, rm(x, y))
Run Code Online (Sandbox Code Playgroud)

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

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

dt[, !"x"]   # Selects all but x into a new data.table.
Run Code Online (Sandbox Code Playgroud)

或多个变量

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

dt[, !c("x", "y")]
Run Code Online (Sandbox Code Playgroud)

  • `in(df,rm(x))`到目前为止*是最干净的解决方案.鉴于这是一种可能性,所有其他答案似乎不必要地复杂化了一个数量级. (22认同)
  • 请注意,如果在`df`中有重复的名为`x`的列,则`within(df,rm(x))`将不起作用. (2认同)
  • @MichaelChirico 澄清一下,它既没有删除,但似乎更改了数据的值。如果是这种情况,问题会更大,但这里有一个例子:`df &lt;- data.frame(x = 1, y = 2); 名称(df)&lt;- c(“x”,“x”);inside(df, rm(x))` 返回 `data.frame(x = 2, x = 2)`。 (2认同)

Jos*_*ich 109

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

df[, !(colnames(df) %in% c("x","bar","foo"))]
Run Code Online (Sandbox Code Playgroud)

  • @DanielFletcher:它是一样的.查看答案的时间戳.我们同时回答了...... 5年前.:) (9认同)
  • 坚果.`same(post_time_1,post_time_2)[1] TRUE` = D. (5认同)

Vin*_*ent 49

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"
Run Code Online (Sandbox Code Playgroud)

  • OP的问题是如何删除多个列.dat [,4:5] < - NULL不起作用.这就是list(NULL)的用武之地.它适用于1列或更多列. (8认同)
  • 你不需要列表(NULL),NULL就足够了.例如:dat [,4] = NULL (6认同)

42-*_*42- 39

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

dfrm2 <- dfrm[ , -grep("\\.B$", names(dfrm)) ]
Run Code Online (Sandbox Code Playgroud)

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

DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]
Run Code Online (Sandbox Code Playgroud)

  • 如果我们首先将 `drops` 定义为 `paste0("^", drop_cols, "$")`,那么使用 `sapply` 就会变得更好(读作:更紧凑): `DF[ , -sapply(drops, grep, 名称(DF))]` (2认同)

mne*_*nel 39

如果要通过引用删除列并避免与之关联的内部复制,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]
Run Code Online (Sandbox Code Playgroud)

如果要将名称预定义为调用之外的字符向量[,请将对象的名称包装在(){}强制在调用范围内评估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.   
Run Code Online (Sandbox Code Playgroud)

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


Pat*_* W. 27

另一个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
Run Code Online (Sandbox Code Playgroud)

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

df2 <- df1 %>% select(-c(var2:var3) )  
df2
#        var1
#1 0.75879754
#2 0.31168919
#3 0.03983268
Run Code Online (Sandbox Code Playgroud)

  • 不要忘记``select()```` 带来的所有其他机会,例如````contains()```` 或````matches()````,它们也接受正则表达式。 (2认同)

Kun*_*Ren 22

DF <- data.frame(
  x=1:10,
  y=10:1,
  z=rep(5,10),
  a=11:20
)
DF
Run Code Online (Sandbox Code Playgroud)

输出:

    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
Run Code Online (Sandbox Code Playgroud)
DF[c("a","x")] <- list(NULL)
Run Code Online (Sandbox Code Playgroud)

输出:

        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
Run Code Online (Sandbox Code Playgroud)


Use*_*716 22

Dplyr解决方案

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

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

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

mtcars <- mtcars %>%
  select(-one_of(undesired))
Run Code Online (Sandbox Code Playgroud)

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

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


jke*_*ead 21

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

df <- data.frame(x=1, y=2)
Run Code Online (Sandbox Code Playgroud)

这给出了一个数据框

subset(df, select=-y)
Run Code Online (Sandbox Code Playgroud)

但这给了一个矢量

df[,-2]
Run Code Online (Sandbox Code Playgroud)

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


sce*_*oni 20

另一种可能性

df <- df[, setdiff(names(df), c("a", "c"))]
Run Code Online (Sandbox Code Playgroud)

要么

df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
Run Code Online (Sandbox Code Playgroud)

  • 太糟糕了,这没有得到更多的支持,因为使用 `setdiff` 是最佳选择,尤其是在列数非常多的情况下。 (2认同)

c.g*_*rez 18

这是一种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()
Run Code Online (Sandbox Code Playgroud)

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


JD *_*ong 14

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

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
Run Code Online (Sandbox Code Playgroud)

  • 否定匹配不是一个好主意 - `df [, - match(c("e","f"),names(df))]` (4认同)

krl*_*mlr 12

dropNamed()Bernd Bischl的BBmisc软件包中有一个函数正是这样做的.

BBmisc::dropNamed(df, "x")
Run Code Online (Sandbox Code Playgroud)

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

df %>% BBmisc::dropNamed("x")
Run Code Online (Sandbox Code Playgroud)


Nic*_*ris 8

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

df[,-which(names(df) == "COLUMN_NAME")]
Run Code Online (Sandbox Code Playgroud)


sbh*_*bha 7

除了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 
Run Code Online (Sandbox Code Playgroud)


Cyb*_*tic 6

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

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

用法

remove_features(iris, "Sepal.Length, Petal.Width")
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述