Drop data frame columns by name
我有许多列要从数据框中删除。我知道我们可以使用如下方式单独删除它们:
1 | df$x <- NULL |
但我希望用更少的命令来完成这个任务。
另外,我知道我可以像这样使用整数索引删除列:
1 | df <- df[ -c(1, 3:6, 12) ] |
但是我担心变量的相对位置可能会改变。
考虑到R有多强大,我认为有一种方法可能比逐个删除每一列要好。
您可以使用简单的名称列表:
1 2 3 4 5 6 7 8 | 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)] |
或者,您也可以列出要保留的内容并按名称引用它们:
1 2 | keeps <- c("y","a") DF[keeps] |
编辑:对于那些还不熟悉indexing函数的
1 2 | keeps <-"y" DF[ , keeps, drop = FALSE] |
还有
1 2 | df <- data.frame(a = 1:10, b = 2:11, c = 3:12) df <- subset(df, select = c(a, c)) |
@hadley:在评论后更新:要删除A、C列,可以执行以下操作:
1 | df <- subset(df, select = -c(a, c)) |
1 | within(df, rm(x)) |
可能是最简单的,或者对于多个变量:
1 | within(df, rm(x, y)) |
或者,如果您正在处理
1 2 3 | dt[, x := NULL] # Deletes column x by reference instantly. dt[, !"x"] # Selects all but x into a new data.table. |
或者对于多个变量
1 2 3 | dt[, c("x","y") := NULL] dt[, !c("x","y")] |
您可以这样使用
1 | df[, !(colnames(df) %in% c("x","bar","foo"))] |
列表(空)也有效:
1 2 3 4 5 6 7 | 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" |
如果要通过引用删除列并避免与
可以将字符向量名传递到
1 2 3 4 5 6 7 | 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] |
如果要在调用
1 2 3 4 5 6 | 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. |
您也可以使用
1 2 3 4 5 6 7 8 | 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) |
基于grep()将返回一个数字向量这一事实,有一种潜在的更强大的策略。如果你有一个长长的变量列表,就像我在我的数据集中所做的那样,一些变量以".a"结尾,而另一些变量以".b"结尾,你只需要以".a"结尾的变量(以及所有与这两种模式都不匹配的变量,请这样做:
1 | dfrm2 <- dfrm[ , -grep("\\.B$", names(dfrm)) ] |
对于手头的案例,使用Joris Meys的例子,它可能没有那么紧凑,但它可能是:
1 | DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )] |
另一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
如果要在数据帧中删除一系列变量,可以使用
1 2 3 4 5 6 | df2 <- df1 %>% select(-c(var2:var3) ) df2 # var1 #1 0.75879754 #2 0.31168919 #3 0.03983268 |
出于兴趣,这标志着R的一个奇怪的多语法不一致。例如,给定两列数据帧:
1 | df <- data.frame(x=1, y=2) |
这给出了一个数据帧
1 | subset(df, select=-y) |
但这给出了一个向量
1 | df[,-2] |
这在
另一种可能性:
1 | df <- df[, setdiff(names(df), c("a","c"))] |
或
1 | df <- df[, grep('^(a|c)$', names(df), invert=TRUE)] |
1 2 3 4 5 6 7 | DF <- data.frame( x=1:10, y=10:1, z=rep(5,10), a=11:20 ) DF |
输出:
1 2 3 4 5 6 7 8 9 10 11 | 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 |
1 | DF[c("a","x")] <- list(NULL) |
输出:
1 2 3 4 5 6 7 8 9 10 11 | 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 |
下面是一个
1 2 | #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() |
我喜欢这一点,因为阅读和理解无需注释,并且对数据帧中改变位置的列具有鲁棒性。它还遵循了使用
DPLYR溶液
我怀疑下面会引起很大的注意,但是如果您有一个要删除的列列表,并且您想在
下面是一个简单的、可复制的示例:
1 2 3 4 | undesired <- c('mpg', 'cyl', 'hp') mtcars <- mtcars %>% select(-one_of(undesired)) |
可以通过运行
http://genomicsclass.github.io/book/pages/dplyr_tutorial.html
我一直认为必须有一个更好的习惯用法,但对于按名称减去列,我倾向于执行以下操作:
1 2 3 4 5 | 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 |
在BerndBischl的
1 | BBmisc::dropNamed(df,"x") |
其优点是避免重复数据帧参数,因此适用于
1 | df %>% BBmisc::dropNamed("x") |
如果不想使用上面的@hadley's,另一个解决方案是:如果"columnu name"是要删除的列的名称:
1 | df[,-which(names(df) =="COLUMN_NAME")] |
除了前面的答案中演示的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
提供要删除的数据框和逗号分隔名称字符串:
1 2 3 4 5 | remove_features <- function(df, features) { rem_vec <- unlist(strsplit(features, ', ')) res <- df[,!(names(df) %in% rem_vec)] return(res) } |
用途:
1 | remove_features(iris,"Sepal.Length, Petal.Width") |
使用
1 2 3 4 5 6 7 8 9 10 | 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 |