Este relatório reúne, em abas, os cinco itens pedidos no exercício: manipulação de dados, tabela interativa, equações em LaTeX, figuras e referências bibliográficas.

Relatório

1) Manipulação de Dados

1.1 Pacotes

Usamos o palmerpenguins (que traz os dados), o dplyr e o DT para a tabela interativa da aba 2.

# install.packages(c("palmerpenguins", "dplyr", "DT"))  # rodar uma vez, se preciso
library(palmerpenguins)
library(dplyr)
library(DT)

1.2 Carregando o conjunto de dados

O conjunto penguins reúne medidas de pinguins coletadas entre 2007 e 2009 na Estação Palmer, na Antártida, por Gorman et al. (2014). Cada linha é um pinguim, e as colunas descrevem a espécie, a ilha onde ele vive, o sexo e medidas do corpo.

dados <- penguins
dim(dados)
## [1] 344   8
head(dados)
## # A tibble: 6 × 8
##   species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
##   <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
## 1 Adelie  Torgersen           39.1          18.7               181        3750
## 2 Adelie  Torgersen           39.5          17.4               186        3800
## 3 Adelie  Torgersen           40.3          18                 195        3250
## 4 Adelie  Torgersen           NA            NA                  NA          NA
## 5 Adelie  Torgersen           36.7          19.3               193        3450
## 6 Adelie  Torgersen           39.3          20.6               190        3650
## # ℹ 2 more variables: sex <fct>, year <int>

O conjunto tem 344 pinguins e 8 variáveis:

Variável Significado
species Espécie (Adelie, Chinstrap ou Gentoo)
island Ilha do arquipélago (Biscoe, Dream ou Torgersen)
bill_length_mm Comprimento do bico (mm)
bill_depth_mm Profundidade (altura) do bico (mm)
flipper_length_mm Comprimento da nadadeira (mm)
body_mass_g Massa corporal (g)
sex Sexo (female ou male)
year Ano da coleta

Vemos a estrutura com str(): species, island e sex são fatores (variáveis categóricas) e as medidas são numéricas.

str(dados)
## tibble [344 × 8] (S3: tbl_df/tbl/data.frame)
##  $ species          : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ island           : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ bill_length_mm   : num [1:344] 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
##  $ bill_depth_mm    : num [1:344] 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
##  $ flipper_length_mm: int [1:344] 181 186 195 NA 193 190 181 195 193 190 ...
##  $ body_mass_g      : int [1:344] 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
##  $ sex              : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
##  $ year             : int [1:344] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...

1.3 Valores ausentes (NA)

Contamos os NA em cada coluna:

colSums(is.na(dados))
##           species            island    bill_length_mm     bill_depth_mm 
##                 0                 0                 2                 2 
## flipper_length_mm       body_mass_g               sex              year 
##                 2                 2                11                 0

São 19 valores ausentes no total. Há duas situações:

  • 2 pinguins não têm nenhuma medida corporal (bico, nadadeira e massa estão todos vazios);
  • 11 pinguins não têm o sexo registrado (os 2 pinguins sem medidas também estão nesse grupo).

Como as análises seguintes comparam medidas e sexo, removemos as linhas com algum NA. Com filter() e if_all() mantemos só as linhas em que nenhuma coluna está vazia:

completos <- dados %>%
  filter(if_all(everything(), ~ !is.na(.x)))

nrow(dados) - nrow(completos)   # linhas removidas
## [1] 11
sum(is.na(completos))           # NAs restantes
## [1] 0

Como os 2 pinguins sem medidas também não têm sexo, os NA se concentram em apenas 11 linhas, que foram removidas (3.2% do total), restando 333 pinguins sem nenhum NA.

1.4 Criação de novas variáveis (mutate)

