Abaixo está o data.frame
que seguiremos utilizando (nativo do R):
names(iris)
[1] "Sepal.Length" "Sepal.Width"
[3] "Petal.Length" "Petal.Width"
[5] "Species"
Como vimos no encontro anterior tapply
pode realizar algumas operações por agrupamento. Exemplo:
tapply(X = iris$Petal.Width, INDEX = iris$Species, FUN = mean)
setosa versicolor virginica
0.246 1.326 2.026
Outra forma de fazer isso seria recebendo o resultado em forma de tabela:
aggregate(Petal.Width ~ Species, data = iris, FUN = mean)
Species Petal.Width
1 setosa 0.246
2 versicolor 1.326
3 virginica 2.026
A função aggregate
é designada para trabalhar com várias colunas e retornar um data.frame
com uma linha para cada categoria, enquanto a tapply
é designada para ser usada com vetores (uma única coluna) retornando uma matriz.
Dentre essas funções, qual seria a opção mais rápida?
Para descobrir, foi construída a seguinte função, com as especificações do passo a passo dentro dela:
clock <- function(f) {
# registro do tempo inicial
tic <- Sys.time()
# função que iremos testar
f
# registro do tempo final
toc <- Sys.time()
# tempo que a função gastou para rodar (tf-ti)
time <- toc - tic
# retornando o resultado da função e o tempo que ela levou, através de uma lista
list(f, time)
}
Aplicando a função nos 2 métodos:
clock(tapply(X = iris$Petal.Width, INDEX = iris$Species, FUN = mean))
[[1]]
setosa versicolor virginica
0.246 1.326 2.026
[[2]]
Time difference of 0.0009338856 secs
clock(aggregate(Petal.Width ~ Species, data = iris, FUN = mean))
[[1]]
Species Petal.Width
1 setosa 0.246
2 versicolor 1.326
3 virginica 2.026
[[2]]
Time difference of 0.002429008 secs
Logo, como foi visto acima, a função tapply
é mais rápida! Isso no geral irá ocorrer, ou seja, operações com vetores tendem a ser mais rápidas do que aquelas que envolvem tabelas.
Obs.: Existem outras maneiras mais eficientes de se obter o exato tempo que leva cada função, mas essa é bastante clara e aborda o tópico de funções que começamos a ver no último encontro.
Outros usos da função aggregate, que explicitam suas vantagens:
aggregate(cbind(iris$Petal.Length, iris$Petal.Width), by = list(iris$Species), FUN = mean)
Group.1 V1 V2
1 setosa 1.462 0.246
2 versicolor 4.260 1.326
3 virginica 5.552 2.026
Existe outra maneira de escrever o mesmo código de maneira simplificada, e o resultado será apresentado abaixo com uma pequena diferença, pois esse método já retorna o nome original das colunas (o que facilita a compreensão do resultado):
aggregate(cbind(Petal.Length, Petal.Width) ~ Species, data = iris, FUN = mean)
Species Petal.Length Petal.Width
1 setosa 1.462 0.246
2 versicolor 4.260 1.326
3 virginica 5.552 2.026
Nas 2 funções acima nós combinamos as colunas através da função cbind
gerando a média por espécies das variáveis especificadas (Petal.Length
e Petal.Width
). Perceba que as funções se diferem no modo de chamar as variáveis. A primeira função exige que o agrupamento seja feito por lista através do argumento by
. A segunda função utiliza o formato de fórmula que vimos no sexto encontro.
Exemplo contando o número de vezes que ocorre cada espécie:
aggregate(iris$Species, by = list(iris$Species), FUN = length)
Group.1 x
1 setosa 50
2 versicolor 50
3 virginica 50
No entanto, a forma mais eficiente e fácil de se fazer isso seria através da função table:
table(iris$Species)
setosa versicolor virginica
50 50 50
Com isso, podemos analisar tabelas e vetores que possuem categorias de forma rápida e eficiente!