Kiedy muszę filtrować ramkę data.frame, tzn. Wyodrębnić wiersze spełniające określone warunki, wolę użyć subset
funkcji:
subset(airquality, Month == 8 & Temp > 90)
Zamiast [
funkcji:
airquality[airquality$Month == 8 & airquality$Temp > 90, ]
Są dwa główne powody mojej preferencji:
Uważam, że kod czyta się lepiej, od lewej do prawej. Nawet ludzie, którzy nie wiedzą nic o R, mogą powiedzieć, co
subset
robi powyższe stwierdzenie.Ponieważ kolumny w
select
wyrażeniu mogą być nazywane zmiennymi , mogę zapisać kilka naciśnięć klawiszy. W powyższym przykładzie musiałem pisaćairquality
tylko razsubset
, ale trzy razy[
.
Tak więc żyłem szczęśliwy, używając subset
wszędzie, ponieważ jest on krótszy i czyta się lepiej, a nawet polecam jego piękno innym znajomym koderom R. Ale wczoraj mój świat się rozpadł. Podczas czytania subset
dokumentacji zauważam ten rozdział:
Ostrzeżenie
Jest to wygodna funkcja przeznaczona do użytku interaktywnego. Do programowania lepiej jest używać standardowych funkcji podzestawu, takich jak [, aw szczególności niestandardowa ocena podzbioru argumentów może mieć nieoczekiwane konsekwencje.
Czy ktoś mógłby pomóc wyjaśnić, co mają na myśli autorzy?
Po pierwsze, co rozumieją przez „ do użytku interaktywnego ”? Wiem, czym jest sesja interaktywna, w przeciwieństwie do skryptu uruchamianego w trybie BATCH, ale nie widzę, jaką różnicę powinna ona robić.
Czy mógłbyś zatem wyjaśnić „ niestandardową ocenę podzbioru argumentów ” i dlaczego jest to niebezpieczne, może podać przykład?
with(airquality, airquality[Month == 8 & Temp > 90, ])
dplyr::filter
ma ten sam problem. To znaczy, jeśli środowisko ma zmienną o tej nazwie, użyje jej zamiast zmiennej w ramce danych. Powoduje mylące debugowanie!Odpowiedzi:
Odpowiedzi na to pytanie udzielono w komentarzach @James, wskazując na doskonałe wyjaśnienie Hadleya Wickhama na temat niebezpieczeństw
subset
(i podobnych funkcji) [tutaj] . Przeczytaj to!Jest to nieco długa lektura, więc pomocne może być zanotowanie tutaj przykładu, który wykorzystuje Hadley, który najbardziej bezpośrednio odnosi się do pytania „co może pójść nie tak?
Hadley sugeruje następujący przykład: załóżmy, że chcemy rozdzielić, a następnie zmienić kolejność ramki danych za pomocą następujących funkcji:
To zwraca błąd:
ponieważ R już nie „wie”, gdzie znaleźć obiekt o nazwie „cyl”. Wskazuje również na naprawdę dziwaczne rzeczy, które mogą się zdarzyć, jeśli przypadkiem w globalnym środowisku pojawi się obiekt o nazwie „cyl”:
(Uruchom je i przekonaj się sam, to całkiem szalone.)
źródło
subset(mtcars, cyl == 4)
(na najwyższym poziomie), gdzie R szuka cyl? Jeśli patrzy namtcars
obiekt, który jest przekazywanysubset()
, to czy nie powinien być w stanie znaleźć,cyl
nawet jeśliscramble
jest w innej funkcji, ponieważmtcars
nadal jest do niego przekazywany? Jeśli moje pytanie nie ma sensu, możesz po prostu wyjaśnić, dlaczego R nie może już znaleźćcyl
. Dzięki!subset.data.frame
, rzeczą, którą próbujemy ocenić w tym momencie, jest właśniecondition
. To nie istniejemtcars
.subset.data.frame
Używa więc,enclos = parent.frame()
aby upewnić się, żecondition
jest poprawnie ocenione jakocyl == 4
. Ale potem wróciliśmy do otaczającej ramy i teraz, gdy R szuka,cyl
nie jest już w środkumtcars
. Gdybyśmy nie korzystalienclos
, coś takiego wsubset(mtcars,cyl == a)
ogóle by nie działało.subset.data.frame
tox[r, vars, drop = drop]
. Problem polega na tym, jak przejść od cytatówsubset
iselect
argumentów do czegoś, co można poprawnie przekazać[.data.frame
.[]
?[
Jest także szybszy:źródło
subset
przeciwieństwie do[
usuwa wiersze, w których ocenia filtrNA
. Zrób to, a zobaczysz, że oba są równie szybkie w porównaniu z „dość”:x <- do.call(rbind, rep(list(airquality), 100)); microbenchmark(subset(x, Month == 8 & Temp > 90),{ i <- x$Month == 8 & x$Temp > 90; x[!is.na(i) & i ,] })