我想从数据帧中删除一些列。我知道我们可以使用如下方法单独删除它们:
df$x <- NULL
但我希望用更少的命令来做到这一点。
另外,我知道我可以像这样使用整数索引删除列:
df <- df[ -c(1, 3:6, 12) ]
但我担心变量的相对位置可能会改变。
考虑到R的强大功能,我认为可能有一种比逐个删除每一列更好的方法。
我想从数据帧中删除一些列。我知道我们可以使用如下方法单独删除它们:
df$x <- NULL
但我希望用更少的命令来做到这一点。
另外,我知道我可以像这样使用整数索引删除列:
df <- df[ -c(1, 3:6, 12) ]
但我担心变量的相对位置可能会改变。
考虑到R的强大功能,我认为可能有一种比逐个删除每一列更好的方法。
当前回答
如果您希望通过引用删除列并避免与data.frames相关的内部复制,则可以使用数据。表包和函数:=
您可以将字符向量名称传递到:=运算符的左侧,并将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]的开销。表,也适用于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)
其他回答
你可以使用一个简单的名字列表:
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列值的向量。
Dplyr解决方案
我怀疑这在这里会得到很多关注,但如果你有一个列列表,你想要删除,并且你想在dplyr链中做它,我在select子句中使用one_of():
这里有一个简单的,可复制的例子:
undesired <- c('mpg', 'cyl', 'hp')
mtcars <- mtcars %>%
select(-one_of(undesired))
可以通过运行?one_of或在这里找到文档:
http://genomicsclass.github.io/book/pages/dplyr_tutorial.html
除了在前面的回答中演示的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列:如果列名不存在,则会发出警告。在这个例子中,'bad_column'不是数据帧中的列:
starwars %>%
select_if(!names(.) %in% c('height', 'mass', 'bad_column'))
我一直在想一定有更好的习语,但对于按名称减法的列,我倾向于这样做:
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
基于grep()将返回数字向量这一事实,有一种可能更强大的策略。如果你有一个很长的变量列表,就像我在我的数据集中做的那样,一些变量以“。A和其他以。结尾的。B"你只想要以。结尾的。A”(连同所有不符合任何一种模式的变量,这样做:
dfrm2 <- dfrm[ , -grep("\\.B$", names(dfrm)) ]
对于手头的情况,使用Joris Meys的例子,它可能没有那么紧凑,但它将是:
DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]