2011-01-05 115 views
612

我有許多列想從數據框中刪除。我知道我們可以刪除他們單獨使用類似的東西:按名稱刪除數據框列

df$x <- NULL 

但我希望用更少的命令做到這一點。

另外,我知道我可以使用索引的整數這樣的刪除列:

df <- df[ -c(1, 3:6, 12) ] 

但我關心的是我的變量的相對位置可能會改變。

給定的R多麼強大,我想有可能是比一個下探每列一個更好的辦法。

回答

684

您可以使用名稱的簡單列表:

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列的值。

+9

子集功能效果更好,因爲它不會轉換成數據幀有一列到一個載體 – mut1na 2013-06-28 09:06:09

+1

@ mut1na檢查:通過運行?one_of或在這裏找到參數drop =索引函數的FALSE。 – 2013-06-28 10:10:19

+1

不應該是'DF [,保持]'而不是'DF [保持]'嗎? – lindelof 2014-10-28 13:53:32

87

您可以使用%in%這樣的:

df[, !(colnames(df) %in% c("x","bar","foo"))] 
+0

我是否錯過了某些東西,或者這與Joris的答案的第一部分是否有效地相同? 'DF [,!(名稱(DF)%以%爲單位)]' – 2016-04-28 05:46:37

+4

@DanielFletcher:這是一樣的。看看答案的時間戳。我們同時回答... 5年前。 :) – 2016-04-28 13:01:18

+2

堅果。 '相同(post_time_1,post_time_2)[1] TRUE' = D – 2016-04-30 02:47:32

327

另外還有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)) 
+2

我真的希望R'子集'函數有一個選項,如「allbut = FALSE」,「反轉」選項設置爲TRUE時,即保留所有列*,除了* select列表中的列。 – 2011-01-05 14:56:20

+4

@prasad,請參閱下面的@joris答案。沒有任何子集標準的子集有點矯枉過正。試試看:'df [c(「a」,「c」)]' – 2011-01-05 15:16:33

+0

@JD我知道這一點,但我喜歡'subset'命令的語法方便性,因爲你不需要在列名 - 我想我不介意輸入一些額外的字符,以避免引用名稱:) – 2011-01-05 15:18:46

10

我一直在想,必須有一個更好的成語,但對於名字列的減法,我傾向於做到以下幾點:

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 
+4

否定匹配不是一個好主意 - ''df [, - match(c (「e」,「f」),names(df))]' – hadley 2011-01-05 18:33:24

34

有根據的事實是grep的一個潛在的更強大的戰略()將返回一個數字向量。如果你有一長串變量,就像我在其中一個數據集中做的那樣,一些變量以「.A」結尾,而其他變量以「.B」結尾,而你只需要以「.B」結尾的變量。A」(所有的變量一起不要麼模式匹配,這樣做:

dfrm2 <- dfrm[ , -grep("\\.B$", names(dfrm)) ] 

手頭的情況下,使用里斯Meys例如,它可能不會像緊湊,但它是:

DF <- DF[, -grep(paste("^",drops,"$", sep="", collapse="|"), names(DF))] 
+1

如果我們首先將'drops'定義爲'paste0(「^」,drop_cols,「$」)',這會變得好多了:更緊湊)使用'sapply':'DF [,-sapply(drops,grep,names(DF))]' – MichaelChirico 2016-04-13 20:31:19

16

另一種可能性:

df <- df[, setdiff(names(df), c("a", "c"))] 

df <- df[, grep('^(a|c)$', names(df), invert=TRUE)] 
+1

糟糕的是,這不是upvoted更多,因爲使用'setdiff'是最佳的,尤其是在大量的專欄。 – ctbrown 2014-03-25 21:42:04

+0

另一個角度就是:在(df,rm(x))內的'df < - df [, - 這個(grepl('a | c',names(df)))]' – Joe 2016-04-21 09:44:25

36

如果您想通過引用刪除列,並避免與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] 

如果您想預定義的名字作爲作爲調用[外面特徵向量,在(){}包裹對象的名稱,迫使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.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) 
19

出於興趣,這標誌着R的奇怪的多個語法不一致之一。例如,給定一個具有兩列的數據幀:

df <- data.frame(x=1, y=2) 

這給出了一個數據幀

subset(df, select=-y) 

但是這給一個矢量

