Quando preciso filtrar um data.frame, ou seja, extrair linhas que atendam a determinadas condições, prefiro usar a subset
função:
subset(airquality, Month == 8 & Temp > 90)
Em vez da [
função:
airquality[airquality$Month == 8 & airquality$Temp > 90, ]
Há duas razões principais para minha preferência:
Acho que o código lê melhor, da esquerda para a direita. Mesmo as pessoas que não sabem nada sobre R podem dizer o que a
subset
afirmação acima está fazendo.Como as colunas podem ser referidas como variáveis na
select
expressão, posso salvar algumas pressionamentos de tecla. No meu exemplo acima, eu só precisei digitarairquality
uma vez comsubset
, mas três vezes com[
.
Então, eu estava vivendo feliz, usando em subset
todos os lugares porque é mais curto e lê melhor, até mesmo defendendo sua beleza aos meus colegas programadores R. Mas ontem meu mundo se desfez. Ao ler a subset
documentação, observe esta seção:
Atenção
Esta é uma função de conveniência destinada ao uso interativamente. Para a programação, é melhor usar as funções de subconjunto padrão como [e, em particular, a avaliação não padrão do subconjunto de argumentos pode ter consequências imprevistas.
Alguém poderia ajudar a esclarecer o que os autores querem dizer?
Primeiro, o que eles querem dizer com " para uso interativo "? Eu sei o que é uma sessão interativa, em oposição a um script executado no modo BATCH, mas não vejo a diferença que deve fazer.
Então, você poderia explicar " a avaliação não padrão do subconjunto de argumentos " e por que é perigosa, talvez fornecer um exemplo?
with(airquality, airquality[Month == 8 & Temp > 90, ])
dplyr::filter
tem o mesmo problema. Ou seja, se o ambiente tiver uma variável com esse nome, ele será usado em vez da variável no quadro de dados. Torna a depuração confusa!Respostas:
Essa pergunta foi bem respondida nos comentários de @James, apontando para uma excelente explicação de Hadley Wickham sobre os perigos
subset
(e funciona como ele) [aqui] . Vá ler!É uma leitura um tanto longa, portanto, pode ser útil registrar aqui o exemplo que Hadley usa que aborda mais diretamente a questão "o que pode dar errado?":
Hadley sugere o seguinte exemplo: suponha que desejemos subconjunto e, em seguida, reordenar um quadro de dados usando as seguintes funções:
Isso retorna o erro:
porque R não "sabe" mais onde encontrar o objeto chamado 'cyl'. Ele também aponta as coisas verdadeiramente bizarras que podem acontecer se, por acaso, houver um objeto chamado 'cyl' no ambiente global:
(Execute-os e veja por si mesmo, é muito louco.)
fonte
subset(mtcars, cyl == 4)
(no nível superior), onde R procura o cyl? Se ele olhar para omtcars
objeto ao qual é passadosubset()
, não deve ser capaz de encontrarcyl
mesmo sescramble
estiver dentro de outra função, poismtcars
ainda está sendo passado para ele? Se minha pergunta não fizer sentido, você pode apenas elaborar mais detalhes sobre por que o R não consegue mais encontrarcyl
. Obrigado!subset.data.frame
, o que estamos tentando avaliar nesse momento é justocondition
. Isso não existemtcars
. Então,subset.data.frame
usaenclos = parent.frame()
para garantir quecondition
seja avaliado corretamente comocyl == 4
. Mas então voltamos ao quadro anexo e agora, quando R o procura,cyl
ele não está mais olhando para dentromtcars
. Se não usássemosenclos
, algo comosubset(mtcars,cyl == a)
não funcionaria.subset.data.frame
éx[r, vars, drop = drop]
. O problema é como passar dos argumentos não citadossubset
eselect
para algo que você possa transmitir validamente[.data.frame
.[]
?Também
[
é mais rápido:fonte
subset
ao contrário[
remove linhas nas quais o filtro é avaliadoNA
. Faça isso e você vai ver que eles são ambos tão rápido quando comparado "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 ,] })