Come si elimina una colonna per nome in data.table?


196

Per sbarazzarsi di una colonna denominata "pippo" in a data.frame, posso fare:

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

Tuttavia, una volta dfconvertito in un data.tableoggetto, non è possibile rimuovere semplicemente una colonna.

Esempio:

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

Ma una volta convertito in un data.tableoggetto, questo non funziona più.


2
Sarebbe stato più chiaro nominare data.table dtinvece di df3...
PatrickT

Risposte:


284

Una delle seguenti foovoci rimuoverà la colonna da data.table 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 supporta anche la sintassi seguente:

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

anche se si fosse realmente vogliono per rimuovere colonna "foo"da df3(in contrasto con appena la stampa di una vista della df3colonna di meno "foo") che ci si vuole veramente utilizzare il metodo 1, invece.

(Si noti che se si utilizza un metodo basato su grep()o grepl(), è necessario impostare pattern="^foo$"piuttosto che "foo", se non si desidera che anche le colonne con nomi come "fool"e "buffoon"(cioè quelli che contengono foocome sottostringa) vengano abbinate e rimosse.)

Opzioni meno sicure, va bene per l'uso interattivo:

Anche i prossimi due modi di dire funzioneranno - se df3contiene una corrispondenza di colonna"foo" - ma in caso contrario falliranno in modo probabilmente inaspettato. Se, ad esempio, ne usi uno qualsiasi per cercare la colonna inesistente "bar", finirai con una data.table a riga zero.

Di conseguenza, sono davvero più adatti per un uso interattivo in cui si potrebbe, ad esempio, voler visualizzare un data.table meno tutte le colonne con nomi contenenti la sottostringa "foo". Ai fini della programmazione (o se si desidera rimuovere effettivamente le colonne df3piuttosto che da una sua copia), i metodi 1, 2a e 2b sono davvero le migliori opzioni.

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

Infine, ci sono approcci che utilizzano with=FALSE, anche se data.tablesi sta gradualmente allontanando dall'uso di questo argomento, quindi ora è scoraggiato dove è possibile evitarlo; mostrando qui in modo da sapere che esiste l'opzione nel caso in cui ne abbiate davvero bisogno:

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

2
Vedere il mio commento al riguardo OP -greprispetto !grepl.
Joshua Ulrich

1
@JoshuaUlrich - Buon punto. Ho provato grepl()inizialmente e non ha funzionato, poiché le colonne data.table non possono essere indicizzate da un vettore logico. Ma ora mi rendo conto che grepl()può essere fatto funzionare avvolgendolo con which(), in modo che restituisca un vettore intero.
Josh O'Brien,

1
Non lo sapevo sull'indicizzazione con data.table, ma avvolgerlo whichè intelligente!
Joshua Ulrich

6
Nemmeno io lo sapevo data.table; aggiunto FR # 1797 . Ma il metodo 1 è (quasi) infinitamente più veloce degli altri. Il metodo 1 rimuove la colonna per riferimento senza alcuna copia. Dubito che lo ottieni sopra 0,005 secondi per qualsiasi dimensione data.table. Al contrario, gli altri potrebbero non funzionare affatto se la tabella è vicina al 50% della RAM perché copiano tutto tranne quello da eliminare.
Matt Dowle,

1
@utente3969377 se si desidera rimuovere una colonna in base al contenuto di una variabile di carattere, è sufficiente racchiuderla tra parentesi. Vale a dire. df [, (afoo): = NULL]
Dean MacGregor,

31

Puoi anche usare setper questo, che evita il sovraccarico di [.data.tablein loop:

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

Se vuoi farlo con il nome della colonna, which(colnames(dt) %in% c("a","c","e"))dovrebbe funzionare per j.


2
In data.table1.11.8, se vuoi farlo per nome di colonna, puoi farlo direttamente rm.col = c("a","b")edt[, (rm.col):=NULL]
Duccio A

20

Lo faccio semplicemente nel modo di frame di dati:

DT$col = NULL

Funziona velocemente e per quanto ho potuto vedere non causa alcun problema.

AGGIORNAMENTO: non è il metodo migliore se il DT è molto grande, poiché l'utilizzo $<-dell'operatore porterà alla copia degli oggetti. Quindi un uso migliore:

DT[, col:=NULL]

8

Opzione molto semplice nel caso in cui ci siano molte colonne individuali da eliminare in una tabella di dati e si desidera evitare di digitare tutti i nomi di colonna #careadviced

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

Ciò rimuoverà invece le colonne in base al numero di colonna.

Ovviamente non è così efficiente perché ignora i vantaggi di data.table ma se lavori con meno di 500.000 righe funziona bene


4

Supponiamo che il vostro dt ha colonne col1, col2, col3, col4, col5, coln.

Per eliminare un sottoinsieme di essi:

vx <- as.character(bquote(c(col1, col2, col3, coln)))[-1]
DT[, paste0(vx):=NULL]

questo dovrebbe essere un commento
Sachila Ranawaka,

-2

Ecco un modo in cui vuoi impostare un numero di colonne su NULL dato che i loro nomi di colonna hanno una funzione per il tuo uso :)

deleteColsFromDataTable <- function (train, toDeleteColNames) {

       for (myNm in toDeleteColNames)

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

       return (train)
}


-7

Per un data.table, l'assegnazione della colonna a NULL la rimuove:

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

... che è l'equivalente di:

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

L'equivalente per un data.frame è:

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

D. Perché esiste una virgola nella versione per data.table e nessuna virgola nella versione per data.frame?

A. Dato che data.frames sono memorizzati come un elenco di colonne, puoi saltare la virgola. Si potrebbe anche aggiungere in, ma allora si avrà bisogno per assegnarli ad una lista di NULLs, DF[, c("col1", "col2", "col3")] <- list(NULL).


@Arun Non riesco a pensare a nessuna situazione in data.framescui la riga e le colonne sarebbero cambiate. Sarebbe illogico.
duHaas,

@Arun Ti ho taggato perché il tuo primo commento mi ha fatto sembrare che ci fossero momenti in cui potresti chiamare, DF[column,row]quindi volevo solo vedere se c'erano davvero dei casi in cui è successo.
duHaas,

Aggiornata la risposta per rimuovere un refuso.
Contango
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.