Agora criamos variáveis novas e traduzimos os rótulos para o português:

  • especie, ilha e sexo: colunas categóricas com nomes em português
  • massa_kg: massa em quilogramas;
  • razao_bico: comprimento ÷ profundidade do bico. Valores altos indicam bicos longos e finos; valores baixos, bicos curtos e altos;
  • porte: classificação da massa em faixas (Pequeno < 3,5 kg ≤ Médio < 4,75 kg ≤ Grande), feita com case_when e transformada em fator com os níveis na ordem certa;
  • massa_z: massa padronizada dentro da espécie (escore-z). Ela diz se o pinguim é mais pesado ou mais leve que a média da sua própria espécie, usando group_by() antes do mutate().
pinguins <- completos %>%
  mutate(
    especie    = species,
    ilha       = island,
    sexo       = recode(sex, female = "Fêmea", male = "Macho"),
    massa_kg   = body_mass_g / 1000,
    razao_bico = round(bill_length_mm / bill_depth_mm, 2),
    porte      = factor(case_when(
      massa_kg < 3.5  ~ "Pequeno",
      massa_kg < 4.75 ~ "Médio",
      TRUE            ~ "Grande"),
      levels = c("Pequeno", "Médio", "Grande")
    )
  ) %>%
  group_by(especie) %>%
  mutate(massa_z = round((massa_kg - mean(massa_kg)) / sd(massa_kg), 2)) %>%
  ungroup() %>%
  select(especie, ilha, sexo, ano = year,
         bico_comp = bill_length_mm, bico_prof = bill_depth_mm,
         nadadeira = flipper_length_mm, massa_kg, razao_bico, porte, massa_z)

head(pinguins)
## # A tibble: 6 × 11
##   especie ilha     sexo    ano bico_comp bico_prof nadadeira massa_kg razao_bico
##   <fct>   <fct>    <fct> <int>     <dbl>     <dbl>     <int>    <dbl>      <dbl>
## 1 Adelie  Torgers… Macho  2007      39.1      18.7       181     3.75       2.09
## 2 Adelie  Torgers… Fêmea  2007      39.5      17.4       186     3.8        2.27
## 3 Adelie  Torgers… Fêmea  2007      40.3      18         195     3.25       2.24
## 4 Adelie  Torgers… Fêmea  2007      36.7      19.3       193     3.45       1.9 
## 5 Adelie  Torgers… Macho  2007      39.3      20.6       190     3.65       1.91
## 6 Adelie  Torgers… Fêmea  2007      38.9      17.8       181     3.62       2.19
## # ℹ 2 more variables: porte <fct>, massa_z <dbl>

A nova tabela pinguins tem 11 colunas com nomes em português.

Veja como a razao_bico separa as espécies. A média por espécie é:

pinguins %>%
  group_by(especie) %>%
  summarise(razao_media = round(mean(razao_bico), 2))
## # A tibble: 3 × 2
##   especie   razao_media
##   <fct>           <dbl>
## 1 Adelie           2.12
## 2 Chinstrap        2.65
## 3 Gentoo           3.18

Os Gentoo têm a maior razão (3.18), ou seja, bicos longos e finos, enquanto os Adelie têm a menor (2.12), com bicos curtos e altos. Uma única variável criada já diferencia bem as espécies.

1.5 Filtragem (filter)

Filtro 1: fêmeas mais pesadas que a média da sua espécie (massa padronizada maior que 0). Comparamos com o mesmo filtro para os machos:

femeas_acima <- pinguins %>%
  filter(sexo == "Fêmea", massa_z > 0)

machos_acima <- pinguins %>%
  filter(sexo == "Macho", massa_z > 0)

femeas_acima %>% count(especie)
## # A tibble: 3 × 2
##   especie       n
##   <fct>     <int>
## 1 Adelie        8
## 2 Chinstrap     6
## 3 Gentoo        4
nrow(femeas_acima)
## [1] 18
nrow(machos_acima)
## [1] 140

Só 18 fêmeas ficam acima da média da sua espécie, contra 140 machos. Como a média de cada espécie mistura os dois sexos, quase só os machos ficam acima dela, o que já indica que eles são mais pesados.

Filtro 2: pinguins Adelie das ilhas Dream ou Torgersen com nadadeira de pelo menos 195 mm, usando o operador %in% para testar várias ilhas de uma vez:

adelie_nadadeira <- pinguins %>%
  filter(especie == "Adelie",
         ilha %in% c("Dream", "Torgersen"),
         nadadeira >= 195)

adelie_nadadeira %>% count(ilha)
## # A tibble: 2 × 2
##   ilha          n
##   <fct>     <int>
## 1 Dream        12
## 2 Torgersen    18

Dos 102 Adelie que vivem nessas duas ilhas, 30 (29.4%) têm nadadeira de 195 mm ou mais.

1.6 Ordenação (arrange)

Os 5 pinguins mais pesados do conjunto:

pinguins %>%
  arrange(desc(massa_kg)) %>%
  select(especie, sexo, ilha, nadadeira, massa_kg) %>%
  head(5)
## # A tibble: 5 × 5
##   especie sexo  ilha   nadadeira massa_kg
##   <fct>   <fct> <fct>      <int>    <dbl>
## 1 Gentoo  Macho Biscoe       221     6.3 
## 2 Gentoo  Macho Biscoe       230     6.05
## 3 Gentoo  Macho Biscoe       220     6   
## 4 Gentoo  Macho Biscoe       222     6   
## 5 Gentoo  Macho Biscoe       223     5.95

Ordenação por mais de uma coluna: dentro de cada espécie (ordem alfabética), o pinguim com a maior nadadeira. Para isso, ordenamos e pegamos a primeira linha de cada grupo com slice(1):

maior_nadadeira <- pinguins %>%
  arrange(especie, desc(nadadeira)) %>%
  group_by(especie) %>%
  slice(1) %>%
  ungroup() %>%
  select(especie, sexo, nadadeira, massa_kg)

maior_nadadeira
## # A tibble: 3 × 4
##   especie   sexo  nadadeira massa_kg
##   <fct>     <fct>     <int>    <dbl>
## 1 Adelie    Macho       210     4   
## 2 Chinstrap Macho       212     4.3 
## 3 Gentoo    Macho       231     5.65

Os cinco mais pesados são todos Gentoo, e o maior valor de nadadeira entre todas as espécies é 231 mm, de um pinguim Gentoo.

1.7 Agrupamento e resumo (group_by + summarise)

Primeiro, onde vive cada espécie, com count():

pinguins %>% count(ilha, especie)
## # A tibble: 5 × 3
##   ilha      especie       n
##   <fct>     <fct>     <int>
## 1 Biscoe    Adelie       44
## 2 Biscoe    Gentoo      119
## 3 Dream     Adelie       55
## 4 Dream     Chinstrap    68
## 5 Torgersen Adelie       47

A tabela mostra que só os Adelie aparecem nas três ilhas; os Chinstrap só vivem em Dream e os Gentoo só em Biscoe.

Agora o resumo das medidas por espécie e sexo:

resumo <- pinguins %>%
  group_by(especie, sexo) %>%
  summarise(
    n               = n(),
    massa_media     = round(mean(massa_kg), 2),
    massa_dp        = round(sd(massa_kg), 2),
    nadadeira_media = round(mean(nadadeira), 1),
    bico_comp_medio = round(mean(bico_comp), 1),
    .groups = "drop"
  ) %>%
  arrange(desc(massa_media))

resumo
## # A tibble: 6 × 7
##   especie   sexo      n massa_media massa_dp nadadeira_media bico_comp_medio
##   <fct>     <fct> <int>       <dbl>    <dbl>           <dbl>           <dbl>
## 1 Gentoo    Macho    61        5.48     0.31            222.            49.5
## 2 Gentoo    Fêmea    58        4.68     0.28            213.            45.6
## 3 Adelie    Macho    73        4.04     0.35            192.            40.4
## 4 Chinstrap Macho    34        3.94     0.36            200.            51.1
## 5 Chinstrap Fêmea    34        3.53     0.29            192.            46.6
## 6 Adelie    Fêmea    73        3.37     0.27            188.            37.3

Por fim, calculamos o dimorfismo sexual (quanto os machos são mais pesados que as fêmeas, em %) em cada espécie:

