---
title: "Análise descritiva"
subtitle: "Aula 4"
author: "Bruno Montezano"
institute: "Grupo Alliance
Programa de Pós-Graduação em Psiquiatria e Ciências do Comportamento
Universidade Federal do Rio Grande do Sul"
date: last-modified
date-format: long
lang: pt-br
execute:
echo: true
format:
revealjs:
incremental: true
smaller: true
theme: [default, ../assets/custom.scss]
logo: "../assets/logo_ufrgs.png"
---
## Conteúdo de hoje
- Medidas de tendência central
- Medidas de dispersão
- Medidas de assimetria e curtose
- Distribuição normal
- Transformação de dados
- Tabelas de frequência
## Dados dos `pinguins`
::: columns
::: {.column width="70%"}
Hoje nós usaremos os dados dos `pinguins` do pacote `dados`.
Este conjunto de dados contém 14 variáveis de 344 observações de pinguins adultos
perto da Estação Palmer na Antártida.
Os dados incluem a espécies de pinguins e ilhas do Arquipélago Palmer,
medidas de cada espécie, sexo do pinguim e ano de documentação.
:::
::: {.column width="30%"}
![](../assets/logo_penguins.png)
:::
:::
## `pinguins`
```{r glimpse-pinguins}
library(dados)
library(tidyverse)
glimpse(pinguins)
```
```{r printar-pinguins}
pinguins
```
## Revisão de conceitos matemáticos
![](../assets/meme_revisao_matematica.jpg){fig-align="center" width=45%}
## Variáveis
**Variáveis** são símbolos que representam conjuntos de um ou mais **elementos**
que podem assumir qualquer quantidade de valores.
::: {.nonincremental}
- Letras como $x$, $y$ e $z$ são comumente usadas para indicar variáveis
- Por exemplo: $x = 3$
:::
. . .
::: {.nonincremental}
- Letras maiúsculas ($X$) ou letras com um índice ($x_i$) referem-se a variáveis
com múltiplos valores — ou seja, com dimensões
- Por exemplo: $X = x_i = (15, 16, 32)$
- Variáveis com uma dimensão (comprimento) são chamadas de **vetor**
:::
. . .
::: {.nonincremental}
- Variáveis como $x_i$ são usadas para **indexar** elementos de vetores
- $i$ é uma variável que indica a posição indexada
- Por exemplo: $x_1 = 15, x_2 = 16, x_3 = 32$
:::
## Somatório
$$\sum_{i=1}^{n}x_i$$
"Soma de todos os valores de $x$ do primeiro ($i = 1$) até o último ($n$)"
. . .
Dado $x = [9, 12, 12, 14, 27]$:
$$\sum_{i=1}^{n}x_i = x_1 + x_2 + x_3 + x_4 + x_5 = 9 + 12 + 12 + 14 + 27 = 74$$
. . .
```{r soma-x}
x <- c(9, 12, 12, 14, 27)
sum(x)
```
É comum ao somar todos os elementos de um vetor, omitirmos os sobrescritos e subscritos,
por exemplo: $\sum{x_i} = \sum_{i=1}^{n}x_i$
## Medidas de tendência central
![](../assets/meme_medidas_tendencia_central.jpg){fig-align="center" width=85%}
## Média
A média (aritmética) é o *valor esperado* de uma variável.
$$\bar{x} = \frac{1}{n}\sum_{i=1}^{n}x_{i}$$
. . .
Se você extrair elementos aleatoriamente dessa variável, a média seria o chute menos errado
que você poderia fazer sobre esse valor^[Tecnicamente, a média
minimiza o *erro quadrático*.].
Dito de outra forma, as diferenças positivas e negativas entre todos os valores e a média
equivalem entre si.
. . .
```{r calcular-media-massa-corporal}
pinguins |>
summarise(media_massa = mean(massa_corporal, na.rm = TRUE),
media_comprimento_bico = mean(comprimento_bico, na.rm = TRUE))
```
## Mediana
O valor para o qual não mais da metade dos
valores é superior ou inferior^[Tecnicamente, a mediana minimiza o erro absoluto].
. . .
A **mediana** tem essa fórmula esquisita:
$$m(x_i) = \begin{cases} x_{\frac{n+1}{2}},& \text{se } n \text{ ímpar}\\ \frac{1}{2}(x_{\frac{n}{2}} + x_{\frac{n}{2} + 1}), &\text{se } n \text{ par}\end{cases}$$
"Se $x$ tem um número ímpar de elementos, ao colocá-los em ordem, a mediana é o valor do meio. Se $x$ tem um número par de elementos, a mediana é a média dos dois valores do meio".
. . .
```{r calcular-mediana-massa-corporal}
pinguins |>
summarise(mediana_massa = median(massa_corporal, na.rm = TRUE),
mediana_comprimento_bico = median(comprimento_bico, na.rm = TRUE))
```
## Moda
A **moda** é o valor mais **frequente** na variável.
. . .
Existem fórmulas para a moda, mas elas não são nada intuitivas, apesar da moda
ser a medida de tendência central mais intuitiva.
. . .
Vocês podem usar `count()` para ver a frequência de valores:
```{r funcao-count-especie}
pinguins |>
count(especie)
```
. . .
E vocês podem achar a moda diretamente com um `filter()`:
```{r achar-moda-especie}
pinguins |>
count(especie) |>
filter(n == max(n))
```
## Valores extremos
A média é sensível a valores extremos:
```{r outliers}
z <- c(2, 5, 3, 5, 105)
mean(z)
```
. . .
A mediana não é:
```{r mediana-outlier}
median(z)
```
. . .
Isso significa que a mediana pode ser uma "média" mais útil quando os dados
têm valores extremos.
Isto é comum com variáveis como renda e números de episódios auto-relatados.
## Medidas de dispersão
![](../assets/meme_variancia.jpg){fig-align="center" width=65%}
## Variância
A variância mede como os dados estão dispersos em torno da média.
Normalmente usamos a variância *amostral*:
$$
s^2 = \frac{\sum (x_i - \bar{x})^2}{n - 1}
$$
. . .
```{r variancia-massa-corporal}
pinguins |>
filter(!is.na(massa_corporal)) |>
summarise(variancia_na_mao_massa = sum(
(massa_corporal - mean(massa_corporal))^2 /
(length(massa_corporal) - 1)),
variancia_massa = var(massa_corporal)
)
```
. . .
Se todos os valores são iguais, a variância é *zero*.
## Desvio padrão
O desvio padrão ($s$ ou $sd$, ou $dp$ em português) é simplesmente a raíz quadrada
da variância:
$$s = \sqrt{s^2}$$
. . .
Você pode interpretar como a distância "típica" dos valores em relação à média.
. . .
```{r desvio-padrao-massa-corporal}
pinguins |>
filter(!is.na(massa_corporal)) |>
summarise(desvio_padrao_na_mao_massa = sqrt(var(massa_corporal)),
desvio_padrao_massa = sd(massa_corporal)
)
```
. . .
O desvio padrão se apresenta na mesma unidade de medida da variável.
## Amplitude
A amplitude ($R$) é a medida de dispersão mais fácil de calcular. Nós subtraímos
o menor valor ($L$) do maior valor ($H$) da variável.
$$R = H - L$$
. . .
```{r amplitude-massa}
pinguins |>
filter(!is.na(massa_corporal)) |>
summarise(
massa_max = max(massa_corporal),
massa_min = min(massa_corporal),
massa_amplitude = max(massa_corporal) - min(massa_corporal)
)
```
## Intervalo interquartil
O intervalo interquartil representa a diferença entre o primeiro quartil (o 25º
percentil) e o terceiro quartil (o 75º percentil) de um conjunto de dados.
$$IQR = Q_3 - Q_1$$
. . .
Em termos simples, o quão distantes estão os 50% valores do meio da variável.
. . .
```{r intervalo-interquartil-massa}
pinguins |>
filter(!is.na(massa_corporal)) |>
summarise(
intervalo_interquartil_massa = IQR(massa_corporal),
primeiro_quartil = quantile(massa_corporal)["25%"],
terceiro_quartil = quantile(massa_corporal)["75%"]
)
```
## Distribuição normal
A distribuição normal é uma das distribuições mais importantes em
estatística.
* Também conhecida como distribuição de Gauss, é frequentemente
usada para modelar fenômenos naturais
* Muitos testes estatísticos assumem
que os dados seguem uma distribuição normal
* 68% dos dados estão dentro de um desvio padrão da média,
95% estão dentro de dois desvios padrão e 99,7% estão dentro de três
desvios padrão
. . .
```{r plot-distribuicao-normal}
#| fig-align: "center"
#| out.width: "60%"
#| echo: false
# Gerando uma amostra aleatória de uma distribuição normal padrão
set.seed(123)
amostra <- rnorm(1000)
# Calculando a média e o desvio padrão da amostra
media <- mean(amostra)
desvio_padrao <- sd(amostra)
# Criando um data frame com os limites das proporções 68-95-99
proporcoes <- data.frame(
limite_inf = c(
media - desvio_padrao,
media - 2 * desvio_padrao,
media - 3 * desvio_padrao,
media - 4 * desvio_padrao
),
limite_sup = c(
media + desvio_padrao,
media + 2 * desvio_padrao,
media + 3 * desvio_padrao,
media + 4 * desvio_padrao
),
proporcao = c(0.6826, 0.9544, 0.9972, 0.9998)
)
# Criando o histograma
ggplot(data.frame(x = amostra), aes(x)) +
geom_rect(xmin = -1,
xmax = 1,
ymin = 0,
ymax = 250,
fill = "tan1",
alpha = 0.2) +
geom_rect(xmin = -1,
xmax = -2,
ymin = 0,
ymax = 250,
fill = "gold",
alpha = 0.2) +
geom_rect(xmin = 1,
xmax = 2,
ymin = 0,
ymax = 250,
fill = "gold",
alpha = 0.2) +
geom_rect(xmin = 2,
xmax = 3,
ymin = 0,
ymax = 250,
fill = "pink",
alpha = 0.2) +
geom_rect(xmin = -2,
xmax = -3,
ymin = 0,
ymax = 250,
fill = "pink",
alpha = 0.2) +
geom_rect(xmin = 3,
xmax = 4,
ymin = 0,
ymax = 250,
fill = "palegreen",
alpha = 0.2) +
geom_rect(xmin = -3,
xmax = -4,
ymin = 0,
ymax = 250,
fill = "palegreen",
alpha = 0.2) +
geom_vline(
xintercept = c(proporcoes$limite_inf, proporcoes$limite_sup),
color = rep("grey30", 8),
linetype = rep("dashed", 8),
size = rep(1, 8),
alpha = rep(1, 8)
) +
geom_histogram(bins = 20,
color = "black",
fill = "lightblue") +
geom_vline(
xintercept = media,
color = "grey20",
linetype = "solid",
size = 1
) +
annotate("text", label = "34,13%",
x = -0.5, y = 240,
size = 4.5, family = "Charter") +
annotate("text", label = "34,13%",
x = 0.5, y = 240,
size = 4.5, family = "Charter") +
annotate("text", label = "13,59%",
x = 1.5, y = 240,
size = 4.5, family = "Charter") +
annotate("text", label = "13,59%",
x = -1.5, y = 240,
size = 4.5, family = "Charter") +
annotate("text", label = "2,14%",
x = 2.5, y = 240,
size = 4.5, family = "Charter") +
annotate("text", label = "2,14%",
x = -2.5, y = 240,
size = 4.5, family = "Charter") +
annotate("text", label = "0,13%",
x = 3.5, y = 240,
size = 4.5, family = "Charter") +
annotate("text", label = "0,13%",
x = -3.5, y = 240,
size = 4.5, family = "Charter") +
scale_x_continuous(
breaks = -4:4,
limits = c(-4.5, 4.5),
labels = c(
latex2exp::TeX("$\\mu - 4\\sigma$"),
latex2exp::TeX("$\\mu - 3\\sigma$"),
latex2exp::TeX("$\\mu - 2\\sigma$"),
latex2exp::TeX("$\\mu - \\sigma$"),
latex2exp::TeX("$\\mu$"),
latex2exp::TeX("$\\mu + \\sigma$"),
latex2exp::TeX("$\\mu + 2\\sigma$"),
latex2exp::TeX("$\\mu + 3\\sigma$"),
latex2exp::TeX("$\\mu + 4\\sigma$")
)
) +
scale_y_continuous(limits = c(0, 250)) +
theme_classic(base_size = 16, base_family = "Charter") +
labs(x = "Valores da amostra", y = "Frequência")
```
## Como testar normalidade?
Em muitos casos, é necessário verificar se uma amostra segue uma distribuição
normal antes de aplicar determinados testes estatísticos.
* O teste de Shapiro-Wilk é um teste de normalidade que verifica se uma amostra segue uma distribuição normal
* Se o $p$-valor do teste for menor do que o nível de significância (geralmente 0,05), rejeita-se a hipótese nula e conclui-se que a amostra não segue uma distribuição normal
. . .
::: columns
::: {.column width="50%"}
```{r shapiro-amostra-simulada}
# Exemplo de distribuição normal
# Amostra de 500 sujeitos
# com média de 175cm e 10cm de desvio padrão
alturas_adultos <- rnorm(n = 500,
mean = 175,
sd = 10)
shapiro.test(alturas_adultos)
```
:::
::: {.column width="50%"}
```{r shapiro-massa-pinguins}
# Exemplo de variável que não segue uma
# distribuição normal
pinguins |>
pull(massa_corporal) |>
shapiro.test()
```
:::
:::
## Assimetria
A assimetria mede o quão assimétrica é uma distribuição. Pode assumir valores
positivos ou negativos. A média, mediana e moda em geral *não* são iguais em
distribuições assimétricas
* Uma assimetria negativa indica que a cauda está no lado esquerdo da
distribuição
* Uma assimetria
positiva indica que a cauda está no lado direito da distribuição
* Um valor de zero indica que não há assimetria na
distribuição
## Exemplo de distribuição assimétrica
```{r histograma-distribuicao-assimetrica}
#| fig-align: "center"
#| out.width: "65%"
#| echo: false
set.seed(1)
tibble(x = rchisq(1000, 10)) |>
ggplot() +
aes(x = x) +
geom_histogram() +
labs(x = "Valores", y = "Frequência",
title = "De que lado a cauda se encontra?",
subtitle = "Um exemplo de assimetria positiva.") +
geom_segment(x = 32, xend = 25, y = 75, yend = 40,
arrow = arrow(length = unit(0.5, "cm")),
color = "steelblue4",
size = 2) +
ggthemes::theme_clean(base_size = 16, base_family = "Charter")
```
## Curtose
Curtose é a medida da forma da distribuição em relação à sua média.
* A curtose de uma distribuição normal é 3
* Se uma dada distribuição tem uma curtose menor que 3, ela é chamada de platicúrtica
* Se uma dada distribuição tem uma curtose maior que 3, diz-se que é leptocúrtica
. . .
*Quanto maior a curtose, maior a propensão a outliers.*
## Visualizando a curtose
```{r exemplo-curtose}
#| fig-align: "center"
#| out.width: "100%"
#| echo: false
set.seed(1)
alta_curtose <- tibble(valores = rnorm(1000, mean = 0, sd = 1) * 5,
curtose = "Alta")
baixa_curtose <- tibble(valores = rnorm(1000, mean = 0, sd = 2),
curtose = "Baixa")
dados_curtose <- bind_rows(alta_curtose, baixa_curtose)
dados_curtose |>
ggplot() +
geom_histogram(aes(x = valores, fill = curtose), alpha = 0.5) +
labs(title = "Comparação de alta e baixa curtose", x = "Valores",
y = "Frequência", fill = "Curtose") +
ggsci::scale_fill_lancet() +
theme_bw(base_size = 16, base_family = "Charter")
```
## Medidas de assimetria e curtose
Tanto a assimetria quanto a curtose podem ser calculados com funções do
pacote `moments`.
::: columns
::: {.column width="50%"}
```{r calcular-assimetria-massa}
library(moments)
pinguins |>
pull(massa_corporal) |>
skewness(na.rm = TRUE)
```
:::
::: {.column width="50%"}
```{r calcular-curtose-massa}
pinguins |>
pull(massa_corporal) |>
kurtosis(na.rm = TRUE)
```
:::
:::
. . .
```{r histograma-massa-corporal}
#| echo: false
#| fig-align: "center"
#| out.width: "75%"
pinguins |>
filter(!is.na(massa_corporal)) |>
ggplot(aes(x = massa_corporal)) + geom_histogram(fill = "brown") +
labs(x = "Massa corporal (em gramas)", y = "Frequência") +
ggthemes::theme_clean(base_size = 16, base_family = "Charter")
```
## Transformação de dados
Em alguns casos, os dados podem apresentar distribuições muito distorcidas, o
que pode afetar a validade dos testes estatísticos aplicados.
. . .
Para resolver esse problema, uma solução comum é aplicar uma transformação aos dados para deixá-los mais próximos de uma distribuição normal.
. . .
```{r plot-transformacao-de-dados}
#| fig-align: "center"
#| out.width: "70%"
#| echo: false
library(patchwork)
set.seed(123)
amostra <- rexp(10000)
original <- ggplot(data.frame(x = amostra), aes(x)) +
geom_histogram(bins = 20, color = "black", fill = "lightblue") +
labs(title = "Distribuição Original", y = "", x = "") +
theme_minimal(base_size = 14, base_family = "Charter")
amostra_log <- log10(amostra)
logaritmo <- ggplot(data.frame(x = amostra_log), aes(x)) +
geom_histogram(bins = 20, color = "black", fill = "lightgreen") +
labs(title = "Transformação logarítmica", x = "", y = "") +
theme_minimal(base_size = 14, base_family = "Charter")
amostra_sqrt <- sqrt(amostra)
raiz_quadrada <- ggplot(data.frame(x = amostra_sqrt), aes(x)) +
geom_histogram(aes(y = ..density..), bins = 20, color = "black", fill = "darksalmon") +
labs(title = "Transformação raíz quadrada", x = "", y = "") +
theme_minimal(base_size = 14, base_family = "Charter")
amostra_raiz_cubica <- amostra^(1/3)
raiz_cubica <- ggplot(data.frame(x = amostra_raiz_cubica), aes(x)) +
geom_histogram(aes(y = ..density..), bins = 20, color = "black", fill = "aquamarine") +
labs(title = "Transformação raíz cúbica", x = "", y = "") +
theme_minimal(base_size = 14, base_family = "Charter")
((original + logaritmo) / (raiz_quadrada + raiz_cubica)) +
plot_annotation(title = "Dados simulados de 10.000 observações",
theme = theme(text = element_text(family = "Charter", size = 16)))
```
## Transformando a `massa_corporal`
::: columns
::: {.column width="50%"}
```{r histograma-massa-corporal-dois}
#| fig-align: "center"
#| out.width: "100%"
pinguins |>
ggplot(aes(x = massa_corporal)) +
geom_histogram(fill = "coral2") +
labs(x = "Massa corporal (em gramas)",
y = "Frequência") +
theme_bw(base_size = 16,
base_family = "Charter")
```
:::
::: {.column width="50%"}
```{r log-massa-corporal}
pinguins |>
mutate(massa_log = log10(massa_corporal)) |>
ggplot(aes(x = massa_log)) +
geom_histogram(fill = "deepskyblue4") +
labs(x = "Log da massa corporal",
y = "Frequência") +
theme_bw(base_size = 16,
base_family = "Charter")
```
:::
:::
## Tabelas de frequência
A função `count()` do pacote `dplyr` pode ser usada para
contar valores (frequência) a partir de uma ou mais
variáveis.
. . .
```{r exemplo-basico-count}
pinguins |>
count(especie)
```
. . .
```{r tabulacao-cruzada-count}
pinguins |>
count(especie, ilha)
```
## Tabelas de frequência com `janitor()`
O pacote `janitor` oferece uma função `tabyl()` para produzir tabulações e
tabulações cruzadas, que podem ser modificadas para exibir porcentagens,
proporções, etc.
. . .
```{r exemplo-basico-tabyl}
library(janitor)
pinguins |>
tabyl(especie)
```
. . .
```{r tabulacao-cruzada-tabyl}
pinguins |>
tabyl(especie, ilha)
```
## Funções de enfeite do `janitor`
Função|Desfecho
-----|-----:
`adorn_totals()`|Adicionar totais.
`adorn_percentages()`|Converter contagens para proporções.
`adorn_pct_formatting()`|Converte proporções para porcentagens.
`adorn_rounding()`|Arredondar proporções com `digits =`.
`adorn_ns()`|Adicionar contagens a uma tabela de proporções ou porcentagens.
`adorn_title()`|Adicionar título da linha e coluna.
## Exemplo de tabela cruzada
::: {.panel-tabset}
## Básica
```{r tabyl-simples}
pinguins |>
tabyl(especie, ilha)
```
## Totais e porcentagens
```{r totais-porcentagens}
pinguins |>
tabyl(especie, ilha) |>
adorn_totals(where = "row") |>
adorn_percentages(denominator = "col") |>
adorn_pct_formatting(digits = 1)
```
## Completa
```{r tabyl-completa}
pinguins |>
tabyl(especie, ilha) |>
adorn_totals(where = "row") |>
adorn_percentages(denominator = "col") |>
adorn_pct_formatting() |>
adorn_ns(position = "front") |>
adorn_title(
row_name = "Espécie",
col_name = "Ilha")
```
## Salvando em Word
```{r tabyl-em-word}
#| eval: false
pinguins |>
tabyl(especie, ilha) |>
adorn_totals(where = "row") |>
adorn_percentages(denominator = "col") |>
adorn_pct_formatting() |>
adorn_ns(position = "front") |>
adorn_title(
row_name = "Espécie",
col_name = "Ilha",
placement = "combined") |>
flextable::flextable() |>
flextable::save_as_docx(path = "tabela_especie_ilha.docx")
```
![](../assets/tabyl_exportada.png){fig-align="center" width=50%}
:::
## Tarefa de casa
* Para a tarefa de casa, vamos seguir usando a base `pinguins` do pacote `dados`.
1. Filtre a base para manter apenas as observações do ano de 2009.
2. Verifique se a variável `comprimento_bico` da base de
dados segue uma distribuição normal através de um histograma
e um teste de normalidade de Shapiro-Wilk.
3. Com a função `count()`, verifique a frequência da
variável `sexo` na base de dados.
4. Com a função `summarise()`, calcule a média, mediana e
desvio padrão da variável `comprimento_nadadeira`.
* Dica de leitura: Capítulos 4 e 5 do livro
[Introduction to Modern Statistics](https://openintro-ims.netlify.app/).