Comment supprimer une colonne par nom dans data.table?

195

Pour se débarrasser d'une colonne nommée "foo" dans un data.frame, je peux faire:

df <- df[-grep('foo', colnames(df))]

Cependant, une fois dfconverti en data.tableobjet, il n'y a aucun moyen de supprimer simplement une colonne.

Exemple:

df <- data.frame(id = 1:100, foo = rnorm(100))
df2 <- df[-grep('foo', colnames(df))] # works
df3 <- data.table(df)
df3[-grep('foo', colnames(df3))] 

Mais une fois converti en data.tableobjet, cela ne fonctionne plus.

Maiasaura
la source
2
Il aurait été plus clair de nommer le data.table dtau lieu de df3...
PatrickT

Réponses:

283

L'un des éléments suivants supprimera la colonne foodu tableau de données df3:

# Method 1 (and preferred as it takes 0.00s even on a 20GB data.table)
df3[,foo:=NULL]

df3[, c("foo","bar"):=NULL]  # remove two columns

myVar = "foo"
df3[, (myVar):=NULL]   # lookup myVar contents

# Method 2a -- A safe idiom for excluding (possibly multiple)
# columns matching a regex
df3[, grep("^foo$", colnames(df3)):=NULL]

# Method 2b -- An alternative to 2a, also "safe" in the sense described below
df3[, which(grepl("^foo$", colnames(df3))):=NULL]

data.table prend également en charge la syntaxe suivante:

## Method 3 (could then assign to df3, 
df3[, !"foo"]  