dimorfismo <- pinguins %>%
  group_by(especie) %>%
  summarise(
    massa_femea = mean(massa_kg[sexo == "Fêmea"]),
    massa_macho = mean(massa_kg[sexo == "Macho"])
  ) %>%
  mutate(diferenca_pct = round(100 * (massa_macho - massa_femea) / massa_femea, 1)) %>%
  arrange(desc(diferenca_pct))

dimorfismo
## # A tibble: 3 × 4
##   especie   massa_femea massa_macho diferenca_pct
##   <fct>           <dbl>       <dbl>         <dbl>
## 1 Adelie           3.37        4.04          20  
## 2 Gentoo           4.68        5.48          17.2
## 3 Chinstrap        3.53        3.94          11.7

Interpretação dos resultados:

  • O grupo mais pesado é o de Gentoo (Macho), com média de 5.48 kg; o mais leve é o de Adelie (Fêmea), com 3.37 kg.
  • Em todas as espécies os machos são mais pesados que as fêmeas. A maior diferença está nos Adelie (20%) e a menor nos Chinstrap (11.7%).
  • Isso explica o filtro 1: como os machos são mais pesados, poucas fêmeas ficam acima da média da própria espécie.

A diferença entre machos e fêmeas é real ou pode ser acaso? Usamos o teste t de Welch (equação 5 da aba de equações) nos Gentoo:

gentoo <- pinguins %>% filter(especie == "Gentoo")
teste <- t.test(massa_kg ~ sexo, data = gentoo)
teste
## 
##  Welch Two Sample t-test
## 
## data:  massa_kg by sexo
## t = -14.761, df = 116.64, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group Fêmea and group Macho is not equal to 0
## 95 percent confidence interval:
##  -0.9131130 -0.6970763
## sample estimates:
## mean in group Fêmea mean in group Macho 
##            4.679741            5.484836

O p-valor é <2e-16, muito menor que 0,05. Então a diferença de massa entre machos e fêmeas Gentoo é estatisticamente significativa: não é fruto do acaso.

Para fechar, a correlação de Pearson entre o tamanho da nadadeira e a massa:

r <- cor(pinguins$nadadeira, pinguins$massa_kg)
round(r, 3)
## [1] 0.873

O valor r = 0.873 indica uma correlação positiva e muito forte: pinguins com nadadeiras maiores tendem a ser mais pesados.

2) Tabela Interativa

A tabela abaixo foi feita com a função datatable() do pacote DT e mostra o conjunto pinguins criado na aba 1. Com ela é possível:

  • ordenar: clique no nome de qualquer coluna;
  • buscar: use a caixa Pesquisar (busca geral) ou os filtros logo abaixo do nome de cada coluna (por exemplo, escolher só a espécie Gentoo);
  • paginar: navegue pelas páginas ou mude quantas linhas são exibidas.
datatable(
  pinguins,
  rownames = FALSE,
  filter   = "top",
  colnames = c("Espécie", "Ilha", "Sexo", "Ano", "Bico comp. (mm)",
               "Bico prof. (mm)", "Nadadeira (mm)", "Massa (kg)",
               "Razão do bico", "Porte", "Massa padronizada (z)"),
  caption  = "Tabela 1: Pinguins do arquipélago Palmer após a manipulação.",
  options  = list(
    scrollX    = TRUE,
    pageLength = 10,
    lengthMenu = c(10, 25, 50, 100),
    order      = list(list(7, "desc")),
    language   = list(url = "https://cdn.datatables.net/plug-ins/1.10.11/i18n/Portuguese-Brasil.json")
  )
) %>%
  formatStyle(
    "porte",
    backgroundColor = styleEqual(
      c("Pequeno", "Médio", "Grande"),
      c("#D6EAF8", "#FFF3CD", "#F5CBA7")
    )
  ) %>%
  formatStyle(
    "massa_z",
    color      = styleInterval(c(-1, 1), c("#C0392B", "black", "#1E8449")),
    fontWeight = styleInterval(c(-1, 1), c("bold", "normal", "bold"))
  )

