Cuando necesito filtrar un data.frame, es decir, extraer filas que cumplen ciertas condiciones, prefiero usar la subset
función:
subset(airquality, Month == 8 & Temp > 90)
En lugar de la [
función:
airquality[airquality$Month == 8 & airquality$Temp > 90, ]
Hay dos razones principales para mi preferencia:
Encuentro que el código se lee mejor, de izquierda a derecha. Incluso las personas que no saben nada sobre R podrían decir qué
subset
está haciendo la declaración anterior.Debido a que las columnas pueden denominarse variables en la
select
expresión, puedo guardar algunas pulsaciones de teclas. En mi ejemplo anterior, solo tuve que escribirairquality
una vez consubset
, pero tres veces con[
.
Así que estaba viviendo feliz, utilizándolo en subset
todas partes porque es más corto y se lee mejor, incluso defendiendo su belleza para mis compañeros codificadores R. Pero ayer mi mundo se rompió. Mientras leo la subset
documentación, noto esta sección:
Advertencia
Esta es una función de conveniencia diseñada para su uso interactivo. Para programar es mejor usar las funciones de subconjunto estándar como [, y en particular la evaluación no estándar del subconjunto de argumentos puede tener consecuencias imprevistas.
¿Alguien podría ayudar a aclarar lo que quieren decir los autores?
Primero, ¿qué quieren decir con " para uso interactivo "? Sé lo que es una sesión interactiva, a diferencia de un script ejecutado en modo BATCH, pero no veo qué diferencia debería hacer.
Entonces, ¿podría explicar " la evaluación no estándar del subconjunto de argumentos " y por qué es peligroso, tal vez dar un ejemplo?
with(airquality, airquality[Month == 8 & Temp > 90, ])
dplyr::filter
tiene el mismo problema. Es decir, si el entorno tiene una variable con ese nombre, lo usará en lugar de la variable en el marco de datos. ¡Hace para la depuración confusa!Respuestas:
Esta pregunta fue respondida bien en los comentarios de @James, señalando una excelente explicación de Hadley Wickham de los peligros de
subset
(y funciones similares) [aquí] . Ve a leerlo!Es una lectura un tanto larga, por lo que puede ser útil registrar aquí el ejemplo que Hadley usa que aborda más directamente la pregunta de "¿qué puede salir mal?":
Hadley sugiere el siguiente ejemplo: supongamos que queremos subconjuntos y luego reordenar un marco de datos utilizando las siguientes funciones:
Esto devuelve el error:
porque R ya no "sabe" dónde encontrar el objeto llamado 'cyl'. También señala las cosas realmente extrañas que pueden suceder si por casualidad hay un objeto llamado 'cyl' en el entorno global:
(Ejecútelos y vea por usted mismo, es bastante loco)
fuente
subset(mtcars, cyl == 4)
(en el nivel superior), ¿dónde busca R cyl? Si examina elmtcars
objeto al que se pasasubset()
, ¿no debería poder encontrarlocyl
incluso siscramble
está dentro de otra función, yamtcars
que todavía se le pasa? Si mi pregunta no tiene sentido, podría explicar con más detalle por qué R ya no puede encontrarlacyl
. ¡Gracias!subset.data.frame
, lo que estamos tratando de evaluar en ese momento es justocondition
. Eso no existe enmtcars
. Por lo tanto, sesubset.data.frame
utilizaenclos = parent.frame()
para garantizar quecondition
se evalúe correctamente comocyl == 4
. Pero luego volvimos a aparecer en el marco adjunto, y ahora, cuando R lo busca,cyl
ya no está mirando hacia adentromtcars
. Si no lo usáramosenclos
, algo asísubset(mtcars,cyl == a)
no funcionaría en absoluto.subset.data.frame
esx[r, vars, drop = drop]
. El problema es cómo pasar de lo no citadosubset
y losselect
argumentos a algo que puede pasar válidamente[.data.frame
.[]
?También
[
es más rápido:fuente
subset
diferencia,[
elimina las filas donde se evalúa el filtroNA
. Haga esto y verá que ambos son tan rápidos cuando se comparan "bastante":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 ,] })