Introdução à Análise de Dados
e
Modelação Estatística

4º trimestre 2024/2025

Pré-requisitos

$

Probabilidade

Estatística

  • Estimação pontual e regional
  • Testes de hipóteses
  • Regressão linear simples

Computação

1 Análise exploratória de dados

Que dados são estes?

Uma população é um conjunto de entidades que têm pelo menos uma característica (variável estatística) em comum.

Exceptuando a realização de censos e casos em que as populações são pequenas não é, em geral, desejável ou mesmo possível conhecer toda a população!

Uma amostra é um conjunto retirado de uma população com o objetivo de a representar.

Notação

\(\mathbf{x}=\left(x_1,\ldots,x_n\right)\) – amostra observada de dimensão \(n\)

\(x_{(1)},\ldots,x_{(n)}\) – amostra observada ordenada por ordem crescente

O que fazer com os dados?

Estatística descritiva

Descrição dos dados recorrendo a:

  • gráficos
  • tabelas
  • medidas numéricas

Estatística inferencial

Uso de dados para aprender algo sobre a população que se admite que representam.

Baseia-se na Teoria da Probabilidade.

Dados multivariados

\(p\) características (variáveis estatísticas) são observadas em \(n\) objetos (unidades estatísticas)

\[\mathbf{X}_{n \times p}=\begin{bmatrix} x_{1,1} & \cdots & x_{1,p} \\ \vdots & \ddots & \vdots \\ x_{n,1} & \cdots & x_{n,p} \\ \end{bmatrix}\]

Tipos de variáveis

\(+\) tempos, datas, coordenadas geográficas, . . .

1.1 Meios computacionais

O é um ambiente de software livre para computação estatística e gráficos que inclui:

  1. uma linguagem de programação com as mais comuns estruturas de programação

  2. uma coleção integrada de ferramentas para análise de dados

O universo

Neste curso vamos usar, de preferência:

  1. <- ou -> – operador de atribuição

    a <- 2 \(\iff\) 2 -> a \(\iff\) a = 2

  1. |> – operador pipe

    a |> f(x, y, . . .) \(\iff\) f(a, x, y, . . .)

  2. pacotes do Tidyverse (ggplot2, dplyr, tidyr, readr, . . .)

Visão geral de uma análise de dados

1.2 Importação de dados

Leitura de dados retangulares

Ficheiros de texto (.txt, .csv)

dados <- readr::read_delim(file, . . .)

         readr::read_csv(file, . . .)
         readr::read_tsv(file, . . .)
         . . .  

Folhas de cálculo (.xls, .xlsx)

dados <- readxl::read_excel(path, sheet = NULL, range = NULL,
                            col_names = TRUE, . . .)

Nota Todas as funções anteriores guardam os dados num tipo de estrutura particular – uma data frame.

Estruturas básicas de dados

  1. Vetores, matrizes e arrays
  2. Data frames
  3. Listas

Nota Para lidar com variáveis categóricas com um número finito e pré-definido de valores, um vetor pode ser codificado como um factor.

Principais tipos de dados

Dados em falta

No , os valores em falta são indicados com NA.

Dados arrumados

Muitos pacotes do requerem dados arrumados (tidy data):

\[\text{1 observação por linha} \times \text{1 variável por coluna}\]

Adicionalmente, cada variável deve ter um nome.

Problemas frequentes:

  1. Nomes das variáveis em falta
  2. Múltiplas variáveis na mesma coluna
  3. Variáveis em linhas e colunas \(\rightarrow\) pivotagem (tidyr)

Distribuição de rendimento entre grupos religiosos nos EUA

file <- "https://web.tecnico.ulisboa.pt/paulo.soares/iadme/dados/pew.txt"
pew <- readr::read_delim(file)

head(pew)
# A tibble: 6 × 11
  religion  `<$10k` `$10-20k` `$20-30k` `$30-40k` `$40-50k` `$50-75k` `$75-100k`
  <chr>       <dbl>     <dbl>     <dbl>     <dbl>     <dbl>     <dbl>      <dbl>
