Capítulo 5 Gráficos estatísticos
Uma imagem vale mais que mil palavras
Os gráficos estatísticos são utilizados para fazer uma representação visual dos dados. São elaborados para serem vistos por você e por outras pessoas, por isso, sempre haverá um certo nível de subjetividade na interpretação do gráfico.
Não há (muitas) regras na elaboração dos gráficos, pelo contrário, temos liberdade para elaborá-los das forma que melhor nos convém. No entanto, existem guias gerais bem estabelecidas que facilitam o processo de escolha do tipo de gráfico mais adequado para o seu conjunto de dados. Em outras palavras, uma boa metodologia aplicada na construção dos gráficos é extremamente útil para seu correto entendimento e interpretação, seja qual for o público alvo.
A Figura 5.1 vemos um exemplo de um gráfico ruim. Há uma quantidade considerável de poluição visual; as barras são difíceis de comparar devido à perspectiva “3D”; os rótulos estão duplicados, na legenda e no eixo vertical; as sombras não acrescentam nenhuma informação; a escolha das cores não foi muito bem feita.
5.1 O pacote ggplot2
O pacote ggplot2
foi criado por Hadley Wickham baseado em um conceito denominado “Gramática de Gráficos” (Grammar of Graphics).
De um modo geral, a criação de gráficos com o ggplot2
executa o mapeamento (mapping
) dos dados para propriedades estéticas (aes
) e geométricas (geom_*
). Ainda, podem ser executadas transformações estatísticas (stat_*
) e divisões (facet_*
).
Todas essas camadas combinadas irão resultar no gráfico final.
O primeiro passo é chamar a funçao ggplot
(sem o número 2 no final!). O argumento data
recebe o conjunto de dados (data.frame) que contém os valores. Para este primeiro exemplo, vamos utilizar o conjunto de dados gapminder.
Ainda, vamos mapear o eixo x para a variável gdpPercap (do inglês, PIB per capita, em US Dollar) e o eixo y para a variável lifeExp (do inglês, expectativa de vida ao nascer, em anos). Fica assim:
library(gapminder) # carregar os dados gapminder
ggplot(
data = gapminder,
mapping = aes(x = gdpPercap, y = lifeExp)
)
Ops, o gráfico resultante está vazio! O que aconteceu? Esta função cria apenas o “pano de fundo” para o gráfico, uma vez que ainda não definimos nenhuma geometria para preenchê-lo.
Para completar o gráfico, basta digitar o sinal de adição +
e chamar alguma função do tipo geom_*
, por exemplo, geom_point
para um gráfico de pontos 16. Na prática, estamos adicionando (+
) mais uma camada ao gráfico.
ggplot(
data = gapminder,
mapping = aes(x = gdpPercap, y = lifeExp)
) +
geom_point()
Em geral, todos os gráficos produzidos com o ggplot
seguem praticamente a mesma receita:
ggplot(
data = <data>,
mapping = aes(x = <variável x>,
y = <variável y>,
<...> = <...>)
) +
geom_*(<...>) +
<...>
Para simplificar ainda mais o código, é possível suprimir o nome dos argumentos data
e mapping
, pois são argumentos muito comuns em todos os gráficos criados com o ggplot2
. Por isso, de agora em diante, neste livro, estes nomes não serão mais escritos.
ggplot(
gapminder,
aes(x = gdpPercap, y = lifeExp)
) +
geom_point()
5.1.1 Criando gráficos do ggplot
como objetos
Uma forma bastante conveniente de trabalhar com os gráficos é armazenar em objetos.
p <- ggplot(
gapminder,
aes(x = gdpPercap, y = lifeExp)
)
Neste código, criamos um objeto denominado p
17 que contém as informações básicas do gráfico. Na sequência, podemos adicionar mais elementos neste mesmo gráfico apenas adicionando (+
) alguma função ao objeto.
p +
geom_point()
p +
geom_smooth()
## `geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
p +
geom_point() +
geom_smooth()
## `geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
5.1.2 Personalizando os eixos
Muitas vezes precisamos personalizar os eixos do gráfico para aprimorar a visualização.
A função labs
permite alterar vários argumentos, como visto no exemplo a seguir:
p +
geom_point() +
labs(
x = "PIB per capita (US$)",
y = "Expectativa de vida ao nascer (anos)",
title = "Economia vs Expectativa de Vida",
subtitle = "Cada ponto representa um país e um ano",
caption = "Fonte: Gapminder"
)
-
x
altera o rótulo do eixo x -
y
altera o rótulo do eixo y -
title
adiciona um título na parte superior -
subtitle
adiciona um subtítulo logo abaixo do título -
caption
rótulo que aparece no canto inferior direito
5.1.3 Mapeando atributos estéticos
Nesta seção, vamos estudar mais sobre os atributos estéticos. Em nosso primeiro gráfico, já utilizamos dois atributos de posição cartesiana: os eixos x e y.
Entre vários outros atributos estéticos, vamos trabalhar com color
e fill
, que alteram cores.
ggplot(
gapminder,
aes(
x = gdpPercap,
y = lifeExp,
color = continent
)
) +
geom_point() +
scale_x_log10()
Vejam que ao mapear color
para uma variável, foram atribuídas cores aos pontos, uma cor diferente para cada continente. Também foi adicionada uma legenda explicativa.
Na figura seguinte, vamos adicionar mais uma camada ao gráfico, a linha ajustada com geom_smooth
.
ggplot(
gapminder,
aes(
x = gdpPercap,
y = lifeExp,
color = continent
)
) +
geom_point() +
geom_smooth(method = "lm", formula = y ~ x) +
scale_x_log10()
Veja que foi criada uma linha de ajuste para cada continente. Isso acontece porque foi mapeado o atributo color
para os continentes. No entanto, a faixa do interval de confiança não acompanhou as cores, permanecendo na cor cinza. Isso acontece porque, para o ggplot
, há dois tipos de objetos: color
serve para linhas e pontos e fill
serve para preenchimento de áreas e políogonos. Assim, para colorir a faixa do intervalo de confiança, os continentes deve ser mapeada para o atributo fill
, como no exemplo a seguir.
ggplot(
gapminder,
aes(
x = gdpPercap,
y = lifeExp,
color = continent,
fill = continent
)
) +
geom_point() +
geom_smooth(method = "lm", formula = y ~ x) +
scale_x_log10()
5.1.4 Mapeando atributos em cada geom_*
Mas cinco linhas ajustadas podem ser demais. Queremos ajustar apenas uma! E ainda queremos manter os pontos coloridos para cada continente. Para resolver esta situação, podemos mapear os atributos dentro de cada geometria.
Por padrão, as funções geom_*
herdam seus mapeamentos da funçao ggplot
. Podemos alterar este comportamento mapeando a estética apenas dentro da função geom_*
que queremos que se aplique.
ggplot(
gapminder,
aes(
x = gdpPercap,
y = lifeExp
)
) +
geom_point(aes(color = continent)) +
geom_smooth(method = "lm", formula = y ~ x) +
scale_x_log10()
Também é possível mapear variáveis numéricas, por exemplo, o logaritmo da população em cada país e ano. Quando fazemos isso, a escala de cor produzida é um gradiente contínuo. A função scale_color_viridis_c()
especifica a utilização da paleta de cor viridis.
ggplot(
gapminder,
aes(
x = gdpPercap,
y = lifeExp
)
) +
geom_point(aes(color = log(pop))) +
geom_smooth(method = "lm", formula = y ~ x) +
scale_x_log10() +
scale_color_viridis_c()
5.1.5 Definindo atributos estéticos
Em algumas situações nós apenas queremos definir atributos estéticos, como cores, em vez de mapeá-los para alguma variável. Para isso, devemos definir estes atributos fora da função aes()
.
p <- ggplot(
data = gapminder,
mapping = aes(
x = gdpPercap,
y = lifeExp
)
)
p +
geom_point(color = "purple") +
scale_x_log10()
p +
geom_point(shape = 8, size = 2, color = "tomato") +
scale_x_log10()
p +
geom_point(alpha = 0.3) +
geom_smooth(color = "orange", size = 8, method = "lm", formula = y ~ x) +
scale_x_log10()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
5.2 Gráfico de barras
O gráfico de barras, que também pode ser chamado de gráfico de colunas, é um gráfico em que a altura das barras é proporcional ao valor por elas representado. Quando ordenado, também pode ser chamado de Gráfico de Pareto
Este tipo de gráfico é utilizado para representar os dados quando uma das variáveis é categórica ou numérica discreta. 18
A maior parte dos exemplos de gráficos de barras utilizará o conjunto de dados mpg.
5.2.1 Gráfico de barras para uma variável
No ggplot2
, as geometrias deste tipo de gráfico são: geom_bar
ou geom_col
. A diferença entre elas é que geom_bar
tem como padrão a função stat_count
que representa o número de casos em cada grupo (contagem) e geom_col
tem como padrão a função stat_identity
que mantém os dados como estão e pode ser usada para representa valores numéricos de outra variável.
Quando há apenas uma variável categórica, a altura das barras é proprocional ao número (contagem) de indivíduos em cada categoria. Neste caso, usamos geom_bar
, cuja função padrão é stat_count
, que realiza a contagem das observações em cada classe.
ggplot(mpg, aes(x = class)) +
geom_bar()
Para ordenar as barras, precisamos organizar o data.frame original. Para isso, utilizamos algumas funções auxiliares presentes no pacote tidyverse
19. Adicionamos uma coluna adicional contendo a contagem de cada grupo e depois procedemos com a reordenação com a função fct_reorder
. Observem também a utilização do operador %>%
(pipe) que também é carregado junto com o pacote tidyverse
. Por fim, a geometria é alterada para geom_col
.
Por padrão, o ordenamento é crescente, ou seja, do menor para o maior. Para inverter, adicionamos o argumento .desc=TRUE
à função fct_reorder
, que faz o ordenamento decrescente.
No caso de uma variável numérica discreta, o código é essencialmente o mesmo, assim como suas variações.
ggplot(mpg, aes(x = cyl)) +
geom_bar()
Por existir uma ordem natural na variável discreta, a ordenação pelo tamanho das barras não é recomendada (na maioria dos casos).
5.2.2 Gráfico de barras para duas variáveis
O gráfico de barras também pode representar a relação entre duas variáveis, sendo uma delas categórica ou numérica discreta (eixo x) e a outra numérica (eixo y).
Neste primeiro exemplo, vamos plotar a relação entre uma variável categórica (class) e outra numérica contínua (displ).
Aqui, é necessário definir uma função para resumir os dados, uma vez que a função padrão (stat_count
) não é adequada. Uma opção muito comum é representar a média de cada grupo. Isso é possível com os argumentos stat = "summary"
e fun = "mean"
dentro da geometria geom_bar
. Assim, calculamos a média da variável displ em cada classe.
ggplot(mpg, aes(x = class, y = displ)) +
geom_bar(stat = "summary", fun = "mean")
Para plotar este mesmo gráfico com ordenação das colunas, devemos trabalhar no data.frame original. Assim, definimos uma nova variável (media_displ
) calculada a partir das médias do agrupamento das classes de automóveis. A função fct_reorder
faz a ordenação crescente das médias. A geometria deve ser modificada para geom_col
.
mpg %>%
group_by(class) %>%
summarise(media_displ = mean(displ)) %>%
ggplot(aes(x = fct_reorder(class, media_displ), y = media_displ)) +
geom_col()
5.2.3 Gráfico de barras para três variáveis.
É possível mapear uma terceira variável categórica ou numérica discreta em um gráfico de barras. A terceira variável é passada para o argumento fill
, que atribui uma cor diferente para cada nível.
Devemos explicitá-la como fatorizada, por isso a necessidade de usar a função factor
.
Nestes exemplo, vamos utilizar o conjunto de dados ToothGrowth.
A opção position = "dodge"
evita a sobreposição das barras ajustando-as lado a lado. Uma variação é position = "dodge2"
que adiciona um pequeno espaço entre as barras.
ggplot(ToothGrowth, aes(x = supp, y = len, fill = factor(dose))) +
geom_bar(stat = "summary", fun = "mean", position = "dodge") +
scale_fill_viridis_d()
Invertendo as variáveis do eixo x e do elemento fill
:
ggplot(ToothGrowth, aes(x = (dose), y = len, fill = supp)) +
geom_bar(stat = "summary", fun = "mean", position = "dodge") +
scale_fill_viridis_d()
5.3 Gráficos de dispersão
São utilizados para mostrar a relação entre duas variáveis numéricas contínuas. Para isso, são utilizados pontos que representam cada observação. A geometria para este tipo de gráfico é geom_point
. Veja este exemplo com os dados do conjunto iris.
ggplot(iris, aes(x = Petal.Length, y = Petal.Width)) +
geom_point()
Quando é bem clara a distinção entre as variáveis, sendo uma a variável preditora (independente) e a outra a variável resposta (dependente), estas devem ser organizadas da seguinte forma: a variável preditora é mapeada no eixo x e a variável resposta é mapeada para o eixo y. Veja este exemplo com dados do conjunto BOD
ggplot(BOD, aes(x = Time, y = demand)) +
geom_point()
5.3.1 Linha de tendência
É bastante comum que seja traçada uma linha para os valores preditos baseados em algum modelo estatístico
Pra isso, utilizaremos a função geom_smooth
, que já realiza o ajuste estatístico do modelo linear. Vamos definir o método (method = "lm"
) para lm
de modelo linear (ou linear model em inglês). O argumento se = FALSE
impede de traçar o intervalo de confiança.
ggplot(iris, aes(x = Petal.Length, y = Petal.Width)) +
geom_point() +
geom_smooth(method = "lm", formula = y ~ x)
Por padrão, é adicionado uma região de confiança de 95% para a regressão. A probabilidade pode ser alterada modificando o argumento level
, ou pode ser suprimida com o argumento se = FALSE
.
iris_disp_plot <- ggplot(iris, aes(x = Petal.Length, y = Petal.Width)) +
geom_point()
iris_disp_plot +
geom_smooth(method = "lm", formula = y ~ x, level =0.99)
iris_disp_plot +
geom_smooth(method = "lm", formula = y ~ x, se = FALSE)
Neste mesmo exemplo, é possível ajustar uma linha para cada espécie de Iris, mapeando as espécies para a cor.
ggplot(iris, aes(x = Petal.Length, y = Petal.Width, color = Species)) +
geom_point() +
geom_smooth(method = "lm", formula = y ~ x)
5.4 Sobreposição de elementos
Existem algumas situações em que, ao plotar os pontos, estes aparecem sobrepostos entre si. É mais comum quando ambas as variáveis são discretas, pois pode ocorrer a sobreposição perfeita.
ggplot(mpg, aes(x = year, y = cyl)) +
geom_point()
Para contornar este problema, pode-se fazer uso da geometria geom_jitter
. Ela adiciona uma pequena quantidade de variação aleatória à localização dos pontos, o que evita a sobreposição. Funciona melhor em conjuntos de dados pequenos.
ggplot(mpg, aes(x = year, y = cyl)) +
geom_jitter(width = 0.2, height = 0.2)
Outra forma de lidar com sobreposição é alterar o elemento alpha
, que determina a transparência dos pontos. É melhor para conjuntos de dados grandes e variáveis contínuas. No exemplo a seguir utilizamos o conjunto de dados diamonds.
diamonds_plot <- ggplot(diamonds, aes(x = carat, y = price))
diamonds_plot + geom_point()
diamonds_plot + geom_point(alpha = 0.1)
5.5 Gráficos de linhas
Os gráficos de linhas são utilizados quando queremos representar uma variável numérica contínua no eixo x. Em alguns casos, também podem ser utilizados para variáveis categóricas ou discretas, mas desde que tenham uma ordenação natural.
Voltamos ao conjunto de dados ToothGrowth. A dose, por ser uma variável numérica, pode ser representada no eixo x. Os valores de comprimento foram resumidos para cada observação.
ToothGrowth %>%
group_by(dose) %>%
summarise(len_mean = mean(len)) %>%
ggplot(aes(x = dose, y = len_mean)) +
geom_line()
É bastante comum a sobreposição dos pontos observados às linhas, com a adição de uma camada geom_point
.
ToothGrowth %>%
group_by(dose) %>%
summarise(len_mean = mean(len)) %>%
ggplot(aes(x = dose, y = len_mean)) +
geom_line() +
geom_point()
Ainda há a possibilidade de mapear uma terceira variável para o elemento color
.
ToothGrowth %>%
group_by(supp, dose) %>%
summarise(len_mean = mean(len)) %>%
ggplot(aes(x = dose, y = len_mean, color = supp)) +
geom_line()
## `summarise()` has grouped output by 'supp'. You can override using the
## `.groups` argument.
5.5.1 Gráficos de linhas para séries temporais
É bastante comum que a variável no eixo x de uma gráfico de linhas seja uma medida de tempo. Neste caso, o gráfico estará representando uma série temporal. A geometria utilizada é geom_line
. Para exemplificar, vamos utilizar o conjunto de dados economics.
ggplot(economics, aes(x = date, y = unemploy)) +
geom_line()
ggplot(economics, aes(x = date, y = pce)) +
geom_line()
5.6 Gráficos para distribuição
Uma distribuição de frequência é uma forma de resumir uma quantidade de dados distribuídos em classes ou intervalos. A frequência é o número de observações que pertencem a cada classe.
Nesta seção, serão apresentados vários tipos de gráficos utilizados para esta finalidade.
5.6.1 Histograma
O histograma é um tipo especial do gráfico de barras. No histograma, a largura de cada barra representa uma classe, e a altura das barras representa a frequência ou proporção dos valores contidos em cada classe. Via de regra, as barras do histograma devem ser apresentadas sem espaço entre elas.
A geometria para a construção do histograma é geom_histogram
.
Vamos exemplificar com o conjunto de dados faithful.
ggplot(faithful, aes(x = waiting)) +
geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
A cor padrão do histograma do ggplot
dificulta a separação das classes. É possível aprimorar este aspecto definindo uma cor para o contorno das barras.
ggplot(faithful, aes(x = waiting)) +
geom_histogram(color = "black")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Por padrão, o histograma feito com o ggplot
é dividido em 30 classes (bins = 30
. Este é um valor aleatório e não serve para a maioria dos casos. 20
Para alterar a quantidade de classes representada, há duas opções:
- Determinar o número de classes diretamente, modificando o argumento
bins
. - Determinar a dimensão das classes, modificando o argumento
binwidth
.
ff_plot <- ggplot(faithful, aes(x = waiting))
ff_plot + geom_histogram(bins = 20, color = "black")
ff_plot + geom_histogram(bins = 10, color = "black")
ff_plot + geom_histogram(binwidth = 1, color = "black")
ff_plot + geom_histogram(binwidth = 6, color = "black")
Quando temos vários grupos, podemos criar os histogramas separadamente para cada grupo coma função fecet_grid
. O argumento scales='free'
permite que a escala do eixo y seja redimensionada independentemente para cada grupo.
ggplot(iris, aes(x = Petal.Length)) +
geom_histogram(color = "black") +
facet_grid(Species ~ ., scales = "free")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
5.6.2 Gráfico de densidade da distribuição
O gráfico de densidade da distribuição é uma versão suavizada do histograma. Para isso, este gráfico utiliza uma linha no lugar de barras (compare com a Figura 5.33).
ggplot(faithful, aes(x = waiting)) +
geom_density()
Uma forma popular de apresentar este gráfico é preenchendo a área abaixo da linha. Isto é possível ajustando o argumento fill
.
ggplot(faithful, aes(x = waiting)) +
geom_density(fill = "green", alpha = 0.5)
5.6.3 Box Plot
O Box plot, também conhecido como diagrama de caixa, representa uma distribuição por meio do resumo de cinco números:
- Limite inferior
- Primeiro quartil
- Mediana
- Terceiro quartil
- Limite superior
A figura abaixo mostra como estes valores formam o gráfico Box plot. A “caixa” (box) tem como limites o 1° e 3° quartis, medida que também é conhecida como Amplitude Interquartil (AIQ). Neste intervalo estão presentes 50% das observações. A linha dentro da caixa representa a mediana. Os “bigodes” (whiskers) se estendem até uma medida predeterminada, que pode ser:
- O mínimo e o máximo entre todos os valores;
- Os valores mais próximos a um limite inferior e um limite superior calculados por: \(L_i=Q_1-c \times AIQ\) e \(L_s=Q_3+c \times AIQ\), em que AIQ é a amplitude interquartil e c é um coeficiente cujo valor padrão é 1,5 21.
Os valores discrepantes, mais extremos que os limites, são plotados como pontos individuais.
O Box plot utiliza a geometria geom_boxplot
. A direção do gráfico (horizontal ou vertical) é ajustada mapeando a variável para o eixo x ou y
ggplot(faithful, aes(y = waiting)) +
geom_boxplot()
ggplot(faithful, aes(x = waiting)) +
geom_boxplot()
Uma utilização bastante comum do Box plot é para comparar diferentes grupos. Para isso, plotamos o Boxplot para cada grupo dentro do mesmo gráfico.
ggplot(mpg, aes(x = class, y = hwy)) +
geom_boxplot()
O argumento coef
ajusta o comprimentos dos bigodes como um múltiplo da AIQ. Por padrão, seu valor é de 1,5. Para que os bigodes se estendam até os valores máximos/mínimos, modificamos o argumento coef
para NULL
. Outros valores numéricos são possíveis para coef
.
ggplot(mpg, aes(x = class, y = hwy)) +
geom_boxplot(coef = NULL)
ggplot(mpg, aes(x = class, y = hwy)) +
geom_boxplot(coef = 2.0)
ggplot(mpg, aes(x = class, y = hwy)) +
geom_boxplot(coef = 1.0)
É possível adicionar uma marca para a média ao Boxplot. Para isso, utilizamos stat_summary
para calcular a média e ajustamos um formato para a marca. O argumento shape=23
adiciona um losango (diamante), já que esse formato é bastante comum na representaçao da média.
ggplot(mpg, aes(x = class, y = hwy)) +
geom_boxplot() +
stat_summary(fun = "mean", shape = 23)