web-dev-qa-db-fra.com

Supprimer les colonnes du cadre de données par nom

J'ai un certain nombre de colonnes que je voudrais supprimer d'un bloc de données. Je sais que nous pouvons les supprimer individuellement en utilisant quelque chose comme:

df$x <- NULL

Mais j'espérais faire cela avec moins de commandes.

De plus, je sais que je pourrais supprimer des colonnes en utilisant l'indexation d'entiers comme ceci:

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

Mais je crains que la position relative de mes variables ne change.

Compte tenu de la puissance de R, je me suis dit qu'il pourrait y avoir un meilleur moyen que de supprimer chaque colonne une par une.

782
Btibert3

Vous pouvez utiliser une simple liste de noms:

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

Ou bien, vous pouvez également dresser une liste de ceux à conserver et les nommer:

keeps <- c("y", "a")
DF[keeps]

EDIT: Pour ceux qui ne connaissent pas encore l'argument drop de la fonction d'indexation, si vous souhaitez conserver une colonne en tant que cadre de données, vous devez:

keeps <- "y"
DF[ , keeps, drop = FALSE]

drop=TRUE (ou ne pas le mentionner) supprime les dimensions inutiles et renvoie donc un vecteur avec les valeurs de la colonne y.

829
Joris Meys

Il y a aussi la commande subset, utile si vous savez quelles colonnes vous voulez:

df <- data.frame(a = 1:10, b = 2:11, c = 3:12)
df <- subset(df, select = c(a, c))

MISE À JOUR après le commentaire de @hadley: Pour déposer colonnes a, c vous pourriez faire:

df <- subset(df, select = -c(a, c))
402
Prasad Chalasani
within(df, rm(x))

est probablement plus facile, ou pour plusieurs variables:

within(df, rm(x, y))

Ou si vous traitez avec data.tables (par Comment effacez-vous une colonne par son nom dans data.table? ):

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

dt[, !"x"]   # Selects all but x into a new data.table.

ou pour plusieurs variables

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

dt[, !c("x", "y")]
164
Max Ghenis

Vous pouvez utiliser %in% comme ceci:

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

list (NULL) fonctionne aussi:

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"
45
Vincent

Il existe une stratégie potentiellement plus puissante basée sur le fait que grep () renverra un vecteur numérique. Si vous avez une longue liste de variables comme dans l'un de mes ensembles de données, certaines variables se terminant par ".A" et d'autres par ".B" et vous ne voulez que celles qui se terminent par ".A" ( avec toutes les variables qui ne correspondent à aucun modèle, procédez comme suit:

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

Pour le cas d'espèce, en utilisant l'exemple de Joris Meys, il pourrait ne pas être aussi compact, mais ce serait:

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

Si vous souhaitez supprimer les colonnes par référence et éviter la copie interne associée à data.frames, vous pouvez utiliser le package data.table et la fonction :=.

Vous pouvez passer un nom de vecteur de caractère à gauche de l'opérateur := et à NULL en tant que 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]

Si vous souhaitez prédéfinir les noms en tant que vecteur de caractères en dehors de l'appel à [, indiquez le nom de l'objet dans () ou {} pour forcer l'évaluation du LHS dans l'étendue de l'appel. pas comme un nom dans le cadre de 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.   

Vous pouvez également utiliser set, ce qui évite les frais généraux de [.data.table, et fonctionne également pour 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)
37
mnel

Une autre réponse dplyr. Si vos variables ont une structure de dénomination commune, vous pouvez essayer starts_with(). Par exemple

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

Si vous souhaitez supprimer une séquence de variables dans le bloc de données, vous pouvez utiliser :. Par exemple, si vous voulez supprimer les variables var2, var3 et toutes, vous ne disposerez que de var1:

df2 <- df1 %>% select(-c(var2:var3) )  
df2
#        var1
#1 0.75879754
#2 0.31168919
#3 0.03983268
24
Pat W.
DF <- data.frame(
  x=1:10,
  y=10:1,
  z=rep(5,10),
  a=11:20
)
DF

Sortie:

    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)

Sortie:

        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
21
Kun Ren

Par intérêt, cela signale l’une des étranges incohérences multiples de la syntaxe de R. Par exemple, dans un cadre de données à deux colonnes:

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

Cela donne un cadre de données

subset(df, select=-y)

mais cela donne un vecteur

df[,-2]

Tout cela est expliqué dans ?[ mais ce n'est pas exactement le comportement attendu. Du moins pas à moi ...

20
jkeirstead

Une autre possibilité:

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

ou

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

Dplyr Solution

Je doute que cela suscite beaucoup d’attention ici, mais si vous avez une liste de colonnes que vous voulez supprimer et que vous voulez le faire dans une chaîne dplyr, j’utilise one_of() dans le select clause:

Voici un exemple simple et reproductible:

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

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

La documentation peut être trouvée en exécutant ?one_of ou ici:

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

18
User632716

Voici un dplyr façon de s'y prendre:

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

J'aime cela car il est intuitif à lire et à comprendre sans annotation et robuste aux colonnes qui changent de position dans le bloc de données. Il suit également l'idiome vectorisé en utilisant - pour supprimer des éléments.

17
c.gutierrez

Je continue de penser qu'il doit y avoir un meilleur langage, mais pour soustraire des colonnes par leur nom, j'ai tendance à faire ce qui suit:

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
13
JD Long

Il y a une fonction appelée dropNamed() dans le package BBmisc de Bernd Bischl qui fait exactement cela.

BBmisc::dropNamed(df, "x")

L'avantage est qu'il évite de répéter l'argument de la trame de données et qu'il convient donc à la tuyauterie dans magrittr (tout comme les approches dplyr):

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

Au-delà de select(-one_of(drop_col_names)) démontrée dans les réponses précédentes, il existe deux autres options dplyr permettant de supprimer des colonnes à l'aide de select() qui n'impliquent pas la définition de tous les noms de colonnes spécifiques (à l'aide des exemples de données dplyr starwars variété dans les noms de colonne):

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

Une autre solution si vous ne souhaitez pas utiliser les symboles de @ hadley ci-dessus: Si "COLUMN_NAME" est le nom de la colonne à supprimer:

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

Fournissez le bloc de données et une chaîne de noms séparés par des virgules à supprimer:

remove_features <- function(df, features) {
  rem_vec <- unlist(strsplit(features, ', '))
  res <- df[,!(names(df) %in% rem_vec)]
  return(res)
}

Utilisation :

remove_features(iris, "Sepal.Length, Petal.Width")

enter image description here

3
Cybernetic

Recherchez l'index des colonnes à supprimer à l'aide de which. Donnez à ces index un signe négatif (*-1). Ensuite, créez un sous-ensemble de ces valeurs, ce qui les supprimera du cadre de données. Ceci est un exemple.

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
milan