1 Agnostic       27        34        60        81        76       137        122
2 Atheist        12        27        37        52        35        70         73
3 Buddhist       27        21        30        34        33        58         62
4 Catholic      418       617       732       670       638      1116        949
5 Don't kn…      15        14        15        11        10        35         21
6 Evangeli…     575       869      1064       982       881      1486        949
# ℹ 3 more variables: `$100-150k` <dbl>, `>150k` <dbl>,
#   `Don't know/refused` <dbl>
dim(pew)
[1] 18 11
pew_tidy <- pew |> tidyr::pivot_longer(-religion,
                                       names_to = "income",
                                       values_to = "frequency")

head(pew_tidy)
# A tibble: 6 × 3
  religion income  frequency
  <chr>    <chr>       <dbl>
1 Agnostic <$10k          27
2 Agnostic $10-20k        34
3 Agnostic $20-30k        60
4 Agnostic $30-40k        81
5 Agnostic $40-50k        76
6 Agnostic $50-75k       137
dim(pew_tidy)
[1] 180   3

1.3 Manipulação de data frames

musicos <- data.frame(
nome = c("John", "Paul", "George", "Ringo", "Stuart", "Pete"),
instrumento = c("guitarra", "baixo", "guitarra", "bateria",
                "baixo", "bateria"),
banda = c(TRUE, TRUE, TRUE, TRUE, FALSE, FALSE),
valor = 1:6)
str(musicos)
'data.frame':   6 obs. of  4 variables:
 $ nome       : chr  "John" "Paul" "George" "Ringo" ...
 $ instrumento: chr  "guitarra" "baixo" "guitarra" "bateria" ...
 $ banda      : logi  TRUE TRUE TRUE TRUE FALSE FALSE
 $ valor      : int  1 2 3 4 5 6

Filtragem de observações

musicos |> dplyr::filter(instrumento == "guitarra")
nome instrumento banda valor
John guitarra TRUE 1
Paul baixo TRUE 2
George guitarra TRUE 3
Ringo bateria TRUE 4
Stuart baixo FALSE 5
Pete bateria FALSE 6

\[\longrightarrow\]

nome instrumento banda valor
John guitarra TRUE 1
George guitarra TRUE 3

Seleção de variáveis

musicos |> dplyr::select(nome, instrumento)
nome instrumento banda valor
John guitarra TRUE 1
Paul baixo TRUE 2
George guitarra TRUE 3
Ringo bateria TRUE 4
Stuart baixo FALSE 5
Pete bateria FALSE 6

\[\longrightarrow\]

nome instrumento
John guitarra
Paul baixo
George guitarra
Ringo bateria
Stuart baixo
Pete bateria
musicos |> dplyr::select(-where(is.character))
nome instrumento banda valor
John guitarra TRUE 1
Paul baixo TRUE 2
George guitarra TRUE 3
Ringo bateria TRUE 4
Stuart baixo FALSE 5
Pete bateria FALSE 6

\[\longrightarrow\]

banda valor
TRUE 1
TRUE 2
TRUE 3
TRUE 4
FALSE 5
FALSE 6

Transformação de variáveis

musicos |> dplyr::mutate(desempregado = !banda,
                         novo_valor = sqrt(valor))
nome instrumento banda valor desempregado novo_valor
John guitarra TRUE 1 FALSE 1.00
Paul baixo TRUE 2 FALSE 1.41
George guitarra TRUE 3 FALSE 1.73
Ringo bateria TRUE 4 FALSE 2.00
Stuart baixo FALSE 5 TRUE 2.24
Pete bateria FALSE 6 TRUE 2.45
musicos |> dplyr::mutate(nome = paste("Mr.", nome))
nome instrumento banda valor
Mr. John guitarra TRUE 1
Mr. Paul baixo TRUE 2
Mr. George guitarra TRUE 3
Mr. Ringo bateria TRUE 4
Mr. Stuart baixo FALSE 5
Mr. Pete bateria FALSE 6

Agregação e sumariação

