df$x <- NULL
但是我希望用更少的命令来做到这一点。
此外,我知道我可以使用整数索引删除列,如下所示:
df <- df[ -c(1, 3:6, 12) ]
但是我担心变量的相对位置可能会发生变化。
鉴于R的强大功能,我认为可能有比逐一删除每一列更好的方法。
#1 楼
您可以使用简单的名称列表: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
列值的向量。评论
子集函数效果更好,因为它不会将具有一列的数据帧转换为向量
– mut1na
13年6月28日在9:06
@ mut1na检查索引函数的参数drop = FALSE。
– Joris Meys
13年6月28日在10:10
那不是DF [,keeps]而不是DF [keeps]吗?
– lindelof
2014-10-28 13:53
@lindelof不。可以,但是如果仅选择一个列,则必须添加drop = FALSE,以防止R将数据帧转换为向量。别忘了数据框是列表,因此列表选择(像我所做的那样是一维的)效果很好,并且总是返回列表。还是这种情况下的数据帧,这就是为什么我更喜欢使用它。
– Joris Meys
2014年10月28日19:05
@AjayOhri是的,会的。如果不使用逗号,则使用“列表”选择方式,这意味着即使提取单个列,也仍然会返回数据框。如果使用“矩阵”方式,则应注意,如果仅选择单个列,则将获得向量而不是数据框。为了避免这种情况,您需要添加drop = FALSE。如我的回答以及您上方的评论中所述...
– Joris Meys
15年7月7日在13:55
#2 楼
还有一个subset
命令,如果您知道要哪些列,则很有用: br /> df <- data.frame(a = 1:10, b = 2:11, c = 3:12)
df <- subset(df, select = c(a, c))
评论
我真的希望R子集函数具有“ allbut = FALSE”之类的选项,该选项在设置为TRUE时“反转”选择,即保留除选择列表中的所有列之外的所有列。
– Prasad Chalasani
2011年1月5日14:56
@prasad,请参阅下面的@joris答案。没有任何子集条件的子集有点过大。简单尝试:df [c(“ a”,“ c”)]
–JD Long
2011年1月5日15:16
@JD我知道这一点,但是我喜欢子集命令的语法方便性,在该语法中,您不需要在列名称周围加上引号-我想我不介意输入一些额外的字符,只是避免引用名称:)
– Prasad Chalasani
2011年1月5日15:18
请注意,您不应在其他函数中使用子集。
–阿里·弗里德曼(Ari B. Friedman)
2012年10月3日14:42
@mac stackoverflow.com/questions/12850141 / ...
–阿里·弗里德曼(Ari B. Friedman)
13年9月30日在18:33
#3 楼
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"] # Selects all but x into a new data.table.
或用于多个变量
dt[, c("x","y") := NULL]
dt[, !c("x", "y")]
评论
到目前为止,inner(df,rm(x))是最干净的解决方案。鉴于这是可能的,其他所有答案似乎都不必要地复杂一个数量级。
–Miles Erickson
2015年10月2日1:00
请注意,如果在df中有重复的名为x的列,则inner(df,rm(x))将不起作用。
–MichaelChirico
16年7月15日在19:51
@MichaelChirico进行澄清,它既未删除,但似乎更改了数据的值。如果是这种情况,则会遇到更大的问题,但这是一个示例:df <-data.frame(x = 1,y = 2); names(df)<-c(“ x”,“ x”); inside(df,rm(x))返回data.frame(x = 2,x = 2)。
– Max Ghenis
17 Mar 10 '17 at 22:23
@MilesErickson问题是您依赖一个内部函数,该函数既强大又使用NSE。帮助页面上的注释清楚地表明,在编程时应格外小心。
– Joris Meys
18/12/13在13:45
@MilesErickson人们多久会遇到一个名称重复的数据框?
–HSchmale
19年1月3日,19:26
#4 楼
您可以像这样使用%in%
:df[, !(colnames(df) %in% c("x","bar","foo"))]
评论
我是否缺少某些东西,或者这实际上与乔里斯回答的第一部分是相同的解决方案? DF [,!(names(DF)%in%drops)]
–丹尼尔·弗莱彻(Daniel Fletcher)
16年4月28日在5:46
@DanielFletcher:一样。查看答案上的时间戳。我们在5年前同时回答。 :)
–约书亚·乌尔里希(Joshua Ulrich)
16年4月28日在13:01
坚果相同(post_time_1,post_time_2)[1]是= D
–丹尼尔·弗莱彻(Daniel Fletcher)
16-4-30的2:47
#5 楼
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"
评论
辉煌!这以一种自然的方式将NULL赋值扩展到单个列,并且(似乎)避免了复制(尽管我不知道幕后发生的事情,因此它在内存使用方面可能没有更高的效率……但是在我看来语法上更有效。)
–c-urchin
2014年5月20日下午16:15
您不需要list(NULL),NULL就足够了。例如:dat [,4] = NULL
–库辛可卡因
2014年7月7日在8:29
OP的问题是如何删除多个列。 dat [,4:5] <-NULL无效。这就是list(NULL)出现的地方。它适用于1个或更多列。
– Vincent
2014年9月16日下午0:01
尝试删除重复的列名时,这也不起作用。
–MichaelChirico
16年7月15日在19:58
@MichaelChirico对我来说很好。如果要删除具有相同名称的第一列,请给标签,或者为要删除的每一列提供索引。如果您有一个不起作用的示例,那么我将很感兴趣地看到它。也许将其发布为新问题?
– Vincent
16年7月15日在22:47
#6 楼
如果要通过引用删除列并避免与data.frames
相关的内部复制,则可以使用data.table
软件包和函数:=
您可以将字符向量名称传递到
:=
的左侧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]
如果要在对
NULL
的调用之外将名称预先定义为字符向量,请将对象的名称包装在[
中或()
强制在调用范围内评估LHS而不是{}
范围内的名称。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.
还可以使用
DT
,这样可以避免开销适用于set
,也适用于[.data.table
!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)
#7 楼
根据grep()将返回数字矢量这一事实,有一种可能更强大的策略。如果您像我在一个数据集中那样拥有一长串变量,则某些变量以“ .A”结尾,而另一些变量以“ .B”结尾,而您只想要以“ .A”结尾的变量(以及对于所有与两个模式都不匹配的变量,请执行以下操作:dfrm2 <- dfrm[ , -grep("\.B$", names(dfrm)) ]
对于手头的情况,使用Joris Meys示例,它可能不那么紧凑,而是:
DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]
评论
如果我们首先将drop定义为paste0(“ ^”,drop_cols,“ $”),则使用sapply会更好(阅读:更紧凑):DF [,-sapply(drops,grep,names(DF)) ]
–MichaelChirico
16-4-13在20:31
#8 楼
另一个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
如果要在数据框中删除一系列变量,则可以使用
:
。例如,如果您要删除var2
,var3
以及它们之间的所有变量,则只剩下var1
:df2 <- df1 %>% select(-c(var2:var3) )
df2
# var1
#1 0.75879754
#2 0.31168919
#3 0.03983268
评论
不要忘记select()附带的所有其他机会,例如contains()或matches(),它们也接受正则表达式。
– ha-pu
19年3月1日在17:31
#9 楼
Dplyr解决方案我怀疑这会在这里引起很多关注,但是如果您有要删除的列的列表,并且希望在
dplyr
链中进行操作,我会在one_of()
中使用select
子句:这是一个简单的可复制示例:
undesired <- c('mpg', 'cyl', 'hp')
mtcars <- mtcars %>%
select(-one_of(undesired))
可以通过运行
?one_of
或此处找到文档: br />http://genomicsclass.github.io/book/pages/dplyr_tutorial.html #10 楼
另一种可能性:df <- df[, setdiff(names(df), c("a", "c"))]
或
df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
评论
遗憾的是,不能更进一步,因为setdiff是最佳选择,尤其是在列数非常多的情况下。
–ctbrown
2014年3月25日在21:42
另一个角度:df <-df [,-which(grepl('a | c',names(df)))]
–乔
16年4月21日在9:44
#11 楼
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
#12 楼
出于兴趣,这标记了R奇怪的多个语法不一致之一。例如,给定一个两列数据框:df <- data.frame(x=1, y=2)
这给出一个数据框
subset(df, select=-y)
但是这给出了一个向量
df[,-2]
在
?[
中对此进行了解释,但这并不是完全预期的行为。好吧至少对我来说... #13 楼
这是一种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()
我喜欢这种方式,因为它直观且无需注释即可阅读和理解,并且对更改数据框中列的位置具有鲁棒性。它还遵循使用
-
删除元素的矢量化习惯用法。评论
加上(1)用户想要替换原始df(2)magrittr具有%<>%运算符来替换输入对象,可以将其简化为df%<>%select(-col.to.drop.1,-col。 to.drop.2,...,-col.to.drop.6)
–马雷克
16-11-23在11:39
如果使用dplyr删除一长列的列,则将它们分组并放一个减号可能会更容易:df.cut <-df%>%select(-c(col.to.drop.1,col .to.drop.2,...,col.to.drop.n))
– iNyar
17年5月4日在6:32
#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
评论
否定匹配不是一个好主意-df [,-match(c(“ e”,“ f”),names(df))]
–哈德利
11年5月5日在18:33
。@ JDLong-如果我想删除列名称以-开头的列怎么办?
–车丹·阿文·帕蒂尔(Chetan Arvind Patil)
19年1月22日在18:04
#15 楼
Bernd Bischl的dropNamed()
软件包中有一个名为BBmisc
的函数可以精确地执行此操作。 magrittr
(就像dplyr
方法一样):BBmisc::dropNamed(df, "x")
#16 楼
如果您不想使用上面的@hadley,则可以使用另一种解决方案:如果“ COLUMN_NAME”是您要删除的列的名称:df[,-which(names(df) == "COLUMN_NAME")]
评论
(1)问题是一次删除多列。 (2)如果COLUMN_NAME不在df中,则将无法正常工作(请检查一下:df <-data.frame(a = 1,b = 2))。 (3)df [,names(df)!=“ COLUMN_NAME”]比较简单,不会受到(2)的影响
–马雷克
16年11月23日在11:34
您能否提供有关此答案的更多信息?
–阿卡什·纳亚克(Akash Nayak)
18年1月17日在13:04
#17 楼
除了早先的答案中展示的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()
的一种小方法,与使用one_of()
的情况不同,如果列名确实存在,则不会发出Unknown columns:
警告不存在。在此示例中,“ bad_column”不是数据框中的列:starwars %>%
select_if(!names(.) %in% c('height', 'mass', 'bad_column'))
#18 楼
提供要删除的数据框和一串用逗号分隔的名称: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")
#19 楼
使用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
#20 楼
如果data.frame
很大而内存不足,请使用[
。 。 。 。或rm
和within
删除data.frame
的列,因为subset
当前(R 3.6.2)使用更多的内存-在手册的提示中可以交互使用subset
。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
评论
有人可以向我解释为什么R没有像df#drop(var_name)这样简单的东西,而是我们需要做这些复杂的变通方法吗?@ ifly6 R中的'subset()'函数与Python中的'drop()'函数差不多,只是您不需要指定axis参数...我同意这很烦人,只是一个全面的,最终的,简单易用的关键字/语法,用于一些基本的操作,例如删除一列。