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.
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
.
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))
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")]
vous pouvez utiliser %in%
comme ceci:
df[, !(colnames(df) %in% c("x","bar","foo"))]
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"
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)
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) )]
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...
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
une autre possibilité:
df <- df[, setdiff(names(df), c("a", "c"))]
ou
df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
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
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.
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
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")
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
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")]
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
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")
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