A tabela abre ordenada pela massa (do maior para o menor). A coluna Porte é colorida por faixa, e na Massa padronizada aparecem em verde os pinguins bem mais pesados que a média da espécie (z > 1) e em vermelho os bem mais leves (z < −1).

3) Equações

As cinco equações abaixo foram escritas com a sintaxe do LaTeX.

Equação 1 — Entropia e Ganho de Informação (Árvores de Decisão)

\[ H(S) = -\sum_{c=1}^{C} p_c \log_2 p_c, \qquad IG(S, A) = H(S) - \sum_{v \in \text{valores}(A)} \frac{\lvert S_v \rvert}{\lvert S \rvert}\, H(S_v) \]

Significado: a entropia \(H(S)\) mede o quanto um conjunto \(S\) está “misturado”: vale \(0\) quando todos os exemplos são da mesma classe e é máxima quando as \(C\) classes aparecem na mesma proporção (\(p_c\) é a proporção da classe \(c\)). O ganho de informação \(IG(S, A)\) mede quanto essa mistura cai ao dividir \(S\) pelo atributo \(A\) em subconjuntos \(S_v\). A árvore de decisão escolhe, a cada nó, o atributo com maior ganho.

Equação 2 — Índice de Gini e votação da Random Forest

\[ G(S) = 1 - \sum_{c=1}^{C} p_c^{2}, \qquad \hat{y}(\mathbf{x}) = \underset{c}{\arg\max} \sum_{b=1}^{B} \mathbb{1}\big(T_b(\mathbf{x}) = c\big) \]

Significado: o índice de Gini \(G(S)\) é outra medida de impureza de um nó, usada por padrão no randomForest do R: é a probabilidade de classificar errado um exemplo sorteado ao acaso se o rótulo também fosse sorteado pelas proporções \(p_c\). A segunda parte é a previsão da Random Forest: cada uma das \(B\) árvores \(T_b\), treinadas em amostras bootstrap diferentes, dá um voto, e a classe final \(\hat{y}\) é a mais votada (\(\mathbb{1}(\cdot)\) vale 1 quando a árvore vota em \(c\) e 0 caso contrário).

Equação 3 — Regressão Logística e Entropia Cruzada

\[ P(y = 1 \mid \mathbf{x}) = \sigma(\mathbf{w}^\top \mathbf{x} + b) = \frac{1}{1 + e^{-(\mathbf{w}^\top \mathbf{x} + b)}}, \qquad J(\mathbf{w}, b) = -\frac{1}{n} \sum_{i=1}^{n} \Big[ y_i \log \hat{p}_i + (1 - y_i) \log (1 - \hat{p}_i) \Big] \]

Significado: a função sigmoide \(\sigma\) transforma uma combinação linear das variáveis \(\mathbf{x}\) (com pesos \(\mathbf{w}\) e intercepto \(b\)) em uma probabilidade entre 0 e 1. Por isso a regressão logística serve para classificação binária (por exemplo, prever se um pinguim é macho ou fêmea pelas medidas). A função de custo \(J\), a entropia cruzada, penaliza muito quando o modelo dá alta probabilidade para a classe errada; o treino busca os \(\mathbf{w}\) e \(b\) que a minimizam.

Equação 4 — Gradiente Descendente no Erro Quadrático Médio

\[ \text{EQM}(\boldsymbol{\theta}) = \frac{1}{n}\sum_{i=1}^{n}\left(y_i - \boldsymbol{\theta}^\top \mathbf{x}_i\right)^2, \qquad \boldsymbol{\theta}^{(t+1)} = \boldsymbol{\theta}^{(t)} - \eta \, \nabla_{\boldsymbol{\theta}} \text{EQM} = \boldsymbol{\theta}^{(t)} + \frac{2\eta}{n} \sum_{i=1}^{n} \left(y_i - \boldsymbol{\theta}^{(t)\top} \mathbf{x}_i\right)\mathbf{x}_i \]

