이름별로 데이터 프레임 열 삭제


874

데이터 프레임에서 제거하려는 여러 열이 있습니다. 다음과 같은 것을 사용하여 개별적으로 삭제할 수 있음을 알고 있습니다.

df$x <- NULL

그러나 나는 더 적은 명령으로 이것을하기를 바랐다.

또한 정수 색인을 사용하여 다음과 같이 열을 삭제할 수 있음을 알고 있습니다.

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

그러나 변수의 상대 위치가 변경 될 수 있다고 걱정합니다.

R이 얼마나 강력한지를 감안할 때 각 열을 하나씩 삭제하는 것보다 더 좋은 방법이 있다고 생각했습니다.


13
누군가 R에 왜 간단한 것이 없는지 설명해 줄 수 있습니까? df#drop(var_name)대신 복잡한 해결 방법이 필요합니까?
ifly6

2
@ ifly6 R의 'subset ()'함수는 축 인수를 지정할 필요가 없다는 점을 제외하고 Python의 'drop ()'함수와 비슷합니다. 열을 떨어 뜨리는 것과 같은 기본적인 것을 위해 하나의 궁극적이고 쉬운 키워드 / 구문이 전반적으로 구현됩니다.
Paul Sochacki

답변:


912

간단한 이름 목록을 사용할 수 있습니다.

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.


19
서브셋 함수는 하나의 열을 가진 데이터 프레임을 벡터로 변환하지 않기 때문에 더 잘 작동합니다
mut1na

3
@ mut1na 인덱싱 함수의 drop = FALSE 인수를 확인하십시오.
Joris Meys

4
DF[,keeps]대신 해서는 안 DF[keeps]됩니까?
lindelof

8
@lindelof 아니요. 단 하나의 열만 선택한 경우 R이 데이터 프레임을 벡터로 변환하지 못하게하려면 drop = FALSE를 추가해야합니다. 데이터 프레임이 목록이라는 것을 잊지 마십시오. 목록 선택 (1 차원과 같은)은 완벽하게 작동하며 항상 목록을 반환합니다. 또는이 경우 데이터 프레임이므로 사용하는 것이 좋습니다.
Joris Meys

7
@AjayOhri 그렇습니다. 쉼표가 없으면 "목록"선택 방법을 사용합니다. 즉, 단일 열을 추출하더라도 여전히 데이터 프레임이 반환됩니다. "행렬"방식을 사용하는 경우 단일 열만 선택하면 데이터 프레임 대신 벡터가 생성됩니다. 이를 방지하려면 drop = FALSE를 추가해야합니다. 마찬가지로 내 대답에 설명하고, 바로 당신 위의 코멘트 더 ...
요리스 MEYS

453

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))

3
R subset함수에 "allbut = FALSE"와 같은 옵션 이 있었으면 좋겠다. TRUE로 설정하면 선택을 "반전"합니다. 즉 , 목록의 열을 제외한 모든 열을 유지 select합니다.
Prasad Chalasani

4
@prasad, 아래 @joris 답변을 참조하십시오. 하위 집합 기준이없는 하위 집합은 약간 과잉입니다. 단순히 시도 :df[c("a", "c")]
JD 롱에게

@JD 나는의 구문 편리 같은 것을 알았지 만 subset난 그냥 이름을 인용 방지하기 위해 몇 가지 추가 문자를 입력 상관없는 것 같아요 :) - 당신이 열 이름 주위에 따옴표를 넣을 필요가 없습니다 명령
Prasad Chalasani

11
subset다른 기능 안에서는 사용하지 마십시오 .
Ari B. Friedman


196
within(df, rm(x))

아마도 가장 쉬운 방법이거나 여러 변수가있는 경우 :

within(df, rm(x, y))

또는 data.tables를 다루는 경우 ( 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")]

26
within(df, rm(x))입니다 지금까지 가장 깨끗한 솔루션입니다. 이것이 가능한 가능성을 감안할 때, 다른 모든 대답은 불필요하게 복잡하게 보입니다.
Miles Erickson

2
참고 within(df, rm(x))없는 이름이 중복 된 열이있는 경우 작업 xdf.
MichaelChirico

2
@MichaelChirico는 명확히하기 위해 아무것도 제거하지 않지만 데이터 값을 변경하는 것으로 보입니다. 이 경우 더 큰 문제가 있지만 여기에 예제가 있습니다 : df <- data.frame(x = 1, y = 2); names(df) <- c("x", "x"); within(df, rm(x))returns data.frame(x = 2, x = 2).
Max Ghenis

1
@MilesErickson 문제는 within()강력하지만 NSE를 사용 하는 기능에 의존한다는 것 입니다. 도움말 페이지의 메모에는 프로그래밍을 위해 충분한주의를 기울여야한다고 명시되어 있습니다.
Joris Meys

@MilesErickson 중복 된 이름을 가진 데이터 프레임이 얼마나 자주 발생합니까?
HSchmale

115

다음 %in%과 같이 사용할 수 있습니다 .

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

1
내가 뭔가를 놓치고 있습니까, 아니면 효과적으로 Joris의 답의 첫 부분과 같은 해결책입니까? DF[ , !(names(DF) %in% drops)]
Daniel Fletcher

9
@DanielFletcher : 동일합니다. 답변의 타임 스탬프를보십시오. 우리는 동시에 ... 5 년 전에 대답했습니다. :)
Joshua Ulrich

