Drop colonnes de base de données par nom

j'ai un certain nombre de colonnes que je voudrais enlever 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 le faire avec moins de commandes.

aussi, je sais que je pourrais laisser tomber les colonnes en utilisant l'indexation entière comme ceci:

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

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

étant donné comment puissant R est, je me suis dit qu'il pourrait y avoir un meilleur moyen que de laisser tomber chaque colonne une par une.

688
demandé sur Henrik 2011-01-05 17:34:29

19 réponses

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, alternativement, vous pouvez faire une liste de ceux à conserver et les désigner par leur nom:

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

EDIT : Pour ceux qui ne connaissent pas encore l'argument drop de la fonction d'indexation, si vous voulez garder une colonne comme base de données, vous faites:

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

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

753
répondu Joris Meys 2016-02-26 20:57:39

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

mis à JOUR après le commentaire de @hadley: drop les colonnes a,c, vous pouvez faire:

df <- subset(df, select = -c(a, c))
369
répondu Prasad Chalasani 2018-04-08 01:02:57
within(df, rm(x))

est probablement le plus facile, ou pour plusieurs variables:

within(df, rm(x, y))

ou si vous avez affaire à data.table s (par Comment supprimer une colonne par nom dans les données.de la table? ):

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

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

ou pour variables multiples

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

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

dans la version de développement de data.table ( instructions d'installation ), with = FALSE n'est plus nécessaire:

dt[ , !"x"]
dt[ , !c("x", "y")]
124
répondu Max Ghenis 2017-05-23 12:18:26

vous pouvez utiliser %in% comme ceci:

df[, !(colnames(df) %in% c("x","bar","foo"))]
93
répondu Joshua Ulrich 2011-01-05 14:40:26

liste (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"
40
répondu Vincent 2016-04-13 20:24:24

si vous voulez supprimer les colonnes par référence et éviter la copie interne associée à data.frames alors vous pouvez utiliser le paquet data.table et la fonction :=

vous pouvez passer des noms de vecteurs de caractères au côté gauche de l'opérateur := , et NULL comme 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 voulez prédéfini les noms comme vecteur de caractères en dehors de l'appel à [ , envelopper le nom de l'objet dans () ou {} pour forcer le LHS à être évalué dans la portée de l'appel pas comme un nom dans le champ d'application 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)
36
répondu mnel 2014-05-21 01:17:06

il y a une stratégie potentiellement plus puissante basée sur le fait que grep() retournera un vecteur numérique. Si vous avez une longue liste de variables comme je le fais dans un de mes jeu de données, certaines variables qui se terminent par ".Un" et d'autres qui se terminent par ".B " et tu ne veux que ceux qui finissent par ".A" (avec toutes les variables qui ne correspondent pas à l'un ou l'autre modèle, faites ceci:

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

pour le cas présent, en utilisant L'exemple de Joris Meys, il pourrait ne pas être aussi compact, mais il serait:

DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]
35
répondu 42- 2014-07-24 16:45:59

par intérêt,ça signale une des étranges incohérences syntaxiques de R. Par exemple donné une base de données à deux colonnes:

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

cela donne une base de données

subset(df, select=-y)

mais cela donne un vecteur

df[,-2]

tout est expliqué dans ?[ mais ce n'est pas exactement le comportement attendu. Eh bien au moins pas pour moi...

19
répondu jkeirstead 2013-05-02 18:42:27

l'Autre dplyr réponse. Si vos variables ont une structure de nommage 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 voulez supprimer une séquence de variables dans la base de données, vous pouvez utiliser : . Par exemple, si vous vouliez laisser tomber var2 , var3 , et toutes les variables entre les deux, vous seriez simplement laissé avec var1 :

df2 <- df1 %>% select(-c(var2:var3) )  
df2
#        var1
#1 0.75879754
#2 0.31168919
#3 0.03983268
19
répondu Pat W. 2014-11-22 20:37:02

une autre possibilité:

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

ou

df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
18
répondu scentoni 2012-01-11 19:07:36
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
18
répondu Kun Ren 2017-02-12 07:37:32

Voici une dplyr façon de procéder:

#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 parce que c'est intuitif à lire et à comprendre sans annotation et robuste aux colonnes changeant la position dans le cadre de données. Il suit également l'idiome vectorisé en utilisant - pour supprimer des éléments.

16
répondu c.gutierrez 2017-08-23 19:16:00

je continue à penser qu'il doit y avoir un meilleur idiome, mais pour la soustraction des colonnes par le 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
10
répondu JD Long 2011-01-05 17:21:58

il y a une fonction appelée dropNamed() dans le paquet 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 base de données et est donc approprié pour la tuyauterie dans magrittr (tout comme le dplyr approches):

df %>% BBmisc::dropNamed("x")
10
répondu krlmlr 2014-12-04 14:06:22

Dplyr Solution

je doute que cela obtienne 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 la select clause:

voici un exemple simple et reproductible:

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

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

9
répondu User632716 2018-10-02 14:02:14

une autre solution si vous ne voulez pas utiliser @hadley's ci-dessus: si "COLUMN_NAME" est le nom de la colonne que vous voulez supprimer:

df[,-which(names(df) == "COLUMN_NAME")]
6
répondu Nick Keramaris 2016-10-25 22:57:20

au-Delà select(-one_of(drop_col_names)) démontré dans les réponses précédentes, il ya un couple d'autres dplyr options pour la suppression de colonnes à l'aide de select() qui n'impliquent pas la définition de tous les noms de colonne (à l'aide de la dplyr starwars données de l'échantillon pour un peu de 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 
2
répondu sbha 2018-07-03 02:11:25

fournit le data frame et une chaîne de noms séparés par des virgules pour 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

0
répondu Cybernetic 2018-06-15 16:51:02

trouvez l'index des colonnes que vous voulez supprimer en utilisant which . Donnez à ces index un signe négatif ( *-1 ). Puis sous-ensemble sur ces valeurs, qui les supprimera de la base de données. C'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
0
répondu milan 2018-08-17 11:42:03