2015-10-05 13 views
14

Chcę przekonwertować podzbiór kolejek data.table na nową klasę. Tu jest popularne pytanie (Convert column classes in data.table), ale odpowiedź tworzy nowy obiekt, a nie działa na obiekcie startowym.Konwertuj * niektóre * klasy kolumn w data.table

Weźmy ten przykład:

dat <- data.frame(ID=c(rep("A", 5), rep("B",5)), Quarter=c(1:5, 1:5), value=rnorm(10)) 
cols <- c('ID', 'Quarter') 

Jak najlepiej konwertować do bodaj cols kolumnach (np) czynnik? W normalnym data.frame można to zrobić:

dat[, cols] <- lapply(dat[, cols], factor) 

ale to nie działa na data.table, a nie robi tego

dat[, .SD := lapply(.SD, factor), .SDcols = cols] 

komentarz w połączonej pytanie Matt Dowle (od grudnia 2013) sugeruje następujące, co działa dobrze, ale wydaje się nieco mniej elegancki.

for (j in cols) set(dat, j = j, value = factor(dat[[j]])) 

Czy istnieje obecnie lepiej data.table odpowiedź (tj krótsza + nie generuje zmienną licznika), czy też po prostu użyć powyżej + rm(j)?

+0

wierzę metoda Matt Dowle zaleca byłoby najlepsze. W końcu jest autorem * data.table *. –

+1

To prawda, ale komentarz pochodził z 2013 roku i od tamtej pory było wiele aktualizacji pakietów, więc pomyślałem, że warto wyrzucić tę żyłkę. – arvi1000

+2

Więcej szczegółów na temat 'for (...) set (...)' idiom added ostatnio tutaj: http://stackoverflow.com/a/33000778/403310 –

Odpowiedz

26

Poza tym przy użyciu opcji jak sugeruje Matt Dowle, inny sposób zmiany klasy kolumn jest następujące:

dat[, (cols) := lapply(.SD, factor), .SDcols=cols] 

Używając := operator aktualizujesz datatable według referencji. Sprawdzenie, czy to działało:

> sapply(dat,class) 
     ID Quarter  value 
"factor" "factor" "numeric" 

Jak suggeted przez @MattDowle w komentarzach, można również użyć kombinacji for(...) set(...) następująco:

for (col in cols) set(dat, j = col, value = factor(dat[[col]])) 

które dadzą ten sam wynik. Trzecią alternatywą jest:

for (col in cols) dat[, (col) := factor(dat[[col]])] 

na mniejszą zbiorów danych, opcja for(...) set(...) jest około trzy razy szybciej niż opcja lapply (ale to naprawdę nie ma znaczenia, ponieważ jest to mały zbiór danych). W przypadku większych zestawów danych (na przykład 2 miliony wierszy) każde z tych podejść zajmuje mniej więcej tyle samo czasu. Do badania na większej zbiorze, użyłem:

dat <- data.table(ID=c(rep("A", 1e6), rep("B",1e6)), 
        Quarter=c(1:1e6, 1:1e6), 
        value=rnorm(10)) 

Czasami trzeba będzie zrobić to trochę inaczej (na przykład, gdy wartości liczbowe są przechowywane jako czynnik).Następnie trzeba użyć czegoś takiego:

dat[, (cols) := lapply(.SD, function(x) as.integer(as.character(x))), .SDcols=cols] 


UWAGA:Poniższe wyjaśnienie jest niedata.table -way robienia rzeczy. Dane nie są aktualizowane przez odniesienie, ponieważ kopia jest tworzona i przechowywana w pamięci (jak wskazano przez @Frank), co zwiększa wykorzystanie pamięci. Jest to raczej dodatek w celu wyjaśnienia działania with=FALSE.

Gdy chcesz zmienić klasach kolumnie w ten sam sposób, jak można zrobić z dataframe, trzeba dodać with = FALSE następująco:

dat[, cols] <- lapply(dat[, cols, with = FALSE], factor) 

Sprawdzenie czy to działało:

> sapply(dat,class) 
     ID Quarter  value 
"factor" "factor" "numeric" 

Jeśli nie dodasz with = FALSE, datatable oceni jako dat[, cols] jako wektor. Sprawdź różnicę w wydajności pomiędzy dat[, cols] i dat[, cols, with=FALSE]:

> dat[, cols] 
[1] "ID"  "Quarter" 

> dat[, cols, with=FALSE] 
    ID Quarter 
1: A  1 
2: A  2 
3: A  3 
4: A  4 
5: A  5 
6: B  1 
7: B  2 
8: B  3 
9: B  4 
10: B  5 
+1

Myślę, że nie chcesz używać '<-'. Jeśli uruchomię 'address()' przed i po nim, wygląda na to, że modyfikacja nie jest przez odniesienie (chociaż "[<-. Data.table" wydaje się pokrywać to użycie). – Frank

+1

@Frank Wiem, ale dodałem drugą część przede wszystkim, aby wyjaśnić, dlaczego potrzebujesz 'with = FALSE', gdy chcesz, aby datatable zwracał kolumny w taki sam sposób jak ramka danych. Dodałem ostrzeżenie. – Jaap

+0

Tak, wiem, jak działa 'with', ale to nie jest natywna metoda' data.table', jak zauważyłeś. Dzięki za główną odpowiedź: – arvi1000

1

Można użyć .SDcols:

dat[, cols] <- dat[, lapply(.SD, factor), .SDcols=cols]

+0

Jakiś powód, dla którego to dostaje spadki? Wygląda na to, że pytający szuka – Chris

+1

Tak samo jak mój komentarz do drugiej odpowiedzi. Jedną dużą zaletą korzystania z data.table jest modyfikacja przez odniesienie, ale o ile mogę powiedzieć, '[<-' z jednym nie wykorzystuje tego. – Frank

+0

@ Ludzie Chrisa tutaj biorą wytyczne "bez krótkich odpowiedzi" trochę zbyt poważnie. Chociaż prawie zawsze jest miejsce do rozszerzenia/objaśnienia. – shadowtalker

Powiązane problemy