Wie löscht man eine Spalte nach Namen in data.table?

194

Um eine Spalte mit dem Namen "foo" in a loszuwerden data.frame, kann ich Folgendes tun:

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

Sobald dfes jedoch in ein data.tableObjekt konvertiert wurde , gibt es keine Möglichkeit, nur eine Spalte zu entfernen.

Beispiel:

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

Sobald es jedoch in ein data.tableObjekt konvertiert wurde, funktioniert dies nicht mehr.

Maiasaura
quelle
2
Es wäre klarer gewesen, die data.table dtzu benennen, anstatt df3...
PatrickT

Antworten:

283

Mit einer der folgenden fooOptionen wird die Spalte aus der Datentabelle entfernt 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 unterstützt auch die folgende Syntax:

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

obwohl , wenn Sie es fehlte eigentlich Spalte zu entfernen , "foo"aus df3(im Gegensatz zu nur einen Blick auf den Druck df3minus Spalte "foo") Sie wirklich verwenden Methode 1 stattdessen wollen würde.

(Beachten Sie, dass Sie, wenn Sie eine Methode verwenden, die auf grep()oder grepl()basiert, festlegen müssen, pattern="^foo$"anstatt "foo", dass Spalten mit Namen wie "fool"und "buffoon"(dh solche, die fooals Teilzeichenfolge enthalten) ebenfalls abgeglichen und entfernt werden sollen.)

Weniger sichere Optionen, gut für den interaktiven Gebrauch:

Die nächsten beiden Redewendungen funktionieren ebenfalls - wenn sie df3eine Spaltenübereinstimmung enthalten"foo" -, schlagen jedoch auf wahrscheinlich unerwartete Weise fehl, wenn dies nicht der Fall ist. Wenn Sie beispielsweise eine davon verwenden, um nach der nicht vorhandenen Spalte zu suchen "bar", erhalten Sie eine Datentabelle mit null Zeilen.

Infolgedessen eignen sie sich am besten für die interaktive Verwendung, bei der beispielsweise eine Datentabelle ohne Spalten mit Namen angezeigt werden soll, die den Teilstring enthalten "foo". Für Programmierzwecke (oder wenn Sie die Spalte (n) tatsächlich df3aus einer Kopie entfernen möchten, anstatt aus einer Kopie davon) sind die Methoden 1, 2a und 2b wirklich die besten Optionen.

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

Schließlich gibt es Ansätze with=FALSE, data.tabledie dieses Argument verwenden , sich jedoch allmählich von der Verwendung dieses Arguments entfernen, sodass jetzt davon abgeraten wird, wo Sie es vermeiden können. Hier anzeigen, damit Sie wissen, dass die Option vorhanden ist, falls Sie sie wirklich benötigen:

# 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
quelle
2
Siehe meinen Kommentar zum OP bezüglich -grepversus !grepl.
Joshua Ulrich
1
@ JoshuaUlrich - Guter Punkt. Ich grepl()habe es ursprünglich versucht und es hat nicht funktioniert, da data.table-Spalten nicht durch einen logischen Vektor indiziert werden können. Aber jetzt ist mir klar, dass grepl()dies durch Umbrechen zum Funktionieren gebracht werden kann which(), sodass ein ganzzahliger Vektor zurückgegeben wird.
Josh O'Brien
1
Ich wusste nicht, wie man mit indiziert data.table, aber es whichist klug, es einzuwickeln!
Joshua Ulrich
6
Das wusste ich auch nicht data.table; FR # 1797 hinzugefügt . Methode 1 ist jedoch (fast) unendlich schneller als die anderen. Methode 1 entfernt die Spalte als Referenz ohne Kopie. Ich bezweifle, dass Sie es für Daten jeder Größe über 0,005 Sekunden erhalten. Im Gegensatz dazu funktionieren die anderen möglicherweise überhaupt nicht, wenn sich die Tabelle in der Nähe von 50% des Arbeitsspeichers befindet, da sie alle außer der zu löschenden kopieren.
Matt Dowle
1
@ user3969377 Wenn Sie eine Spalte basierend auf dem Inhalt einer Zeichenvariablen entfernen möchten, setzen Sie sie einfach in Klammern. Dh. df [, (afoo): = NULL]
Dean MacGregor
31

Sie können dies auch verwenden, setum den Overhead von [.data.tablein-Schleifen zu vermeiden :

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

Wenn Sie es nach Spaltennamen tun möchten, which(colnames(dt) %in% c("a","c","e"))sollte für funktionieren j.

Ari B. Friedman
quelle
2
In data.table1.11.8, wenn Sie es nach Spaltennamen tun möchten, können Sie direkt rm.col = c("a","b")unddt[, (rm.col):=NULL]
Duccio A
20

Ich mache es einfach im Datenrahmen:

DT$col = NULL

Funktioniert schnell und verursacht, soweit ich sehen konnte, keine Probleme.

UPDATE: Nicht die beste Methode, wenn Ihr DT sehr groß ist, da die Verwendung des $<-Operators zum Kopieren von Objekten führt. Also besser nutzen:

DT[, col:=NULL]
msp
quelle
8

Sehr einfache Option für den Fall, dass Sie viele einzelne Spalten in einer Datentabelle löschen müssen und nicht alle Spaltennamen #careadviced eingeben möchten

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

Dadurch werden stattdessen Spalten basierend auf der Spaltennummer entfernt.

Es ist offensichtlich nicht so effizient, weil es die Vorteile von data.table umgeht, aber wenn Sie mit weniger als 500.000 Zeilen arbeiten, funktioniert es einwandfrei

SJDS
quelle
4

Angenommen , Ihre dt Spalten hat col1, col2, col3, col4, col5, coln.

So löschen Sie eine Teilmenge davon:

vx <- as.character(bquote(c(col1, col2, col3, coln)))[-1]
DT[, paste0(vx):=NULL]
Ricardo Paixao
quelle
Dies sollte ein Kommentar sein
Sachila Ranawaka
-2

Hier ist eine Möglichkeit, wenn Sie eine Anzahl von Spalten auf NULL setzen möchten, da deren Spaltennamen eine Funktion für Ihre Verwendung sind :)

deleteColsFromDataTable <- function (train, toDeleteColNames) {

       for (myNm in toDeleteColNames)

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

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

Wenn Sie für eine data.table die Spalte NULL zuweisen, wird sie entfernt:

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

... was entspricht:

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

Das Äquivalent für einen data.frame lautet:

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

F. Warum enthält die Version für data.table ein Komma und in der Version für data.frame kein Komma?

A. Da data.frames als Liste von Spalten gespeichert werden, können Sie das Komma überspringen. Sie können es auch hinzufügen, aber dann müssen Sie sie einer Liste von NULLs , DF[, c("col1", "col2", "col3")] <- list(NULL).

Contango
quelle
@Arun Ich kann mir keine Situation vorstellen, data.framesin der die Zeilen und Spalten gewechselt würden. Das wäre unlogisch.
duHaas
@Arun Ich habe dich markiert, weil dein erster Kommentar den Anschein erweckte, als gäbe es Zeiten, in denen du anrufen könntest. DF[column,row]Ich wollte nur sehen, ob es tatsächlich Fälle gibt, in denen dies passiert ist.
duHaas
Die Antwort wurde aktualisiert, um einen Tippfehler zu entfernen.
Contango