346 votes

Comment faire pour supprimer des colonnes par leur nom dans une trame de données

J’ai un jeu de données volumineux et j’aimerais lire des colonnes spécifiques ou de laisser tomber tous les autres.

Je sélectionne les colonnes que je ne suis pas intéressé par :

et que je voudrais faire quelque chose comme :

pour supprimer toutes les colonnes non désirés. Est-ce la solution optimale ?

439voto

juba Points 15701

Vous devez utiliser l'indexation ou l' subset fonction. Par exemple :

R> df <- data.frame(x=1:5, y=2:6, z=3:7, u=4:8)
R> df
  x y z u
1 1 2 3 4
2 2 3 4 5
3 3 4 5 6
4 4 5 6 7
5 5 6 7 8

Ensuite, vous pouvez utiliser l' which de la fonction et de l' - de l'opérateur dans la colonne d'indexation :

R> df[ , -which(names(df) %in% c("z","u"))]
  x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6

Ou, beaucoup plus simple, l'utilisation de l' select argument de l' subset fonction : vous pouvez ensuite utiliser l' - opérateur directement sur un vecteur de noms de colonnes, et vous pouvez omettre les guillemets autour des noms de !

R> subset(df, select=-c(z,u))
  x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6

Notez que vous pouvez également sélectionner les colonnes que vous voulez, au lieu de les laisser tomber les autres :

R> df[ , c("x","y")]
  x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6

R> subset(df, select=c(x,y))
  x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6

133voto

Ista Points 3100

Ne pas utiliser `` pour cela, il est extrêmement dangereux. Tenir compte :

Utilisez plutôt le sous-ensemble ou le `` fonction :

J’ai appris cela de douloureuse expérience. N’abusez pas `` !

52voto

Antoine Lizée Points 662

D'abord, vous pouvez utiliser l'indexation directe (avec des vecteurs de booléens), au lieu de ré-accéder à des noms de colonne si vous travaillez avec le même bloc de données; il sera plus en sécurité comme l'a souligné l'Ista, et plus rapide à écrire et à exécuter. Donc, ce que vous aurez seulement besoin de:

var.out.bool <- !names(data) %in% c("iden", "name", "x_serv", "m_serv")

et puis, il suffit de réaffecter des données:

data <- data[,var.out.bool] # or...
data <- data[,var.out.bool, drop = FALSE] # You will need this option to avoid the conversion to an atomic vector if there is only one column left

La seconde, plus rapide à écrire, vous pouvez affecter directement la valeur NULL pour les colonnes que vous souhaitez supprimer:

data[c("iden", "name", "x_serv", "m_serv")] <- list(NULL) # You need list() to respect the target structure.

Enfin, vous pouvez utiliser le sous-ensemble(), mais il ne peut pas vraiment être utilisé dans le code (même le fichier d'aide avertit à ce sujet). Plus précisément, un problème pour moi est que si vous voulez utiliser directement le drop fonctionnalité de susbset (), vous devrez l'écrire sans guillemets l'expression correspondant à la colonne des noms:

subset( data, select = -c("iden", "name", "x_serv", "m_serv") ) # WILL NOT WORK
subset( data, select = -c(iden, name, x_serv, m_serv) ) # WILL

En bonus, voici le petit benchmark des différentes options, qui montre clairement que le sous-ensemble est le plus lent, et que le premier, redéploiement de la méthode la plus rapide:

                                        re_assign(dtest, drop_vec)  46.719  52.5655  54.6460  59.0400  1347.331
                                      null_assign(dtest, drop_vec)  74.593  83.0585  86.2025  94.0035  1476.150
               subset(dtest, select = !names(dtest) %in% drop_vec) 106.280 115.4810 120.3435 131.4665 65133.780
 subset(dtest, select = names(dtest)[!names(dtest) %in% drop_vec]) 108.611 119.4830 124.0865 135.4270  1599.577
                                  subset(dtest, select = -c(x, y)) 102.026 111.2680 115.7035 126.2320  1484.174

Microbench graph

Le Code est ci-dessous :

dtest <- data.frame(x=1:5, y=2:6, z = 3:7)
drop_vec <- c("x", "y")

null_assign <- function(df, names) {
  df[names] <- list(NULL)
  df
}

re_assign <- function(df, drop) {
  df <- df [, ! names(df) %in% drop, drop = FALSE]
  df
}

res <- microbenchmark(
  re_assign(dtest,drop_vec),
  null_assign(dtest,drop_vec),
  subset(dtest, select = ! names(dtest) %in% drop_vec),
  subset(dtest, select = names(dtest)[! names(dtest) %in% drop_vec]),
  subset(dtest, select = -c(x, y) ),
times=5000)

plt <- ggplot2::qplot(y=time, data=res[res$time < 1000000,], colour=expr)
plt <- plt + ggplot2::scale_y_log10() + 
  ggplot2::labs(colour = "expression") + 
  ggplot2::scale_color_discrete(labels = c("re_assign", "null_assign", "subset_bool", "subset_names", "subset_drop")) +
  ggplot2::theme_bw(base_size=16)
print(plt)

7voto

Mark Miller Points 3193

J'ai essayé de supprimer une colonne en utilisant le package data.table et j'ai obtenu un résultat inattendu. Je pense en quelque sorte que ce qui suit pourrait être utile. Juste un petit avertissement.

[Edité par Matthew ...]

 DF = read.table(text = "
     fruit state grade y1980 y1990 y2000
     apples Ohio   aa    500   100   55
     apples Ohio   bb      0     0   44
     apples Ohio   cc    700     0   33
     apples Ohio   dd    300    50   66
", sep = "", header = TRUE, stringsAsFactors = FALSE)

DF[ , !names(DF) %in% c("grade")]   # all columns other than 'grade'
   fruit state y1980 y1990 y2000
1 apples  Ohio   500   100    55
2 apples  Ohio     0     0    44
3 apples  Ohio   700     0    33
4 apples  Ohio   300    50    66

library('data.table')
DT = as.data.table(DF)

DT[ , !names(dat4) %in% c("grade")]    # not expected !! not the same as DF !!
[1]  TRUE  TRUE FALSE  TRUE  TRUE  TRUE

DT[ , !names(DT) %in% c("grade"), with=FALSE]    # that's better
    fruit state y1980 y1990 y2000
1: apples  Ohio   500   100    55
2: apples  Ohio     0     0    44
3: apples  Ohio   700     0    33
4: apples  Ohio   300    50    66
 

Fondamentalement, la syntaxe pour data.table n'est PAS exactement la même que data.frame . Il y a en fait beaucoup de différences, voir FAQ 1.1 et FAQ 2.17. Tu étais prévenu!

3voto

leroux Points 253

J'ai changé le code pour:

 # read data
dat<-read.dta("file.dta")

# vars to delete
var.in<-c("iden", "name", "x_serv", "m_serv")

# what I'm keeping
var.out<-setdiff(names(dat),var.in)

# keep only the ones I want       
dat <- dat[var.out]
 

n'avait pas pensé à ça!

de toute façon, la réponse de juba est la meilleure solution à mon problème!

merci à tous pour votre aide!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X