A.6 Comparando o mesmo conjunto de ações entre base R e dplyr

Abaixo, para efeitos de comparação, executamos as mesmas ações usando os pacotes base e dplyr; ao utilizar o dplyr, também fizemos uso do operador %>%.

# para avaliar os objetos criados no ambiente de trabalho, vamos apagar tudo da area de trabalho e comecar do zero
rm(list = ls())
# filtra os dados em iris
## quem tem sepala menor que 6 cm e tem petala maior que 5 cm?
iris2 <- subset(iris, Sepal.Length < 6 & Petal.Length < 5)
head(iris2, 10)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
4.7 3.2 1.3 0.2 setosa
4.6 3.1 1.5 0.2 setosa
5.0 3.6 1.4 0.2 setosa
5.4 3.9 1.7 0.4 setosa
4.6 3.4 1.4 0.3 setosa
5.0 3.4 1.5 0.2 setosa
4.4 2.9 1.4 0.2 setosa
4.9 3.1 1.5 0.1 setosa
# checa as dimensoes do novo objeto
dim(iris2)
## [1] 78  5
# ordena os dados segundo comprimento da petala
iris_ord <- iris2[order(iris2$Petal.Length), ]
head(iris_ord, 10)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
23 4.6 3.6 1.0 0.2 setosa
14 4.3 3.0 1.1 0.1 setosa
15 5.8 4.0 1.2 0.2 setosa
36 5.0 3.2 1.2 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
17 5.4 3.9 1.3 0.4 setosa
37 5.5 3.5 1.3 0.2 setosa
39 4.4 3.0 1.3 0.2 setosa
41 5.0 3.5 1.3 0.3 setosa
42 4.5 2.3 1.3 0.3 setosa
# muda a ordem das colunas, colocando a coluna Species primeiro
colsp <- which(colnames(iris_ord) == "Species") # qual a posicao da coluna Species?
irisf <- iris_ord[, c(colsp, (which(!(1:ncol(iris_ord)) %in% colsp)))]
# cria uma nova coluna de razao entre comprimento da sepala e comprimento da petala
irisf$razao_sepall_petall <- irisf$Sepal.Length / irisf$Petal.Length
head(irisf, 10)
Species Sepal.Length Sepal.Width Petal.Length Petal.Width razao_sepall_petall
23 setosa 4.6 3.6 1.0 0.2 4.600000
14 setosa 4.3 3.0 1.1 0.1 3.909091
15 setosa 5.8 4.0 1.2 0.2 4.833333
36 setosa 5.0 3.2 1.2 0.2 4.166667
3 setosa 4.7 3.2 1.3 0.2 3.615385
17 setosa 5.4 3.9 1.3 0.4 4.153846
37 setosa 5.5 3.5 1.3 0.2 4.230769
39 setosa 4.4 3.0 1.3 0.2 3.384615
41 setosa 5.0 3.5 1.3 0.3 3.846154
42 setosa 4.5 2.3 1.3 0.3 3.461539
# faz um sumario estatisco agrupando as especies e checando min, max, desvio, media e mediana de cada variavel
mean_pl <- aggregate(irisf$Petal.Length, list(Species = irisf$Species), FUN = "mean")
mean_raz <- aggregate(irisf$razao_sepall_petall, list(Species = irisf$Species), FUN = "mean")
sd_pl <- aggregate(irisf$Petal.Length, list(Species = irisf$Species), FUN = "sd")
sd_raz <- aggregate(irisf$razao_sepall_petall, list(Species = irisf$Species), FUN = "sd")
res <- as.data.frame(mean_pl)
res2 <- cbind(res, media_razao = mean_raz[, -1], desvio_pl = sd_pl[, -1], desvio_raz = sd_raz[, -1])
names(res2)[2] <- "media_pl"
res2
Species media_pl media_razao desvio_pl desvio_raz
setosa 1.462000 3.464906 0.1736640 0.4302168
versicolor 3.969231 1.404475 0.4249887 0.1195457
virginica 4.700000 1.115873 0.2828427 0.0381613
# plota grafico de pontos com eixo X correspondendo ao comprimento da sepala, e eixo Y ao comprimento da petala
plot(irisf$Sepal.Length, irisf$Petal.Length, col = irisf$Species)

# para avaliar os objetos criados no ambiente de trabalho, vamos apagar tudo da area de trabalho e comecar do zero
rm(list = ls())
# chama os pacotes tidyverse
library("dplyr") # o pacote para manipular dados
library("ggplot2") # o pacote para plotar graficos
# utilizando a filosofia tidyverse, utilizarei o pipe (" %>% ")
iris2t <- # salvamos o objeto como `iris2t` para diferenciar do salvo acima
  iris %>% # chama os dados e passa para a funcao abaixo
  filter(Sepal.Length < 6 & Petal.Length < 5) %>% # quem tem sepala menor que 6 cm E petala maior que 5 cm?
  arrange(Petal.Length) %>%
  mutate(razao_sepall_petall = Sepal.Length / Petal.Length) %>%
  select(Species, everything()) # reordena as colunas