musicos |> dplyr::summarise(número = dplyr::n(),
                            .by = instrumento)
instrumento número
guitarra 2
baixo 2
bateria 2
musicos |> dplyr::summarise(média_valor = mean(valor),
                            .by = banda)
banda média_valor
TRUE 2.5
FALSE 5.5

Combinação de data frames

As funções dplyr::bind_rows(x, y) e dplyr::bind_cols(x, y) permitem juntar linhas e colunas de data frames compatíveis.

confiar apenas na posição dos dados pode ser perigoso!

x <- data.frame(
nome = c("John", "Paul", "George", "Ringo", "Stuart", "Pete"),
instrumento = c("guitarra", "baixo", "guitarra", "bateria",
                "baixo", "bateria"))

y <- data.frame(
nome = c("John", "Paul", "George", "Ringo", "Brian"),
banda = c(TRUE, TRUE, TRUE, TRUE, FALSE))

\[x + y = ?\]

 

nome instrumento
John guitarra
Paul baixo
George guitarra
Ringo bateria
Stuart baixo
Pete bateria

\[+\]

nome banda
John TRUE
Paul TRUE
George TRUE
Ringo TRUE
Brian FALSE

\[=\ ?\]

dplyr::left_join(x, y, by = "nome")
nome instrumento
John guitarra
Paul baixo
George guitarra
Ringo bateria
Stuart baixo
Pete bateria

\[+\]

nome banda
John TRUE
Paul TRUE
George TRUE
Ringo TRUE
Brian FALSE

\[=\]

nome instrumento banda
John guitarra TRUE
Paul baixo TRUE
George guitarra TRUE
Ringo bateria TRUE
Stuart baixo NA
Pete bateria NA
dplyr::right_join(x, y, by = "nome")
nome instrumento
John guitarra
Paul baixo
George guitarra
Ringo bateria
Stuart baixo
Pete bateria

\[+\]

nome banda
John TRUE
Paul TRUE
George TRUE
Ringo TRUE
Brian FALSE

\[=\]

nome instrumento banda
John guitarra TRUE
Paul baixo TRUE
George guitarra TRUE
Ringo bateria TRUE
Brian NA FALSE
dplyr::inner_join(x, y, by = "nome")
nome instrumento
John guitarra
Paul baixo
George guitarra
Ringo bateria
Stuart baixo
Pete bateria

\[+\]

nome banda
John TRUE
Paul TRUE
George TRUE
Ringo TRUE
Brian FALSE

\[=\]

nome instrumento banda
John guitarra TRUE
Paul baixo TRUE
George guitarra TRUE
Ringo bateria TRUE
dplyr::full_join(x, y, by = "nome")
nome instrumento
John guitarra
Paul baixo
George guitarra
Ringo bateria
Stuart baixo
Pete bateria

\[+\]

nome banda
John TRUE
Paul TRUE
George TRUE
Ringo TRUE
Brian FALSE

\[=\]

nome instrumento banda
John guitarra TRUE
Paul baixo TRUE
George guitarra TRUE
Ringo bateria TRUE
Stuart baixo NA
Pete bateria NA
Brian NA FALSE

1.4 Estatísticas sumárias

Análise univariada de VN

Dados: \(\mathbf{x}=\left(x_1,\ldots,x_n\right)\in \mathbb{R}^n\)

Quantis

Para \(\alpha \in ]0, 1[\):

