提问人:Btibert3 提问时间:1/5/2011 最后编辑:HenrikBtibert3 更新时间:8/27/2022 访问量:1904272
按名称删除数据框列
Drop data frame columns by name
问:
我想从数据框中删除许多列。我知道我们可以使用以下方法单独删除它们:
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
(或不提及它)将删除不必要的维度,因此返回一个值为 column 的向量。y
评论
DF[,keeps]
DF[keeps]
你可以这样使用:%in%
df[, !(colnames(df) %in% c("x","bar","foo"))]
评论
DF[ , !(names(DF) %in% drops)]
identical(post_time_1, post_time_2) [1] TRUE
df[!(colnames(df) %in% c("x","bar","foo"))]
还有一个命令,如果你知道你想要哪些列,它很有用: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))
评论
subset
select
df[c("a", "c")]
subset
subset
我一直认为一定有更好的成语,但是对于按名称减去列,我倾向于执行以下操作:
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))]
-
基于grep()将返回一个数字向量这一事实,可能有一个更强大的策略。如果你有一个很长的变量列表,就像我在我的一个数据集中所做的那样,一些以“.A“和其他以”.B“,你只想要以”.A“(连同所有与任一模式不匹配的变量,执行以下操作:
dfrm2 <- dfrm[ , -grep("\\.B$", names(dfrm)) ]
对于手头的情况,以 Joris Meys 为例,它可能没有那么紧凑,但它会是:
DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]
评论
drops
paste0("^", drop_cols, "$")
sapply
DF[ , -sapply(drops, grep, names(DF))]
另一种可能性:
df <- df[, setdiff(names(df), c("a", "c"))]
或
df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
评论
setdiff
df <- df[ , -which(grepl('a|c', names(df)))]
如果要通过引用删除列并避免与之关联的内部复制,则可以使用包和函数data.frames
data.table
:=
您可以将字符向量名称传递到运算符的左侧,并作为 RHS。:=
NULL
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.
您还可以使用 ,它避免了 的开销,并且也适用于 data.frames
!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)
出于兴趣,这标记了 R 奇怪的多种语法不一致之一。例如,给定一个两列数据框:
df <- data.frame(x=1, y=2)
这给出了一个数据框
subset(df, select=-y)
但这给出了一个向量
df[,-2]
这都在解释中,但并不完全是预期的行为。好吧,至少对我来说不是......?[
within(df, rm(x))
可能是最简单的,或者对于多个变量:
within(df, rm(x, y))
或者,如果您正在处理 s(根据 如何在 data.table 中按名称删除列?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")]
评论
within(df, rm(x))
是迄今为止最干净的解决方案。鉴于这是一种可能性,所有其他答案似乎都不必要地复杂了一个数量级。
within(df, rm(x))
x
df
df <- data.frame(x = 1, y = 2); names(df) <- c("x", "x"); within(df, rm(x))
data.frame(x = 2, x = 2)
within()
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"
评论
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
这里有一种方法可以解决它: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()
我喜欢这个,因为它在没有注释的情况下阅读和理解很直观,并且对列在数据框中改变位置很可靠。它还遵循用于删除元素的矢量化习语。-
评论
%<>%
df %<>% select(-col.to.drop.1, -col.to.drop.2, ..., -col.to.drop.6)
dplyr
df.cut <- df %>% select(-c(col.to.drop.1, col.to.drop.2, ..., col.to.drop.n))
另一个答案。
用。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
评论
select()
contains()
matches()
Bernd Bischl 的包中有一个函数可以做到这一点。dropNamed()
BBmisc
BBmisc::dropNamed(df, "x")
优点是它避免了重复数据帧参数,因此适合管道输入(就像方法一样):magrittr
dplyr
df %>% BBmisc::dropNamed("x")
如果您不想使用上述@hadley,另一种解决方案: 如果“COLUMN_NAME”是要删除的列的名称:
df[,-which(names(df) == "COLUMN_NAME")]
评论
COLUMN_NAME
df
df<-data.frame(a=1,b=2)
df[,names(df) != "COLUMN_NAME"]
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
提供要删除的数据框和逗号分隔的名称字符串:
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")
除了前面的答案中演示之外,还有其他几个选项可用于删除列,这些选项不涉及定义所有特定的列名称(使用 dplyr starwars 示例数据来表示列名称的某些变化):select(-one_of(drop_col_names))
dplyr
select()
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
如果您需要删除数据框中可能存在也可能不存在的列,这里有一个轻微的转折,使用与使用不同,如果列名称不存在,则不会引发警告。在此示例中,“bad_column”不是数据框中的列:select_if()
one_of()
Unknown columns:
starwars %>%
select_if(!names(.) %in% c('height', 'mass', 'bad_column'))
使用 找到要删除的列的索引。给这些索引一个负号 ()。然后对这些值进行子集,这将从数据帧中删除它们。这是一个示例。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
如果你有一个大和低内存使用。 。 。 。或 rm
和 within
删除 data.frame
的列,就像当前 (R 3.6.2) 使用更多内存一样 - 除了手册的提示以交互方式使用子集
。data.frame
[
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
另一个尚未发布的 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 中此类任务的所有选项的摘要
你可以做很多方法......
选项 1:
df[ , -which(names(df) %in% c("name1","name2"))]
选项 2:
df[!names(df) %in% c("name1", "name2")]
选项 3:
subset(df, select=-c(name1,name2))
在数据框中按列名称删除和删除列。
A <- df[ , c("Name","Name1","Name2","Name3")]
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
使用折叠包中的函数的另一个选项。下面是一个可重现的例子:fselect
DF <- data.frame(
x=1:10,
y=10:1,
z=rep(5,10),
a=11:20
)
library(collapse)
fselect(DF, -z)
#> x y a
#> 1 1 10 11
#> 2 2 9 12
#> 3 3 8 13
#> 4 4 7 14
#> 5 5 6 15
#> 6 6 5 16
#> 7 7 4 17
#> 8 8 3 18
#> 9 9 2 19
#> 10 10 1 20
创建于 2022-08-26 with reprex v2.0.2
评论
df#drop(var_name)