head(iris2t, 10)
Species Sepal.Length Sepal.Width Petal.Length Petal.Width razao_sepall_petall
setosa 4.6 3.6 1.0 0.2 4.600000
setosa 4.3 3.0 1.1 0.1 3.909091
setosa 5.8 4.0 1.2 0.2 4.833333
setosa 5.0 3.2 1.2 0.2 4.166667
setosa 4.7 3.2 1.3 0.2 3.615385
setosa 5.4 3.9 1.3 0.4 4.153846
setosa 5.5 3.5 1.3 0.2 4.230769
setosa 4.4 3.0 1.3 0.2 3.384615
setosa 5.0 3.5 1.3 0.3 3.846154
setosa 4.5 2.3 1.3 0.3 3.461539
# faz um sumario estatisco agrupando as especies e checando min, max, desvio, media e mediana de cada variavel
res_t <- iris2t %>%
  group_by(Species) %>% # agrupa dados pela coluna Species
  summarise( # sumarisa dados de acordo com os grupo estabelecidos acima
    mean_pl = mean(Petal.Length), # media da coluna comp de petala
    mean_raz = mean(razao_sepall_petall), # media da coluna razao de comp de sepala/petala
    sd_pl = sd(Petal.Length), # desvio do comp da petala
    sd_raz = sd(razao_sepall_petall)
  ) # desvio do comp da sepala
head(res_t, 10)
Species mean_pl mean_raz sd_pl sd_raz
setosa 1.462000 3.464906 0.1736640 0.4302168
versicolor 3.969231 1.404475 0.4249887 0.1195457
virginica 4.700000 1.115873 0.2828427 0.0381613
# plota grafico de pontos com eixo X correspondendo ao comprimento da sepala, e eixo Y ao comprimento da petala
tgraf <- ggplot(data = iris2t) +
  geom_point(aes(x = Sepal.Length, y = Petal.Length, color = Species))
tgraf

Vejam que os resultados são iguais, com exceção da estética diferente proporcionada pelo pacote ggplot2. Porém, há uma mudança notável em como a manipulação dos dados é feita quando utilizamos o operador %>% dentro do fluxo de trabalho, como resumido acima: a leitura é feita da esquerda para a direita, podemos reduzir a criação de objetos intermediários na área de trabalho, e o código pode ser lido com mais clareza. Postagens futuras abordarão com mais detalhes outros usos deste operador e de alguns outros inclusos no mesmo pacote, porém com funções levemente diferentes.

A.6.1 E o uso do operador %>% com o pacote base?

Apesar de termos explorado até aqui o uso do operador %>% apenas com o pacote dplyr, ele pode ser utilizado com qualquer função no R. Vamos retormar o exemplo da seção acima com comandos do pacote base do R, porém adicionando o operador %>% na manipulação dos dados:

iris_ord <-
  iris %>%
  subset(Sepal.Length < 6 & Petal.Length < 5) %>% # filtramos os dados com a funcao subset()
  .[order(.$Petal.Length), ] # usamos o `.` para representar o data.frame filtrado no passo anterior
colsp <- which(colnames(iris_ord) == "Species")
irisf <- iris_ord[, c(colsp, (which(!(1:ncol(iris_ord)) %in% colsp)))]
irisf$razao_sepall_petall <- irisf$Sepal.Length / irisf$Petal.Length
head(irisf, 10)
Species Sepal.Length Sepal.Width Petal.Length Petal.Width razao_sepall_petall
23 setosa 4.6 3.6 1.0 0.2 4.600000
14 setosa 4.3 3.0 1.1 0.1 3.909091
15 setosa 5.8 4.0 1.2 0.2 4.833333
36 setosa 5.0 3.2 1.2 0.2 4.166667
3 setosa 4.7 3.2 1.3 0.2 3.615385
17 setosa 5.4 3.9 1.3 0.4 4.153846
37 setosa 5.5 3.5 1.3 0.2 4.230769
39 setosa 4.4 3.0 1.3 0.2 3.384615
41 setosa 5.0 3.5 1.3 0.3 3.846154
42 setosa 4.5 2.3 1.3 0.3 3.461539
mean_pl <- aggregate(irisf$Petal.Length, list(Species = irisf$Species), FUN = "mean")
mean_raz <- aggregate(irisf$razao_sepall_petall, list(Species = irisf$Species), FUN = "mean")
sd_pl <- aggregate(irisf$Petal.Length, list(Species = irisf$Species), FUN = "sd")
sd_raz <- aggregate(irisf$razao_sepall_petall, list(Species = irisf$Species), FUN = "sd")
res <- as.data.frame(mean_pl)
res2 <- cbind(res, media_razao = mean_raz[, -1], desvio_pl = sd_pl[, -1], desvio_raz = sd_raz[, -1])
names(res2)[2] <- "media_pl"
res2
Species media_pl media_razao desvio_pl desvio_raz
setosa 1.462000 3.464906 0.1736640 0.4302168
versicolor 3.969231 1.404475 0.4249887 0.1195457
virginica 4.700000 1.115873 0.2828427 0.0381613

Reparem que, mesmo utilizando o operador %>%, algumas transformações realizadas com poucas linhas de código com o pacote dplyr em uma cadeia de comandos (o chamado pipeline em inglês) não são possíveis com o uso do pacote base do R, notadamente a criação de colunas, o rearranjo de colunas, e o sumário de dados.