\[q_{\alpha} : \left\{\begin{align*} \# \left\{x_i : x_i\leq q_{\alpha} \right\} & \geq n \alpha \\[0.25cm] \# \left\{x_i : x_i\geq q_{\alpha} \right\} & \geq n (1-\alpha) \end{align*}\right.\]

Há diferentes formas de “forçar” a unicidade de um quantil.

\[q_{\alpha} = \left\{\begin{align*} x_{(\lfloor n \alpha \rfloor + 1)}, & & n \alpha \not \in \mathbb{N} \\[0.25cm] \text{interp}\left(x_{(n \alpha)}, x_{(n \alpha + 1)}\right), & & n \alpha \in \mathbb{N} \end{align*}\right.\]

em que \(\text{interp}\left(a, b\right)\) representa um valor em \([a, b]\) obtido por interpolação.

Nota No há 9 tipos de quantis!

Casos particulares:

Moda(s)

Valor ou valores mais frequentes na amostra – mais útil para VND ou VNC agrupadas em classes (classe modal)

Médias aritméticas

\[\bar{\mathbf{x}}_{\mathbf{w}}=\frac{\sum_{i=1}^n w_i x_i}{\sum_{i=1}^n w_i}\]

Se os pesos são todos iguais \(\leadsto\) média aritmética simples

Comparação da média com a mediana

Médias \(\alpha\)–aparadas

Para \(\alpha \in [0, 0.5[\):

\[\bar{\mathbf{x}}_{\alpha}=\frac{1}{n-2m}\sum_{i=m+1}^{n-m}x_{(i)}\]

com \(m=\lfloor n \alpha \rfloor\).

Nota \(\bar{\mathbf{x}}_{0}=\bar{\mathbf{x}}\)

\(\bar{\mathbf{x}}_{\alpha}\underset{\alpha\rightarrow 0.5}{\longrightarrow}\) Mediana

Exemplo

Dados: \(\mathbf{x}= (2, 4, 5, 10, 200)\)

\(\bar{\mathbf{x}} = 44.2\)

\(\text{Mediana}(\mathbf{x}) = 5\)

\(\bar{\mathbf{x}}_{0.2} = 6.333\)

A mediana e as médias aparadas \((\alpha >0)\) são medidas robustas ao contrário da média (ou qualquer outra estatística que dependa da média).

Amplitude

\[\text{R} = x_{(n)} - x_{(1)}\]

Amplitude inter-quartis

\[\text{IQR} = q_{0.75} - q_{0.25}\]

Variância e derivados

\(s^2 = \frac{\sum_{i=1}^n(x_i-\bar{\mathbf{x}})^2}{n-1}= \frac{\sum_{i=1}^n x_i^2 - n\bar{\mathbf{x}}^2}{n-1}\)variância (corrigida)

\(s = \sqrt{s^2}\)desvio-padrão

\(Cv=\frac{s}{|\bar{\mathbf{x}}|}\)coeficiente de variação

MAD

\[\text{MAD}(\mathbf{x}) = \text{Mediana}\left\{|\mathbf{x} - \text{Mediana}(\mathbf{x})|\right\}\]

chama-se o desvio absoluto mediano.

Nota É também usado o MAD normalizado \(\text{MADN}(\mathbf{x})= 1.4826\ \text{MAD}(\mathbf{x})\) que garante que \(E[\text{MADN}(\mathbf{X})]\underset{n\rightarrow + \infty}{\longrightarrow} \sigma\), quando \(X\sim N(\mu, \sigma^2)\).

Análise multivariada de VN

Dados: \(\mathbf{X}=\left(\mathbf{x}_1,\ldots,\mathbf{x}_p\right), \mathbf{x}_i\in \mathbb{R}^n\)

Covariância

\(\begin{align*} s_{i, j} = \text{cov}(\mathbf{x}_i, \mathbf{x}_j) = & \frac{\sum_{k=1}^n\left(x_{k, i} - \bar{\mathbf{x}}_i\right)\left(x_{k, j} - \bar{\mathbf{x}}_j\right)}{n-1}= \\ & =\frac{\sum_{k=1}^n x_{k, i}x_{k, j} - n \bar{\mathbf{x}}_i\bar{\mathbf{x}}_j}{n-1} \end{align*}\)

Matriz de covariâncias: \(\mathbf{S}=\left(s_{i,j}\right)_{p\times p}\)

Propriedades

  1. \(s_{i,j}=s_{j,i}\in \mathbb{R}\)
  1. \(s_{i,i} = s_i^2\)

  2. \(\text{cov}(a_i\mathbf{x}_i + b_i, a_j\mathbf{x}_j + b_j) = a_i a_j \text{cov}(\mathbf{x}_i, \mathbf{x}_j)\)

\(\forall a_i a_j>1 : \text{cov}(a_i\mathbf{x}_i , a_j\mathbf{x}_j) > \text{cov}(\mathbf{x}_i, \mathbf{x}_j)\)

A covariância pode aumentar arbitrariamente apenas com mudanças de escala nas variáveis!

Uma solução possível: estandardizar os dados \[z_i = \frac{x_i-\bar{x}}{s}\]

Coeficiente de correlação linear de Pearson

\[r_{i,j} = \frac{s_{i,j}}{s_i s_j}\]

  1. não é afetado por translações

  2. mudanças de escala apenas podem mudar o seu sinal

  3. \(-1 \leq r_{i,j} \leq 1\)

Matriz de correlações

\[\mathbf{R}=\left(r_{i,j}\right)_{p\times p}=\begin{bmatrix} 1 & r_{1,2} & \cdots & r_{1,p} \\ r_{2,1} & 1 & \cdots & r_{2,p} \\ \vdots & \vdots & \ddots & \vdots \\ r_{p,1} & r_{p,2} & \cdots & 1 \\ \end{bmatrix}\]

Análise de VC

As medidas anteriores não se aplicam a variáveis categorizadas. Neste caso, as frequências têm um papel importante.

Exemplo

# Fuel economy data from 1999 to 2008 for 38 popular models of cars
library(ggplot2)
head(mpg)
# A tibble: 6 × 11
  manufacturer model displ  year   cyl trans      drv     cty   hwy fl    class 
  <chr>        <chr> <dbl> <int> <int> <chr>      <chr> <int> <int> <chr> <chr> 
1 audi         a4      1.8  1999     4 auto(l5)   f        18    29 p     compa…
2 audi         a4      1.8  1999     4 manual(m5) f        21    29 p     compa…
3 audi         a4      2    2008     4 manual(m6) f        20    31 p     compa…
4 audi         a4      2    2008     4 auto(av)   f        21    30 p     compa…
5 audi         a4      2.8  1999     6 auto(l5)   f        16    26 p     compa…
6 audi         a4      2.8  1999     6 manual(m5) f        18    26 p     compa…
tab1 <- with(mpg, table(cyl))
tab1
cyl
 4  5  6  8 
81  4 79 70 
mpg |> summarize(freq = n(), .by = "cyl")
# A tibble: 4 × 2
    cyl  freq
  <int> <int>
1     4    81
2     6    79
3     8    70
4     5     4
barplot(tab1)

O que falta neste gráfico?

tab2 <- prop.table(tab1)
tab2
cyl
     4      5      6      8 
0.3462 0.0171 0.3376 0.2991 
barplot(tab2)

tab3 <- with(mpg, table(cyl, class))
tab3
   class
cyl 2seater compact midsize minivan pickup subcompact suv
  4       0      32      16       1      3         21   8
  5       0       2       0       0      0          2   0
  6       0      13      23      10     10          7  16
  8       5       0       2       0     20          5  38
addmargins(tab3, 1:2)
     class
cyl   2seater compact midsize minivan pickup subcompact suv Sum
  4         0      32      16       1      3         21   8  81
  5         0       2       0       0      0          2   0   4
  6         0      13      23      10     10          7  16  79
  8         5       0       2       0     20          5  38  70
  Sum       5      47      41      11     33         35  62 234
barplot(tab3)

O que falta neste gráfico?

tab4 <- prop.table(tab3)
addmargins(tab4, 1:2)
     class
cyl   2seater compact midsize minivan  pickup subcompact     suv     Sum
  4   0.00000 0.13675 0.06838 0.00427 0.01282    0.08974 0.03419 0.34615
  5   0.00000 0.00855 0.00000 0.00000 0.00000    0.00855 0.00000 0.01709
  6   0.00000 0.05556 0.09829 0.04274 0.04274    0.02991 0.06838 0.33761
  8   0.02137 0.00000 0.00855 0.00000 0.08547    0.02137 0.16239 0.29915
  Sum 0.02137 0.20085 0.17521 0.04701 0.14103    0.14957 0.26496 1.00000
tab5 <- prop.table(tab3, 2)
addmargins(tab5, 1)
     class
cyl   2seater compact midsize minivan pickup subcompact    suv
  4    0.0000  0.6809  0.3902  0.0909 0.0909     0.6000 0.1290
  5    0.0000  0.0426  0.0000  0.0000 0.0000     0.0571 0.0000
  6    0.0000  0.2766  0.5610  0.9091 0.3030     0.2000 0.2581
  8    1.0000  0.0000  0.0488  0.0000 0.6061     0.1429 0.6129
  Sum  1.0000  1.0000  1.0000  1.0000 1.0000     1.0000 1.0000

1.5 Gráficos com o ggplot

ggplot(data) +
  geom_xxxx(aes(...), ...) +
  geom_yyyy(aes(...), ...) + 
  ...
ggplot() +
  geom_xxxx(aes(...), data = ..., ...) +
  geom_yyyy(aes(...), data = ..., ...) + 
  ...
ggplot(mpg) +
  geom_bar(aes(x = cyl))

O que está errado neste gráfico?

mpg$cyl_f <- as.factor(mpg$cyl)
ggplot(mpg) +
  geom_bar(aes(x = cyl_f))

dados <- mpg |> summarise(freq = n(), .by = c(cyl_f, class))
ggplot(dados) +
  geom_col(aes(x = class, y = freq,  fill = cyl_f))

ggplot(mpg) +
  geom_histogram(aes(x = cty))

O que pode ser melhorado neste gráfico?

nbins <- nclass.Sturges(mpg$cty)
ggplot(mpg) +
  geom_histogram(aes(x = cty, y= after_stat(density)),
                 bins = nbins, fill = "darkorange")

ggplot(mpg) +
  geom_boxplot(aes(x = cty))

ggplot(mpg) +
  geom_point(aes(x = displ, y = hwy))

ggplot(mpg) +
  geom_point(aes(x = displ, y = hwy, color = class))

ggplot(mpg) +
  geom_point(aes(x = displ, y = hwy, color = class),
             position = position_jitter(width = 0.1,
                                        height = 0))

ggplot(mpg) +
  geom_boxplot(aes(x = class, y = hwy), fill = "hotpink")

ggplot(mpg) +
  geom_boxplot(aes(x = reorder(class, hwy), y = hwy),
               fill = "hotpink")

1.6 Deteção de observações potencialmente atípicas

A existência de observações atípicas ou discordantes pode influenciar fortemente uma análise estatística.

Caso univariado

  1. z-scores

    Clássicos: \(z_i=\frac{x_i-\bar{\mathbf{x}}}{s}\)

    Robustos: \(z_i^r=\frac{x_i-\text{Mediana}(\mathbf{x})}{\text{MADN}(\mathbf{x})}\)

    \(|z_i^*| > 3 \leadsto\) potencial observação atípica

  1. quartis

    \(x_i > q_{0.75} + k \times \text{IQR}\) ou \(x_i < q_{0.25} - k \times \text{IQR}\leadsto\) potencial observação atípica

    Num boxplot é usual \(k=1.5\), como vimos atrás.

Caso multivariado

Com uma amostra multivariada não basta analisar cada variável separadamente.

Distância de Mahalanobis à média

\[D(\mathbf{x}) = \sqrt{(\mathbf{x} - \bar{\mathbf{x}})'S^{-1}(\mathbf{x} - \bar{\mathbf{x}})}\]

Teorema Se \(\mathbf{X} \sim N_p (\mu, \Sigma)\) então \(D^2(\mathbf{X}) \sim\chi_{(p)}^2\).

\(D^2(\mathbf{x}_i)> F_{\chi_{(p)}^2}^{-1}(k) \leadsto\) potencial observação atípica

menu
fullscreen
aspect_ratio
visibility_off
zoom_out
zoom_in
grid_view

pages