5
멋진. identical(post_time_1, post_time_2) [1] TRUE = D
Daniel Fletcher

54

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"

1
훌륭한! 이것은 자연스럽게 방식으로 NULL 할당을 단일 열로 확장하고 (겉보기) 복사를 피합니다 (후드에서 어떤 일이 발생하는지 알지 못하므로 메모리 사용에서 더 효율적이지 않을 수는 있지만 명확하게 보입니다 ... 문법적으로 더 효율적입니다.)
c-urchin

6
list (NULL)가 필요하지 않으며 NULL이면 충분합니다. 예 : dat [, 4] = NULL
CousinCocaine

8
OP의 질문은 여러 열을 삭제하는 방법이었습니다. dat [, 4 : 5] <-NULL이 작동하지 않습니다. 그것은 list (NULL)가 들어오는 곳입니다. 하나 이상의 열에서 작동합니다.
Vincent

중복 된 열 이름을 제거하려고 할 때도 작동하지 않습니다.
MichaelChirico

@MichaelChirico 저에게 잘 작동합니다. 동일한 이름을 가진 첫 번째 열을 제거하거나 제거하려는 각 열에 대한 색인을 제공하려면 레이블을 지정하십시오. 작동하지 않는 예제가 있다면 관심을 가질 것입니다. 아마도 새로운 질문으로 게시 하시겠습니까?
Vincent

42

참조로 열을 제거하고 연관된 내부 복사를 피 data.frames하려면 data.table패키지와 함수를 사용할 수 있습니다:=

문자형 벡터 이름을 :=연산자 의 왼쪽 과 NULLRHS로 전달할 수 있습니다 .

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)

41

grep ()이 숫자 형 벡터를 반환한다는 사실을 기반으로 잠재적으로 더 강력한 전략이 있습니다. 내 데이터 세트 중 하나에서와 같이 긴 변수 목록이있는 경우 ".A"로 끝나는 일부 변수와 ".B"로 끝나는 일부 변수는 ".A"로 끝나는 변수 만 원합니다. 패턴과 일치하지 않는 모든 변수를 사용하여 다음을 수행하십시오.

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

이 경우 Joris Meys 예제를 사용하면 컴팩트하지는 않지만 다음과 같습니다.

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

1
drops처음에로 정의하면 다음 과 같이 paste0("^", drop_cols, "$")훨씬 더 좋아집니다 (읽기 : 더 작음) sapply.DF[ , -sapply(drops, grep, names(DF))]
MichaelChirico

30

또 다른 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

1
또는 정규 표현식을 허용하는와 select()같은 다른 모든 기회를 잊지 마십시오 . contains()matches()
ha_pu 2016 년

23

또 다른 가능성 :

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

또는

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

2
setdiff열 수가 매우 많은 경우에 사용하는 것이 최적 이기 때문에 이것이 더 많이지지되지 않는다는 것이 너무 나쁩니다 .
ctbrown

이것에 대한 또 다른 각도 :df <- df[ , -which(grepl('a|c', names(df)))]
Joe

23
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

23

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


22

흥미롭게도 이것은 R의 이상한 다중 구문 불일치 중 하나를 표시합니다. 예를 들어 2 열 데이터 프레임이 제공된 경우 :

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

이것은 데이터 프레임을 제공합니다

subset(df, select=-y)

그러나 이것은 벡터를 제공합니다

df[,-2]

이것은 모두 설명되어 ?[있지만 정확하게 예상되는 동작은 아닙니다. 글쎄, 적어도 나에게는 ...


18

여기 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)
Marek

1
를 사용하여 삭제할 열 목록이 긴 경우 열을 dplyr그룹화하고 하나의 빼기 df.cut <- df %>% select(-c(col.to.drop.1, col.to.drop.2, ..., col.to.drop.n))
만하

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

4
경기를 부정하는 것은 좋은 생각이 아닙니다df[,-match(c("e","f"),names(df))]
hadley

. @ JDLong-열 이름으로 시작하는 열을 삭제하려면 어떻게해야 -합니까?
Chetan Arvind Patil

12

dropNamed()Bernd Bischl의 BBmisc패키지에는 정확히 이것을 수행 하는 함수가 있습니다 .

BBmisc::dropNamed(df, "x")

장점은 데이터 프레임 인수를 반복하지 않으므로 magrittr( dplyr접근 방식 과 마찬가지로) 배관에 적합하다는 것입니다 .

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

9

위의 @hadley를 사용하지 않으려는 경우 다른 해결책 : "COLUMN_NAME"이 삭제하려는 열의 이름 인 경우 :

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

1
(1) 문제는 한 번에 여러 열을 삭제하는 것입니다. (2) 안에 있지 않으면 작동 COLUMN_NAME하지 않습니다 df(자체 확인 :) df<-data.frame(a=1,b=2). (3) df[,names(df) != "COLUMN_NAME"]더 간단하고 고통받지 않습니다. (2)
Marek

이 답변에 대한 추가 정보를 줄 수 있습니까?
Akash Nayak

8

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'))

4

제거 할 데이터 프레임쉼표로 구분 된 문자열을 제공 하십시오.

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")

여기에 이미지 설명을 입력하십시오


1

을 사용하여 삭제하려는 열의 색인을 찾으십시오 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

1

data.frame메모리가 크 거나 부족한 경우 사용하십시오 [ . . . . 또는 rmwithin 하기 (A)의 열을 제거하는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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.