Processing math: 100%

Análise descritiva

Published

Oct. 25, 2021

DOI

Introdução

A análise exploratória dos dados, baseada na descrição estatística de dados, é uma abordagem que tem como objetivos contribuir para adquirir conhecimento e uma visão mais aprofundada dos dados, de modo a evidenciar padrões e a detectar anomalias.

Apresentam-se neste documento algumas técnicas e ferramentas básicas de análise para atingir estes objetivos, usando a linguagem R.

Dados Fisher Iris

Iremos usar o ficheiro de dados Iris:

data(iris)
str(iris)
'data.frame':   150 obs. of  5 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

As variáveis quantitativas referem-se ao comprimento e largura das pétalas e das sépalas, a variável categorica descreve a especie.

head(iris, n = 3)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa

Gráficos

Variável quantitativa

Para uma variável numérica, é frequente usar um histograma dos dados observados para descrever a distribuição empírica da variável. A descrição do histograma faz-se em torno da sua forma em termos de dispersão, assimetria ou achatamento.

Um histograma pode ser obtido com a função hist():

hist (iris$Sepal.Width, breaks = 10, 
      main = "Histograma", 
      xlab = "Comp. pétala (cm)", 
      ylab = "Freq. absoluta")

Em alternativa ao histograma, pode usar-se a função boxplot() para construir uma caixa-de-bigodes (boxplot). O box-plot fornece cinco medidas :

O IQR = percentil 75 - percentil 25 (ou amplitude inter-quartil) .

par(oma = rep(0,4)); par(mar= c(1,4,3,0))
boxplot (iris$Sepal.Width,
         main = "Caixa-de-bigodes",
         xlab = "", 
         ylab = "Comp. pétala (cm)", 
         col = c("magenta"))

Um dos pontos fortes dos box-plots será a capacidade de identificar facilmente a presença de valores extremos, muito afastados do centro de gravidade. No gráfico, os pontos que aparecem acima e abaixo dos limites do bigode podem ser vistos como valores extremos ou “anomalos”.

Variável categórica

Para variáveis categóricas (ou factor) é usual calcular frequências absolutas/relativas usando a função table() ou prop.table():

iris$Species <- factor(iris$Species)
tabs <- table(iris$Species)
tabs

    setosa versicolor  virginica 
        50         50         50 
trel <- prop.table(tabs)
trel

    setosa versicolor  virginica 
 0.3333333  0.3333333  0.3333333 

A função table() constroí uma tabela de contingência (neste caso a tabela tem apenas uma variável, com 3 categorias). O argumento da função prop.table() é a tabela de contingência.

Duas variáveis

A função plot() é uma função genérica do R que produz diferentes gráficos em função do tipo de argumentos. Ex:

Por ex. a função plot() do comprimento das pétalas e das sépalas (ambas quantitativas) devolve um gráfico de dispersão:

plot (iris$Petal.Length, iris$Sepal.Length, 
     main = "Gráfico de dispersão",
     xlab = "Comprimento pétala (cm)", 
     ylab = "Comprimento sépala (cm)", type="p")

No caso de uma das variáveis ser numérica e a outra categrorica (factor), a função plot() devolve uma caixa-de-bigodes (por categoria):

plot (iris$Species, iris$Petal.Length, 
      main = "Caixa-de-bigodes",
      xlab = "Espécie", 
      ylab = "Comprimento pétala (cm)", 
      col = c("white","grey","pink"))

No caso de ambas as variáveis serem quantitativas, e existir uma variável factor que discrimine as categorias, pode criar-se, com a função plot() um gráfico de dispersão mais informativo onde se distinguirem as categorias:

# para por legenda fora do plot 
par(mar=c(5, 4, 4, 8), xpd=TRUE)
# plot
plot (iris$Petal.Length, iris$Sepal.Length, 
     main = "Gráfico de dispersão",
     xlab = "Comprimento pétala (cm)", 
     ylab = "Comprimento sepala (cm)", 
     col = as.numeric(iris$Species))
# legenda
legend ("bottomright", legend = levels(iris$Species), 
        pch = c(1,1,1), col = unique (as.numeric(iris$Species)), 
        inset=c(-0.5, 0))

2 ou mais variáveis

Se quisermos visualizar vários planos formados por pares de vetores numéricos, podemos gerar um painel dos gráficos de dispersão com a função pairs():

pairs (iris[,1:4], 
       col = as.numeric(iris$Species), 
       oma = c(3,3,3,14))
par (xpd = TRUE)
legend ("bottomright",
        pch = c(1,1,1),
        col = unique(as.numeric(iris$Species)), 
        legend = levels(iris$Species))

Com a função lattice::xyplot()

O package lattice extende as capacidades gráficas do R que vimos até aqui. Embora venha instalado no R base, é necessário carregar o package dentro da sessão R para beneficiar das funcionalidades:

library (lattice)

Com a função xyplot() também se podem criar gráficos de dispersão para cada categoria:

xyplot(Sepal.Length ~ Petal.Length | Species, 
       data = iris, 
       ylab = "Comprimento sépala (cm)", 
       xlab= "Comprimento pétala (cm)")

Para criar um histograma por categoria, no mesmo gráfico podemos usar a função lattice::histogram():