df[,-2] 

這全部在?[說明,但它不是準確的預期行爲。至少不對我來說...

103
within(df, rm(x)) 

是可能比較容易,或多個變量:

within(df, rm(x, y)) 

或者,如果你正在處理data.table S(每How do you delete a column by name in data.table?):

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

dt[, !"x", with=FALSE] # selects all but x into a new data.table 

或多個變量

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

dt[, !c("x", "y"), with=FALSE] 

data.tableinstallation instructions)的開發版本,with = FALSE不再是必要的:

dt[ , !"x"] 
dt[ , !c("x", "y")] 
+15

'最乾淨的解決方案。鑑於這是一種可能性,所有其他答案似乎都不必要地複雜一個數量級。 – 2015-10-02 01:00:10

+2

請注意,如果在'df'中存在名爲'x'的重複列,'within(df,rm(x))'將不工作。 – MichaelChirico 2016-07-15 19:51:54

+1

@MichaelChirico澄清,它既不刪除,但似乎改變數據的價值觀。如果出現這種情況,則會遇到更大的問題,但這裏有一個例子:'df < - data.frame(x = 1,y = 2);名稱(df)< - c(「x」,「x」);在(df,rm(x))內返回'data.frame(x = 2,x = 2)'。 – 2017-03-10 22:23:11

36

列表(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" 
+1

太棒了!這將NULL分配以一種自然的方式擴展到單個列,並且(看似)避免了複製(雖然我不知道底層會發生什麼,所以它在內存使用方面可能沒有效率......但在我看來很清楚語法上更有效率。) – 2014-05-20 16:15:48

+4

您不需要列表(NULL),NULL就足夠了。例如:dat [,4] = NULL – CousinCocaine 2014-07-07 08:29:07

+5

OP的問題是如何刪除多列。 dat [,4:5] < - NULL將不起作用。這就是list(NULL)進來的地方。它適用於1列或更多列。 – Vincent 2014-09-16 00:01:45

15
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 
14

這裏是去做一個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() 

我喜歡這個,因爲它直觀的閱讀&理解沒有註釋和對列在數據框架內的位置變化具有魯棒性。它也遵循矢量化慣用法,使用-刪除元素。

+0

此外,(1)用戶想要替換原來的df(2)magrittr具有用於替換輸入對象的'%<>%'操作符,它可以簡化爲'df%<>%select select(-col.to.drop.1 ,-col.to.drop.2,...,-col.to.drop.6)' – Marek 2016-11-23 11:39:48

+1

如果你有一長串列要刪除,使用'dplyr',可能會更容易將它們分組並放入只有一個減:'df.cut <- df %>%select(-c(col.to.drop.1,col.to.drop.2,...,col.to.drop.n))' – 2017-05-04 06:32:12

16

另一個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 

如果你想在數據幀丟棄的變量序列,您可以使用:。例如,如果你想砸var2var3,並所有變量之間,你只是會留下var1

df2 <- df1 %>% select(-c(var2:var3)) 
df2 
#  var1 
#1 0.75879754 
#2 0.31168919 
#3 0.03983268 
9

有一個在貝恩德Bischl的BBmisc呼包dropNamed()一個函數,它正是這樣做的。

BBmisc::dropNamed(df, "x") 

的優點在於,它避免了重複數據幀的參數,因此適合於在管路magrittr(就像dplyr方法):

df %>% BBmisc::dropNamed("x") 
4

另一種解決方案,如果你不希望使用@哈德利的上面:如果「COLUMN_NAME」是列的名稱要刪除:

df[,-which(names(df) == "COLUMN_NAME")] 
+0

(1)問題是一次刪除多個列。 (2)如果'COLUMN_NAME'不在'df'中(檢查你自己:'df <-data.frame(a = 1,b = 2)'),它將不起作用。 (3)'df [,names(df)!=「COLUMN_NAME」]'更簡單,不會受到(2) – Marek 2016-11-23 11:34:10

+0

您能提供更多關於此答案的信息嗎? – 2018-01-17 13:04:46

2

我懷疑這會得到多少關注到這裏,但如果你甲肝

下面是一個簡單的,可再現的例子:

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

mtcars %>% 
    select(-one_of(undesired)) 

文檔可以是您要刪除,並希望做一個dplyr鏈我用one_of()select子句中的列EA名單

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