Antes de qualquer modelo, olhe os dados. A exploração tem quatro tarefas (Zuur et al. 2010): encontrar erros e outliers, entender a estrutura dos dados — o que conta como réplica —, ver as distribuições que os modelos terão de descrever e detectar colinearidade entre variáveis que um modelo terá dificuldade em separar. Pular essa etapa não economiza tempo: os problemas continuam lá, e aparecem depois como resultados estranhos de modelo.
As lagoas simuladas dos capítulos anteriores são limpas demais para isso. Este capítulo usa dados reais, com todos os problemas que dados reais têm.
NotaDe onde vem este capítulo
Como o Capítulo 10 e o Capítulo 11, este capítulo é inspirado no ecoR(Oliveira 2026), o wiki do curso de R do Instituto de Biociências da Universidade de São Paulo, produzido e mantido por Alexandre Adalardo de Oliveira. A sequência — conferir o data frame, estatísticas descritivas, gráficos univariados, relações entre variáveis e o quarteto de Anscombe — segue o módulo de análise exploratória do ecoR. O texto, os dados, os exemplos e os exercícios daqui foram escritos do zero para Julia; os autores do ecoR não revisaram este livro.
Se quiser ir além, o material original está disponível gratuitamente (CC BY-SA 4.0):
O ATLANTIC BIRD TRAITS(Rodrigues et al. 2019) reúne medidas morfológicas de aves das florestas atlânticas da América do Sul: 72 483 registros, compilados de coleções de museu, projetos de anilhamento e da literatura entre 1820 e 2018, por 179 autores. O artigo de dados afirma que não há restrições de direitos autorais nem de propriedade sobre o seu uso, e pede que seja citado quando usado em publicações ou no ensino — como aqui.
O data/atlantic_bird_traits.csv mantém todos os registros e 21 das 83 colunas originais, com os nomes e códigos originais. Nada foi limpo: encontrar os problemas é o objetivo. O scripts/prepare_birds.jl documenta como o subconjunto foi feito a partir do arquivo original, que está no material suplementar do artigo.
Massa corporal, comprimento da asa, comprimento da cauda: tudo lido como texto (String), e nenhum valor faltante. O motivo está no próprio arquivo — os valores faltantes estão escritos como as duas letras NA, que o CSV.jl não trata como faltante por padrão. Um único não número em uma coluna faz a coluna inteira virar texto. Diga ao CSV.read qual código significa faltante:
O read.csv trata "NA" como faltante por padrão, então em R esse problema passaria despercebido. Aqui ele fica visível: uma coluna numérica que chega como texto é o primeiro sinal de que o arquivo usa um código de faltante que você não declarou. Outros códigos comuns são "", "-", ".", -999 e 99999; missingstring também aceita um vetor deles.
Os nomes das colunas misturam unidades, pontos e maiúsculas, como Body_mass.g.. São incômodos de digitar, e as macros do Tidier não conseguem usá-los diretamente. Renomeie-os uma vez, no início:
Os parênteses com nomes formam uma tupla nomeada (named tuple): uma tupla (Seção 4.1) em que cada valor tem um nome. Ela volta na Seção 10.1.
Há dois tipos de faltante aqui. missing quer dizer que a informação nunca foi anotada; "Unknown" quer dizer que alguém olhou a ave e não conseguiu determinar. Não é a mesma coisa: um estudo de razão sexual deve contar os desconhecidos, mas não os não anotados.
"no" e "Yes": a capitalização muda entre os níveis. Aqui isso é inofensivo, porque cada nível tem uma única grafia, mas um único "yes" em algum lugar criaria um terceiro nível, que o agrupamento trataria como diferente. Padronizar custa pouco:
Menos da metade: muitos passeriformes da Mata Atlântica não podem ser sexados na mão. Qualquer análise por sexo é uma análise de uma metade não aleatória dos dados.
7.3 Estrutura: o que é uma réplica?
Uma linha é um registro, mas registros não são observações independentes. Eles estão agrupados de várias formas ao mesmo tempo.
Por espécie. Os registros estão muito desigualmente distribuídos:
780 nomes — alguns identificados só até gênero, como Elaenia sp. —, enquanto o artigo de dados relata 711 espécies. Antes de contar espécies, decida o que conta como uma. As dez espécies mais registradas concentram um quinto de todos os registros; 68 nomes aparecem uma única vez.
Por indivíduo. Uma ave anilhada capturada de novo aparece de novo:
Algumas “anilhas” são compartilhadas por mais de vinte espécies. Não são números de anilha, e sim códigos de anilhas coloridas, como BRD ou BLUE RIGHT, que muitas aves carregam. Uma contagem ingênua de recapturas tomaria todas essas aves por um único indivíduo.
Por fonte e método. Cada registro vem de um de 65 pesquisadores principais, e de aves vivas ou peles de museu, ao longo de dois séculos:
combine(groupby(dropmissing(birds[:, [:status, :year]]), :status), nrow =>:n, :year => minimum =>:primeiro, :year => median =>:mediana,:year => maximum =>:ultimo)
2×5 DataFrame
Row
status
n
primeiro
mediana
ultimo
String7
Int64
Int64
Float64
Int64
1
live
57862
1990
2010.0
2018
2
museum
11152
1820
2007.0
2017
Cada um desses agrupamentos pode tornar os registros de um mesmo grupo mais parecidos entre si do que registros de grupos diferentes — a dependência que os modelos mistos da Seção 8.7 levam em conta. Explorar a estrutura diz quais termos de agrupamento um modelo precisa.
NotaSua vez 7.3 — Quantas aves foram capturadas duas vezes?
Conte os indivíduos registrados mais de uma vez: anilhas que aparecem em mais de um registro da mesma espécie, ignorando os códigos feitos só de letras (anilhas coloridas). Passe o número para checar("7.3", ...).
DicaDica
Descarte os códigos só de letras com occursin(r"^[A-Za-z]+$", ring), que dá true para eles. Depois agrupe por ringespecies, conte as linhas e conte os grupos com mais de uma.
Cerca de 4 500 aves contribuem com dois registros ou mais, uma delas com até 43. Tratar esses registros como independentes superestimaria o tamanho amostral — e os códigos de cor teriam acrescentado 27 “indivíduos” falsos à contagem.
7.4 Distribuições
A massa corporal de todas as aves cobre três ordens de grandeza, de beija-flores a grandes aves marinhas. Em escala linear, quase tudo se acumula à esquerda; em escala log, a forma aparece:
Figura 7.1: Massa corporal de todas as aves pesadas, em escala linear (a) e logarítmica (b).
Tamanhos, áreas e concentrações são limitados em zero e crescem de forma multiplicativa; por isso costumam ser assimétricos à direita e mais simétricos em escala log. É por isso que modelos dessas variáveis usam tão frequentemente o seu logaritmo.
Dentro de uma espécie, o quadro é outro. Para o sabiá-coleira (Turdus albicollis), uma das espécies mais registradas, compare a distribuição com uma curva normal de mesma média e desvio-padrão:
Figura 7.2: Massa corporal de Turdus albicollis: histograma com uma curva normal de mesma média e desvio-padrão (a), e QQ-plot contra a normal (b).
Perto da normal no meio, com algumas aves bem mais leves ou mais pesadas que as outras — visíveis como os pontos que se afastam da reta nas duas pontas do QQ-plot. Essas caudas são o assunto da próxima seção.
NotaSua vez 7.4 — Média ou mediana?
Calcule a mediana e a média da massa corporal de Turdus albicollis e passe-as, nessa ordem, como um vetor para checar("7.4", ...). Qual das duas é menos afetada pelas aves extremas?
DicaDica
sabia, acima, já tem as massas. [median(x), mean(x)] monta o vetor.
CuidadoSolução
centro_sabia = [median(sabia), mean(sabia)]
2-element Vector{Float64}:
66.0
66.74542818610924
checar("7.4", centro_sabia)
✓ Correto!
66 e 66,7 g: quase iguais, como se espera de uma distribuição aproximadamente simétrica. A mediana ignora o quão extremas são as caudas; a média é puxada por elas. Com alguns registros de 26 g ou 114 g, a média se move pouco; com os erros grosseiros da próxima seção, se moveria muito mais.
7.5 Erros e outliers
Um histograma geral não mostra o erro de uma ave de 14 g registrada com 1 240 g: 1 240 g é uma massa perfeitamente comum para uma ave grande. Outliers em dados de atributos são outliers em relação à espécie. Um sinal simples e robusto compara cada massa com a mediana da sua espécie:
Thlypopsis sordida, uma saíra de 14 g, registrada com mais de 1 kg: quase certamente um erro de digitação, talvez um separador decimal fora do lugar ou uma unidade errada.
Várias massas cerca de dez vezes a mediana da espécie — 102 g para um papa-moscas de 9 g, 50 g para um beija-flor de 4,5 g: a assinatura de uma vírgula deslocada.
Jovens pesados de Tityra cayana em uma coleção de museu: talvez erros, talvez um espécime com etiqueta trocada. Só a fonte pode dizer.
Aqui alguns dos “outliers” são reais. Uma saracura-do-mato (Aramides saracura, mediana de 346 g) de 24 g marcada como jovem é plausivelmente um filhote. Apagá-la removeria uma ave real; mantê-la em uma análise de tamanho adulto a distorceria.
ImportanteSinalize, não apague
Uma regra estatística só pode dizer que um valor é incomum, nunca que ele está errado. Sinalize os valores suspeitos, olhe-os um a um, volte à fonte quando puder e decida — e registre o que decidiu e por quê, em código, para que a decisão possa ser revisada. Em muitas análises, a escolha certa é restringir os dados ao que a pergunta trata (adultos, digamos) em vez de remover pontos individuais.
Os dados também carregam um problema mais discreto, a precisão. A maioria das massas é um número inteiro:
mean(pesadas.mass_g .==round.(pesadas.mass_g))
0.7217974646080995
72% das massas são inteiras, o que quer dizer que muitas foram pesadas com precisão de 1 grama. Para um beija-flor de 3 g, arredondar ao grama é um erro de até 17%; para um sabiá, menos de 1%. Uma precisão que varia com o tamanho do animal é fácil de não notar, e vale saber disso antes de comparar espécies pequenas.
NotaSua vez 7.5 — Quantas massas suspeitas?
Conte os registros cuja massa é mais de 3 vezes, ou menos de um terço, da mediana da sua espécie, entre as espécies com pelo menos 10 registros pesados. Passe o número para checar("7.5", ...).
DicaDica
pesadas já tem ratio e n_species. Combine as condições com .& e .| e conte os true com count.
291 de cerca de 60 000 registros pesados, 0,5%: poucos, mas suficientes para arruinar a média de uma espécie. O limiar de 3 é uma escolha, não uma regra; com 2, você sinalizaria mais que o dobro.
7.6 Relações e colinearidade
Atributos morfológicos andam juntos: aves grandes têm asas longas, caudas longas, pernas longas e bicos longos. Para ver com que força, resuma cada espécie pela mediana de cada atributo — a mediana, por causa dos outliers acima — e compare as espécies:
atributos = [:mass_g, :wing_mm, :tail_mm, :tarsus_mm, :bill_mm]mediana_ou_missing(x) = (v =collect(skipmissing(x)); isempty(v) ? missing:median(v))por_especie_med =dropmissing(combine(groupby(birds, :species), [t => mediana_ou_missing => t for t in atributos]...))log_atributos =DataFrame(log.(Matrix(por_especie_med[:, atributos])), atributos)nrow(por_especie_med)
rotulos = ["log massa", "log asa", "log cauda", "log tarso", "log bico"]fig =Figure(size = (820, 820))for i in1:5, j in1:5 ax =Axis(fig[i, j], xlabel = i ==5 ? rotulos[j] :"", ylabel = j ==1 ? rotulos[i] :"", xticklabelsvisible = i ==5, yticklabelsvisible = j ==1&& i !=1)if i == j # diagonal: a distribuição de cada atributo (contagens)hist!(ax, log_atributos[:, i], bins =25, color = (:grey60, 0.8))elsescatter!(ax, log_atributos[:, j], log_atributos[:, i], markersize =3, color = (:steelblue, 0.5))endendfig
Figura 7.3: Medianas de cinco atributos por espécie, em escala log, um ponto por espécie. Fora da diagonal, cada painel mostra um par de atributos; na diagonal, a distribuição de cada atributo.
Massa e comprimento da asa são quase uma única variável entre espécies. Se os dois entrassem em um modelo como preditores, o modelo não conseguiria separar os seus efeitos: as estimativas seriam instáveis e os erros-padrão, grandes. O fator de inflação da variância (VIF) mede isso. Para cada preditor, faça a regressão dele em todos os outros; com o \(R^2\) dessa regressão, \(\text{VIF} = 1 / (1 - R^2)\):
functionvif(df, col) outros =setdiff(propertynames(df), [col]) f =Term(col) ~sum(Term.(outros))return1/ (1-r2(lm(f, df)))endDataFrame(atributo = atributos, vif =round.([vif(log_atributos, t) for t in atributos]; digits =1))
5×2 DataFrame
Row
atributo
vif
Symbol
Float64
1
mass_g
11.9
2
wing_mm
9.7
3
tail_mm
2.5
4
tarsus_mm
3.0
5
bill_mm
2.1
Zuur et al. (2010) usam um limite de 3; outros autores usam 5 ou 10. Massa e asa ficam acima de todos eles. As respostas usuais são manter só um de cada grupo colinear, combiná-los (um índice de tamanho) ou fazer uma pergunta que não precise deles separadamente.
NotaSua vez 7.6 — Massa e asa
Qual é a correlação entre log da massa corporal e log do comprimento da asa entre espécies, usando as medianas por espécie acima? Passe-a para checar("7.6", ...).
Cerca de 0,93. Entre espécies, esses dois atributos carregam quase a mesma informação. Dentro de uma espécie, a correlação é muito mais fraca — cerca de 0,25 entre indivíduos de Turdus albicollis —, porque indivíduos de uma espécie variam pouco em tamanho: a colinearidade depende da escala da pergunta.
7.7 Por que os gráficos: o quarteto de Anscombe
Resumos não substituem olhar. Anscombe (1973) construiu quatro pequenos conjuntos de dados com as mesmas médias, variâncias, correlações e retas de regressão:
anscombe =dataset("datasets", "anscombe")DataFrame(conjunto =1:4, media_x = [mean(anscombe[:, "X$i"]) for i in1:4], media_y = [round(mean(anscombe[:, "Y$i"]); digits =2) for i in1:4], cor_xy = [round(cor(anscombe[:, "X$i"], anscombe[:, "Y$i"]); digits =3) for i in1:4])
4×4 DataFrame
Row
conjunto
media_x
media_y
cor_xy
Int64
Float64
Float64
Float64
1
1
9.0
7.5
0.816
2
2
9.0
7.5
0.816
3
3
9.0
7.5
0.816
4
4
9.0
7.5
0.817
fig =Figure(size = (760, 560))for i in1:4 x, y = anscombe[:, "X$i"], anscombe[:, "Y$i"] ax =Axis(fig[(i -1) ÷2+1, (i -1) %2+1], title ="Conjunto $i", limits = (3, 20, 3, 14))scatter!(ax, x, y, color =:steelblue) b =coef(lm(@formula(y ~ x), DataFrame(; x, y)))ablines!(ax, b[1], b[2], color =:darkorange)endfig
Figura 7.4: O quarteto de Anscombe: quatro conjuntos de dados com as mesmas estatísticas resumo e a mesma reta de mínimos quadrados.
O primeiro parece o que um modelo linear supõe. O segundo é uma curva. No terceiro, um ponto afasta a reta de uma relação de resto perfeita. No quarto, toda a inclinação depende de uma única observação. Só os gráficos mostram isso.
Desafios
Faça o gráfico das coordenadas de todos os registros (lon, lat) e pinte-os por outside_range. Os registros marcados como fora da distribuição da espécie estão onde você esperaria? Há pontos fora da região da Mata Atlântica?
Machos e fêmeas de Chiroxiphia caudata (tangará) diferem muito na plumagem. Diferem na massa? Compare as distribuições, não só as medianas, e decida o que fazer com os registros de sexo "Unknown".
Repita a regra de outliers da Seção 7.5 para o comprimento da asa. As espécies com asas suspeitas são as mesmas com massas suspeitas? O que isso diria sobre a origem dos erros?
Oliveira, Alexandre Adalardo de. 2026. ecoR: curso de introdução à linguagem R. Wiki, Instituto de Biociências, Universidade de São Paulo. https://ecor.ib.usp.br/.
Rodrigues, Rodolpho Credo, Érica Hasui, Julia Camara Assis, João Carlos Castro Pena, Renata L. Muylaert, et al. 2019. «ATLANTIC BIRD TRAITS: a data set of bird morphological traits from the Atlantic forests of South America». Ecology 100 (6): e02647. https://doi.org/10.1002/ecy.2647.
Zuur, Alain F., Elena N. Ieno, e Chris S. Elphick. 2010. «A protocol for data exploration to avoid common statistical problems». Methods in Ecology and Evolution 1 (1): 3–14. https://doi.org/10.1111/j.2041-210X.2009.00001.x.