histogram ( ~ Petal.Length | Species, data = iris, 
           xlab = "Comprimento pétala (cm)",
           ylab="%", type = "percent", 
           nint = 50, layout = c(1,3))

Exportar gráficos

Podem exportar-se gráficos, gravando-os num ficheiro, através do interface RStudio:

ou usando consola:

# cria ficheiro png
png(file="grafico_1.png", 
    width=1000, height = 1000, res = 600)

# guarda gráfico
histogram ( ~ Petal.Length | Species, data = iris, 
           xlab = "Comprimento pétala (cm)", ylab="%",
           type = "percent", nint = 50, layout = c(1,3))

# fecha ficheiro
dev.off()

Tabelas

Univariadas

A função summary devolve algumas medidas dos dados observados :

summary(iris)
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
 Median :5.800   Median :3.000   Median :4.350   Median :1.300  
 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
       Species  
 setosa    :50  
 versicolor:50  
 virginica :50  
                
                
                

No caso das variáveis quantitativas devolve medidas de localização (minimo, máximo, média e percentis 25,50 e 75), no caso de variáveis categoricas devolve as contagens por categoria.

Os valores das estimativas da média ou do desvio-padrão podem ser obtidas com as funções mean, sd:

mean(iris$Petal.Length)
[1] 3.758
sd(iris$Petal.Length)
[1] 1.765298

Para obter estas estatísticas para mais que uma variável podemos usar a função apply() que aplica uma função a um objeto (data.frame, matriz), em coluna (ou em linha):

apply(iris[,1:4], 2, mean)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333     3.057333     3.758000     1.199333 
apply(iris[,1:4], 2, sd)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
   0.8280661    0.4358663    1.7652982    0.7622377 

As medidas de assimetria ou achatamento não estão implementadas no R base. A função moments::skewness calcula a assimetria de um vetor ou de um conjunto de vetores:

library(moments)
skewness(iris[,1:4])
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
   0.3117531    0.3157671   -0.2721277   -0.1019342 

Um coeficiente de assimetria positivo tipicamente indica que a distribuição empírica da variável tem uma cauda mais alongada para o lado direito (caso seja negativo, ocorre o oposto). Quanto mais afastado de zero o valor do coeficiente, mais assimétrica é a distribuição.

Para obter estas estatísticas (média,..) por categorias, pode usar-se a função aggregate(), especificando os argumentos by= (variável categorica) e FUN (função):

aggregate(iris[,1:4], by = list(iris$Species), FUN = mean)
     Group.1 Sepal.Length Sepal.Width Petal.Length Petal.Width
1     setosa        5.006       3.428        1.462       0.246
2 versicolor        5.936       2.770        4.260       1.326
3  virginica        6.588       2.974        5.552       2.026

A função apply() aceita qualquer função que possa ser aplicada ao objeto. Podemos criar uma função (que não esteja implementada) e usá-la com o apply().

Por exemplo, o coeficiente de variação, cv=sd/m (medida de dispersão dada pelo quociente entre desvio-padrão e media) não está implementado no R. Quanto maior o coeficiente de variação maior o grau de dispersão em torno da media.

Vamos criar a função e usar o apply() para obter o cv das variáveis quantitativas:

calc_cv = function (vetor) {
 # calcula a media e desvio padrao
 m = mean(vetor)
 d = sd (vetor)
 # devolve resultado 
 return(d/m)
 }

Agora podemos usar a função apply() e aplicar a função calc_cv() ao objecto iris[,1:4]:

apply(iris[,1:4], 2, calc_cv)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
   0.1417113    0.1425642    0.4697441    0.6355511 
# a sintaxe mais habitual é:
apply(iris[,1:4], 2, function(x) calc_cv(x))
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
   0.1417113    0.1425642    0.4697441    0.6355511 

Bivariadas

A matriz de variâncias-covariâncias pode ser calculada com a função cov() :

cov(iris[,1:4])
             Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length    0.6856935  -0.0424340    1.2743154   0.5162707
Sepal.Width    -0.0424340   0.1899794   -0.3296564  -0.1216394
Petal.Length    1.2743154  -0.3296564    3.1162779   1.2956094
Petal.Width     0.5162707  -0.1216394    1.2956094   0.5810063

A matriz de correlações dos dados é dada pela função cor():

cor_iris <- cor(iris[,1:4])

As matrizes de correlações (ou de variâncias-covariâncias) em cada categoria podem ser obtida com um ciclo cujo indice i indica a especie :

# vetor com 3 especies (categorias)
class <- levels(iris$Species)
# lista
covk <- list()
# ciclo percorre as classes
# filtra observações e calcula cov
for (i in class){
  irisk <- iris[iris$Species == i, 1:4]
  covk[[i]] <- cor(irisk)
}

Uma forma alternativa de visualizar estas matrizes (especialmente interessante quando há muitas variáveis) é com um heatmap que usa um gradiente de cores para representar os valores dos termos da matriz. A função ggplot2::ggplot() é uma das que permite obter um heatmap:

library("ggplot2")
# definir as coordenadas em linha/coluna dos termos da matriz
dataXY <- expand.grid(X=colnames(cor_iris), Y=colnames(cor_iris))

# Heatmap 
ggplot(dataXY, aes(X, Y, fill= cor_iris)) + 
  geom_tile()