2012-03-25 15 views
343

Kiedy trzeba filtrować data.frame, czyli wyciąg wiersze, które spełniają określone warunki, wolę używać subset funkcję:Dlaczego jest `[` lepiej niż `podzbiór`?

subset(airquality, Month == 8 & Temp > 90) 

zamiast funkcji [:

airquality[airquality$Month == 8 & airquality$Temp > 90, ] 

Nie są dwa główne powody moich preferencji:

  1. Uważam, że kod brzmi lepiej, od lewej do prawej. Nawet ludzie, którzy nic nie wiedzą o R, mogą powiedzieć, co robi powyższe oświadczenie subset.

  2. Ponieważ kolumny można nazywać zmiennymi w wyrażeniu select, mogę zapisać kilka naciśnięć klawiszy. W powyższym przykładzie musiałem tylko raz wpisać airquality z subset, ale trzy razy z [.

Tak żyłem zadowolony, używając subset wszędzie, ponieważ jest krótsza i brzmi lepiej, nawet promując swoje piękno do moich kolegów programistów R. Ale wczoraj mój świat się rozpadł. Podczas czytania dokumentacji subset, zauważam ten rozdział:

Warning

This is a convenience function intended for use interactively. For programming it is better to use the standard subsetting functions like [, and in particular the non-standard evaluation of argument subset can have unanticipated consequences.

Może ktoś pomóc wyjaśnić, co autorzy na myśli?

Po pierwsze, co oznaczają "do użytku interaktywnego"? Wiem, czym jest sesja interaktywna, w przeciwieństwie do skryptu uruchamianego w trybie BATCH, ale nie widzę różnicy, jaką powinna ona mieć.

Następnie, proszę wyjaśnić "niestandardową ocenę podzbioru argumentów" i dlaczego jest niebezpieczny, może podać przykład?

+12

Jest to nieco mniej (a nakrętka poniżej części) w użyciu, 'z (czystości powietrza, czystości powietrza [miesiąc == 8 i Temp> 90]) ' –

+1

Ten wątek omawia ostrzeżenie 'subset()': http://r.789695.n4.nabble.com/Variable-passed-to-function-not-used-in-function-in-select-in-subset- tt872217.html – jthetzel

+3

Możesz również rzucić okiem na Cirlces 8.2.31 i 8.2.32 z "The R Inferno" http://www.burns-stat.com/pages/Tutor/R_inferno.pdf –

Odpowiedz

201

Na to pytanie odpowiedzieli dobrze w komentarzach @ James, wskazując na doskonałe wyjaśnienie Hadleya Wickhama dotyczące niebezpieczeństw związanych z subset (i funkcji takich jak to) [here]. Idź przeczytać!

Jest to dość długo czytać, więc może to być pomocne, aby nagrać tu przykład, że Hadley używa które najbardziej bezpośrednio odnosi się do kwestii „co może pójść źle?”:

Hadley sugeruje następujący przykład: Załóżmy, że aby podzbioru i kolejność ramkę danych za pomocą następujących funkcji:

scramble <- function(x) x[sample(nrow(x)), ] 

subscramble <- function(x, condition) { 
    scramble(subset(x, condition)) 
} 

subscramble(mtcars, cyl == 4) 

to zwraca błąd:

Error in eval(expr, envir, enclos) : object 'cyl' not found

ponieważ R L onger "wie", gdzie znaleźć obiekt o nazwie "cyl". Podkreśla również, prawdziwie dziwaczne rzeczy, które mogą się zdarzyć, jeśli przez przypadek nie jest obiekt o nazwie „cyl” w otoczeniu globalnym:

cyl <- 4 
subscramble(mtcars, cyl == 4) 

cyl <- sample(10, 100, rep = T) 
subscramble(mtcars, cyl == 4) 

(Uruchom je i zobaczyć na własne oczy, to dość szalony.)

+2

Czy mogę prosić o wyjaśnienia? Kiedy piszemy 'podzbiór (mtcars, cyl == 4)' (na najwyższym poziomie), gdzie R szuka cylindra? Jeśli zajrzy do obiektu 'mtcars', który jest przekazywany do' subset() ', to nie powinien być w stanie znaleźć' cyl', nawet jeśli 'scramble' jest w innej funkcji, ponieważ' mtcars' nadal jest przekazywane do to? Jeśli moje pytanie nie ma sensu, możesz po prostu rozwinąć więcej o tym, dlaczego R nie może już znaleźć 'cyl'. Dzięki! – Heisenberg

+3

@Anh Wewnątrz 'subset.data.frame', rzeczą, którą próbujemy ocenić w tym momencie, jest po prostu' warunek'. To nie istnieje w 'mtcars'. Tak więc 'subset.data.frame' używa' enclos = parent.frame() ', aby upewnić się, że' warunek' jest poprawnie oceniony jako 'cyl == 4'. Ale potem weszliśmy z powrotem do ramki otaczającej, a teraz, gdy R szuka "cyl", nie patrzy już na "mtcars". Gdybyśmy nie używali 'enclos', coś takiego jak' podzbiór (mtcars, cyl == a) 'nie działałby wcale. – joran

+0

czy ktoś wie, dlaczego podzbiór() nie zaimplementowałby szybszej i bezpieczniejszej [,] metody za kulisami? –

20

także [ szybciej:

require(microbenchmark)   
microbenchmark(subset(airquality, Month == 8 & Temp > 90),airquality[airquality$Month == 8 & airquality$Temp > 90,]) 
    Unit: microseconds 
                  expr  min  lq median  uq  max neval 
        subset(airquality, Month == 8 & Temp > 90) 301.994 312.1565 317.3600 349.4170 500.903 100 
    airquality[airquality$Month == 8 & airquality$Temp > 90, ] 234.807 239.3125 244.2715 271.7885 340.058 100 
+26

Tak i nie. Myślę, że różnica czasu, którą widzisz, wynika z dwóch rzeczy. 1) mały (<100 mikrosekund) i 2) 'podzbiór' w przeciwieństwie do' ['usuwa wiersze, w których filtr ocenia wartość 'NA'. Zrób to, a zobaczysz, że oba są równie szybkie, gdy porównane są "sprawiedliwie": 'x <- do.call (rbind, rep (lista (airquality), 100)); microbenchmark (podzbiór (x, Miesiąc == 8 i Temp> 90), {i <- x $ Miesiąc == 8 i x $ Temp> 90; x [! is.na (i) i i,]}) – flodel

Powiązane problemy