Jak usunąć kolumnę według nazwy w data.table?

195

Aby pozbyć się kolumny o nazwie „foo” w data.frame, mogę:

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

Jednak po dfprzekonwertowaniu na data.tableobiekt nie ma sposobu, aby po prostu usunąć kolumnę.

Przykład:

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

Ale po przekształceniu w data.tableobiekt nie działa.

Maiasaura
źródło
2
Byłoby łatwiej nazwać tabelę data. dtzamiast df3...
PatrickT

Odpowiedzi:

283

Każda z poniższych czynności spowoduje usunięcie kolumny fooz tabeli 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 obsługuje również następującą składnię:

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

ale jeśli rzeczywiście chce usunąć kolumnę "foo"z df3(a nie tylko drukowanie widok df3minus kolumny "foo"), które tak naprawdę nie chcą korzystać z metody 1 zamiast.

(Pamiętaj, że jeśli używasz metody polegającej na grep()lub grepl(), musisz pattern="^foo$"raczej ustawić , niż "foo", jeśli nie chcesz, aby kolumny o nazwach takich jak "fool"i "buffoon"(tj. Zawierające foojako podłańcuch) również były dopasowywane i usuwane).

Mniej bezpieczne opcje, w porządku do użytku interaktywnego:

Kolejne dwa idiomy również będą działać - jeśli df3zawiera dopasowanie do kolumny"foo" - ale zakończy się niepowodzeniem w prawdopodobnie nieoczekiwany sposób, jeśli nie będzie. Jeśli, na przykład, użyjesz któregoś z nich do wyszukania nieistniejącej kolumny "bar", skończysz na zerowym wierszu data.table.

W rezultacie najlepiej nadają się do użytku interaktywnego, w którym można np. Wyświetlić tabelę data.tab pomniejszoną o kolumny zawierające nazwy zawierające podłańcuch "foo". Do celów programistycznych (lub jeśli chcesz faktycznie usunąć kolumny df3z kopii, a nie z jej kopii), Metody 1, 2a i 2b są naprawdę najlepszymi opcjami.

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

Wreszcie istnieją podejścia wykorzystujące with=FALSE, choć data.tablestopniowo odchodzi od używania tego argumentu, więc odradza się, gdzie można tego uniknąć; pokazując tutaj, abyś wiedział, że istnieje opcja na wypadek, gdybyś naprawdę jej potrzebował:

# 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
źródło
2
Zobacz mój komentarz do PO dotyczący -grepkontra !grepl.
Joshua Ulrich
1
@JoshuaUlrich - Dobra uwaga. Próbowałem grepl()początkowo i to nie zadziałało, ponieważ kolumn data.table nie można indeksować za pomocą wektora logicznego. Ale teraz zdaję sobie sprawę, że grepl()można sprawić, by działał, owijając go which()tak, aby zwracał wektor liczb całkowitych.
Josh O'Brien
1
Nie wiedziałem tego o indeksowaniu data.table, ale spakowanie go whichjest sprytne!
Joshua Ulrich
6
Nie wiedziałem też o tym data.table; dodano FR # 1797 . Ale metoda 1 jest (prawie) nieskończenie szybsza niż inne. Metoda 1 usuwa kolumnę przez odniesienie bez żadnej kopii. Wątpię, czy otrzymujesz go powyżej 0,005 sekundy dla dowolnej wielkości danych. Tabela. Z kolei inne mogą w ogóle nie działać, jeśli tabela zawiera prawie 50% pamięci RAM, ponieważ kopiują wszystkie oprócz tej do usunięcia.
Matt Dowle,
1
@ user3969377, jeśli chcesz usunąć kolumnę na podstawie zawartości zmiennej znakowej, po prostu zawiń ją w nawiasie. To znaczy. df [, (afoo): = NULL]
Dean MacGregor
31

Możesz również użyć setdo tego celu, co pozwala uniknąć narzutu [.data.tablew pętlach:

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

Jeśli chcesz to zrobić według nazwy kolumny, which(colnames(dt) %in% c("a","c","e"))powinno działać j.

Ari B. Friedman
źródło
2
W data.table1.11.8, jeśli chcesz to zrobić według nazwy kolumny, możesz to zrobić bezpośrednio rm.col = c("a","b")idt[, (rm.col):=NULL]
Duccio A
20

Po prostu robię to w sposób podobny do ramki danych:

DT$col = NULL

Działa szybko i o ile wiem, nie powoduje żadnych problemów.

AKTUALIZACJA: nie najlepsza metoda, jeśli ID jest bardzo duży, ponieważ użycie $<-operatora doprowadzi do kopiowania obiektów. Więc lepiej użyj:

DT[, col:=NULL]
msp
źródło
8

Bardzo prosta opcja, jeśli masz wiele pojedynczych kolumn do usunięcia w tabeli danych i chcesz uniknąć wpisywania wszystkich nazw kolumn #careadviced

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

Spowoduje to usunięcie kolumn opartych na numerze kolumny.

Oczywiście nie jest tak wydajny, ponieważ omija dane. Zalety tabeli, ale jeśli pracujesz z mniej niż powiedzmy 500 000 wierszy, działa dobrze

SJDS
źródło
4

Załóżmy, że dt ma kolumn col1, col2, col3, col4, col5, coln.

Aby usunąć ich podzbiór:

vx <- as.character(bquote(c(col1, col2, col3, coln)))[-1]
DT[, paste0(vx):=NULL]
Ricardo Paixao
źródło
powinien to być komentarz
Sachila Ranawaka
-2

Oto sposób, w jaki chcesz ustawić liczbę kolumn na NULL, biorąc pod uwagę, że nazwy ich kolumn mają funkcję do użytku :)

deleteColsFromDataTable <- function (train, toDeleteColNames) {

       for (myNm in toDeleteColNames)

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

       return (train)
}
użytkownik3531326
źródło
-3
DT[,c:=NULL] # remove column c
Durga Gaddam
źródło
-7

W przypadku data.table przypisanie kolumny do NULL powoduje jej usunięcie:

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

... co jest odpowiednikiem:

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

Odpowiednikiem dla data.frame jest:

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

P: Dlaczego w wersji dla data.table występuje przecinek, aw wersji dla data.frame nie ma przecinka?

A. Ponieważ ramki danych są przechowywane jako lista kolumn, możesz pominąć przecinek. Można również dodać je jednak wtedy trzeba będzie przypisać je do listy NULLs DF[, c("col1", "col2", "col3")] <- list(NULL).

Contango
źródło
@Arun Nie mogę wymyślić żadnej sytuacji, w data.framesktórej wiersz i kolumny byłyby przełączane. To byłoby nielogiczne.
duHaas
@Arun Oznaczyłem Cię tagiem, ponieważ twój pierwszy komentarz sprawiał wrażenie, jakby były chwile, w których możesz zadzwonić, DF[column,row]więc chciałem tylko sprawdzić, czy rzeczywiście są jakieś przypadki, w których to się wydarzyło.
duHaas
Zaktualizowano odpowiedź, aby usunąć literówkę.
Contango,