mais si vous vouliez réellement supprimer la colonne "foo"de df3(au lieu d'imprimer simplement une vue de la df3colonne moins "foo"), vous voudriez vraiment utiliser la méthode 1 à la place.

(Notez que si vous utilisez une méthode reposant sur grep()ou grepl(), vous devez définir pattern="^foo$"plutôt que "foo", si vous ne voulez pas que les colonnes avec des noms comme "fool"et "buffoon"(c'est-à-dire celles contenant foocomme sous-chaîne) soient également mises en correspondance et supprimées.)

Options moins sûres, bien pour une utilisation interactive:

Les deux idiomes suivants fonctionneront également - s'ils df3contiennent une correspondance de colonne"foo" - mais échoueront d'une manière probablement inattendue si ce n'est pas le cas. Si, par exemple, vous utilisez l'un d'eux pour rechercher la colonne inexistante "bar", vous vous retrouverez avec un data.table à zéro ligne.

En conséquence, ils sont vraiment les mieux adaptés à une utilisation interactive où l'on peut, par exemple, vouloir afficher une table de données moins toutes les colonnes avec des noms contenant la sous-chaîne "foo". À des fins de programmation (ou si vous souhaitez réellement supprimer les colonnes df3plutôt que d'en copier), les méthodes 1, 2a et 2b sont vraiment les meilleures options.

# Method 4:
df3[, .SD, .SDcols = !patterns("^foo$")]

Enfin, certaines approches sont utilisées with=FALSE, mais data.tables'éloignent progressivement de cet argument, il est donc déconseillé de les éviter; montrant ici afin que vous sachiez que l'option existe au cas où vous en auriez vraiment besoin:

# Method 5a (like Method 3)
df3[, !"foo", with=FALSE] 
# Method 5b (like Method 4)
df3[, !grep("^foo$", names(df3)), with=FALSE]
# Method 5b (another like Method 4)
df3[, !grepl("^foo$", names(df3)), with=FALSE]
Josh O'Brien
la source
2
Voir mon commentaire au PO concernant -grepversus !grepl.
Joshua Ulrich
1
@JoshuaUlrich - Bon point. J'ai essayé au grepl()début et cela n'a pas fonctionné, car les colonnes data.table ne peuvent pas être indexées par un vecteur logique. Mais je me rends compte maintenant que cela grepl()peut être fait fonctionner en l'enveloppant avec which(), de sorte qu'il retourne un vecteur entier.
Josh O'Brien
1
Je ne savais pas cela sur l'indexation avec data.table, mais l'envelopper whichest intelligent!
Joshua Ulrich
6
Je ne le savais pas non data.tableplus; ajouté FR # 1797 . Mais, la méthode 1 est (presque) infiniment plus rapide que les autres. La méthode 1 supprime la colonne par référence sans aucune copie. Je doute que vous l'obteniez au-dessus de 0,005 secondes pour n'importe quelle taille data.table. En revanche, les autres peuvent ne pas fonctionner du tout si la table est proche de 50% de RAM car ils copient tout sauf celui à supprimer.
Matt Dowle
1
@ user3969377 si vous souhaitez supprimer une colonne basée sur le contenu d'une variable de caractère, vous devez simplement la mettre entre parenthèses. C'est à dire. df [, (afoo): = NULL]
Dean MacGregor
31

Vous pouvez également utiliser setpour cela, ce qui évite la surcharge des [.data.tableboucles in:

dt <- data.table( a=letters, b=LETTERS, c=seq(26), d=letters, e=letters )
set( dt, j=c(1L,3L,5L), value=NULL )
> dt[1:5]
   b d
1: A a
2: B b
3: C c
4: D d
5: E e

Si vous voulez le faire par nom de colonne, which(colnames(dt) %in% c("a","c","e"))devrait fonctionner pour j.

Ari B. Friedman
la source
2
En data.table1.11.8, si vous voulez le faire par nom de colonne, vous pouvez le faire directement rm.col = c("a","b")etdt[, (rm.col):=NULL]
Duccio A
20

Je le fais simplement dans le cadre de données:

DT$col = NULL

Fonctionne rapidement et autant que je puisse voir ne pose aucun problème.

MISE À JOUR: pas la meilleure méthode si votre DT est très grand, car l'utilisation de l' $<-opérateur entraînera la copie d'objet. Donc mieux utiliser:

DT[, col:=NULL]
msp
la source
8

Option très simple dans le cas où vous avez plusieurs colonnes individuelles à supprimer dans un tableau de données et que vous souhaitez éviter de taper tous les noms de colonnes #careadviced

dt <- dt[, -c(1,4,6,17,83,104)]

Cela supprimera à la place les colonnes basées sur le numéro de colonne.

Ce n'est évidemment pas aussi efficace car il contourne les avantages de data.table mais si vous travaillez avec moins de 500 000 lignes, cela fonctionne bien

SJDS
la source
4

Supposons que votre dt comporte des colonnes col1, col2, col3, col4, col5, coln.

Pour en supprimer un sous-ensemble:

vx <- as.character(bquote(c(col1, col2, col3, coln)))[-1]
DT[, paste0(vx):=NULL]
Ricardo Paixao
la source
cela devrait être un commentaire
Sachila Ranawaka
-2

Voici un moyen lorsque vous souhaitez définir un nombre de colonnes sur NULL, étant donné que leurs noms de colonne ont une fonction pour votre usage :)

deleteColsFromDataTable <- function (train, toDeleteColNames) {

       for (myNm in toDeleteColNames)

       train <- train [,(myNm):=NULL]

       return (train)
}
user3531326
la source
-3
DT[,c:=NULL] # remove column c
Durga Gaddam
la source
-7

Pour un data.table, l'attribution de la colonne à NULL la supprime:

DT[,c("col1", "col1", "col2", "col2")] <- NULL
^
|---- Notice the extra comma if DT is a data.table

... ce qui équivaut à:

DT$col1 <- NULL
DT$col2 <- NULL
DT$col3 <- NULL
DT$col4 <- NULL

L'équivalent pour un data.frame est:

DF[c("col1", "col1", "col2", "col2")] <- NULL
      ^
      |---- Notice the missing comma if DF is a data.frame

Q. Pourquoi y a-t-il une virgule dans la version de data.table et aucune virgule dans la version de data.frame?

A. Comme les data.frames sont stockés sous forme de liste de colonnes, vous pouvez ignorer la virgule. Vous pouvez également l' ajouter dans, mais vous devrez les affecter à une liste de NULLs, DF[, c("col1", "col2", "col3")] <- list(NULL).

Contango
la source
@Arun Je ne peux penser à aucune situation data.framesoù la ligne et les colonnes seraient commutées. Ce serait illogique.
duHaas
@Arun Je vous ai tagué parce que votre premier commentaire donnait l'impression qu'il y avait des moments où vous pouviez appeler, DF[column,row]donc je voulais juste voir s'il y avait effectivement des cas où cela s'était produit.
duHaas
Mise à jour de la réponse pour supprimer une faute de frappe.
Contango du