Significado: o erro quadrático médio (EQM) mede o quanto as previsões \(\boldsymbol{\theta}^\top \mathbf{x}_i\) se afastam dos valores reais \(y_i\). O gradiente descendente encontra os parâmetros \(\boldsymbol{\theta}\) que minimizam esse erro aos poucos: a cada iteração \(t\), dá um passo de tamanho \(\eta\) (a taxa de aprendizado) na direção contrária ao gradiente, ou seja, “descendo a ladeira” da função de erro. É o algoritmo por trás do treino da maioria dos modelos de machine learning.

Equação 5 — Teste t de Welch

\[ t = \frac{\bar{x}_1 - \bar{x}_2}{\sqrt{\dfrac{s_1^2}{n_1} + \dfrac{s_2^2}{n_2}}}, \qquad \nu \approx \frac{\left( \dfrac{s_1^2}{n_1} + \dfrac{s_2^2}{n_2} \right)^2}{\dfrac{\left(s_1^2 / n_1\right)^2}{n_1 - 1} + \dfrac{\left(s_2^2 / n_2\right)^2}{n_2 - 1}} \]

Significado: o teste t de Welch verifica se as médias de dois grupos (\(\bar{x}_1\) e \(\bar{x}_2\)) são diferentes de verdade ou se a diferença pode ser só acaso. Ele divide a diferença das médias pelo seu erro padrão, usando as variâncias \(s^2\) e os tamanhos \(n\) de cada grupo, sem supor que as variâncias sejam iguais. Os graus de liberdade \(\nu\) (fórmula de Welch–Satterthwaite) definem a distribuição t usada para calcular o p-valor. É o teste que o t.test() do R faz por padrão, e foi usado na aba 1 para comparar a massa de machos e fêmeas.

4) Figuras

Figura 1 — Ciclo da Ciência de Dados

Figura 1: Ciclo da Ciência de Dados, adaptado de Wickham et al. (2023).
Figura 1: Ciclo da Ciência de Dados, adaptado de Wickham et al. (2023).

A figura mostra as etapas de um projeto de ciência de dados segundo Wickham et al. (2023): importar os dados, arrumá-los (tidy) e entrar no ciclo de entendimento, onde se transforma, visualiza e modela repetidamente até chegar a uma conclusão. A última etapa é comunicar os resultados, que é justamente o papel de relatórios em R Markdown (Xie et al. 2018) e do storytelling com dados (Knaflic 2015).

Figura 2 — Diagrama de Venn da Ciência de Dados

Figura 2: Diagrama de Venn da Ciência de Dados, baseado na proposta de Drew Conway (2010).
Figura 2: Diagrama de Venn da Ciência de Dados, baseado na proposta de Drew Conway (2010).

O diagrama mostra a ciência de dados como a interseção de três áreas: computação, matemática e estatística e conhecimento do domínio. Juntar só computação e estatística dá machine learning (James et al. 2021); juntar computação e domínio sem base estatística é a “zona de perigo”, onde se tiram conclusões erradas com facilidade.

5) Referências

As referências abaixo foram gerenciadas com BibTeX, a partir do arquivo referencias.bib indicado no campo bibliography do cabeçalho. Elas foram citadas ao longo do relatório com a sintaxe [@chave].

Gorman, Kristen B., Tony D. Williams, e William R. Fraser. 2014. “Ecological Sexual Dimorphism and Environmental Variability within a Community of Antarctic Penguins (Genus Pygoscelis)”. PLoS ONE 9 (3): e90081. https://doi.org/10.1371/journal.pone.0090081.
James, Gareth, Daniela Witten, Trevor Hastie, e Robert Tibshirani. 2021. An Introduction to Statistical Learning: with Applications in R. 2º ed. Springer.
Knaflic, Cole Nussbaumer. 2015. Storytelling with Data: A Data Visualization Guide for Business Professionals. John Wiley & Sons.
Wickham, Hadley, Mine Çetinkaya-Rundel, e Garrett Grolemund. 2023. R for Data Science: Import, Tidy, Transform, Visualize, and Model Data. 2º ed. O’Reilly Media.
Xie, Yihui, J. J. Allaire, e Garrett Grolemund. 2018. R Markdown: The Definitive Guide. Chapman & Hall/CRC.