Tutorial R Módulo 6. Análise de outliers baseada no desvio padrão do centróide

Disciplina de Ecologia Numérica1

Autores

Prof. Elvio S. F. Medeiros

Laboratório de Ecologia

Universidade Estadual da Paraíba

Campus V, João Pessoa, PB

Data de Publicação

24 de maio de 2023

Resumo
A análise de outliers baseada no desvio padrão do centróide em análise multivariada é uma técnica utilizada para identificar valores discrepantes em uma matriz de dados com várias variáveis. Essa técnica consiste em calcular o centróide dos dados (ou seja, a média de cada variável), e então calcular o desvio padrão de cada observação em relação ao centróide. Os valores que estão a uma distância maior que um certo número de desvios padrão do centróide são considerados outliers. Essa técnica é útil para identificar observações que podem estar afetando a análise de dados multivariados, como análise de componentes principais, e que podem precisar ser tratadas de forma especial. No entanto, é importante lembrar que a identificação de outliers é uma questão subjetiva e depende do contexto da análise e do objetivo do estudo.

1 Organização básica

rm(list=ls(all=TRUE)) #limpa a memória

Instalando os pacotes necessários para esse módulo

install.packages("openxlsx") #importa arquivos do excel
install.packages("moments") #calcula assimetria e curtose dos dados
install.packages("matrixStats") #fornece funções rápidas para a estatística de matrizes
install.packages("gt") #ferramenta para criação de tabelas bonitas e personalizáveis
library(openxlsx)

Os códigos acima, são usados para instalar e carregar os pacotes necessários para este módulo. Esses códigos são comandos para instalar pacotes no R. Um pacote é uma coleção de funções, dados e documentação que ampliam as capacidades do R (R CRAN e RStudio). No exemplo acima, o pacote openxlsx permite ler e escrever arquivos Excel no R. Para instalar um pacote no R, você precisa usar a função install.packages().

Depois de instalar um pacote, você precisa carregá-lo na sua sessão R com a função library(). Por exemplo, para carregar o pacote openxlsx, você precisa executar a função library(openxlsx). Isso irá permitir que você use as funções do pacote na sua sessão R. Você precisa carregar um pacote toda vez que iniciar uma nova sessão R e quiser usar um pacote instalado.

Agora vamos definir o diretório de trabalho. Esse código é usado para obter e definir o diretório de trabalho atual no R. O comando getwd() retorna o caminho do diretório onde o R está lendo e salvando arquivos. O comando setwd() muda esse diretório de trabalho para o caminho especificado entre aspas. No seu caso, você deve ajustar o caminho para o seu próprio diretório de trabalho. Lembre de usar a barra “/” entre os diretórios. E não a contra-barra “\”.

Definindo o diretório de trabalho e installando os pacotes necessários:

getwd()
setwd("C:/Seu/Diretório/De/Trabalho")

Alternativamente você pode ir na barra de tarefas e escolhes as opções:
SESSION -> SET WORKING DIRECTORY -> CHOOSE DIRECTORY

1.1 Sobre os dados do PPBio

A planilha ppbio contém os dados de abundância de espécies em diferentes unidades amostrais (UA’s) (Figura 1) (Veja Programa de Pesquisa em Biodiversidade – PPBio). Essa é a matriz bruta de dados, porque os valores ainda não foram ajustados para os valores de Captura Por Unidade de Esforço (CPUE), nem foram relativizados ou transformados (Tabela 1).

Figura 1: Parte da planilha de dados brutos do PPBio.
Tabela 1: Matrizes disponíveis para análises, com suas descrições e tipos de dados recomendados.
Arquivo (.xlsx) Tipo de matriz Descrição Tipo de dados
ppbio06c Matriz comunitária O arquivo ppbio06 traz os dados brutos que serão usados nas análises. A matriz de dados brutos contendo 26 localidades em estações do ano diferentes (objetos) x 35 espécies (atributos), antes de qualquer modificação. Contagens de indivíduos com alta amplitude de variação, sugerido uso de matriz relativizada.
ppbio06h Matriz ambiental O arquivo ppbio06h traz os dados brutos que serão usados nas análises. A matriz de dados brutos contendo 26 localidades em estações diferentes (objetos) x 35 variáveis ambienteis (atributos) medidas em diferentes escalas espaciais, antes de qualquer modificação. Unidades de medição diferentes (cm, m, °C, mg/L, etc.), com uma alta amplitude de variação, sugerido uso de matriz transformada e/ou reescalada.
ppbio06 Matriz comunitária O arquivo ppbio06 traz os dados brutos que serão usados nessa análise. A matriz de dados brutos contendo 26 locais/ocasiões (objetos) x 35 espécies (atributos), antes de qualquer modificação. Contagens de indivíduos com alta amplitude de variação, sugerido uso de matriz relativizada.
ppbio06cpue Matriz comunitária O arquivo ppbio06cpue traz os valores depois de terem sidos ajustados pela Captura Por Unidade de Esforço (CPUE), onde o número de indivíduos de cada espécie em uma determinada UA é dividido pelo esforço de captura daquela UA. Isso significa que os dados foram relativizados pela CPUE. A matriz de dados brutos contendo 26 localidades em estações do ano diferentes (objetos) x 35 espécies (atributos), antes de qualquer modificação. Densidades de indivíduos (no. de indivíduos por Unidade de Esforço de Captura) com alta amplitude de variação, sugerido uso de matriz relativizada.

Várias das espécies nessa matriz tem grande importância ecológica, como é o caso de Astyanax bimaculatus 2 (Figura 2), que é muito comum em rios intermitentes e serve de alimento para predadores maiores como a espécie Hoplias malabaricus 3 (Figura 3).

Figura 2: Astyanax bimaculatus, a espécie mais comum da matriz de dados ppbio. Peru, by Eakins, R. Fonte: https://www.fishbase.se/summary/Astianax-bimaculatus.html

Figura 3: Hoplias malabaricus, espécie que cresce para se tornar um importante predador. Brazil, by Roselet, F.F.G. Fonte: https://www.fishbase.se/summary/Hoplias-malabaricus.html

1.2 Importando a planilha de trabalho

Note que o sómbolo # em programação R significa que o texto que vem depois dele é um comentário e não será executado pelo programa. Isso é útil para explicar o código ou deixar anotações. Ajuste a segunda linha do código abaixo para refletir “C:/Seu/Diretório/De/Trabalho/Planilha.xlsx”.

library(openxlsx)
ppbio <- read.xlsx("D:/Elvio/OneDrive/Disciplinas/_EcoNumerica/5.Matrizes/ppbio06.xlsx",
                   rowNames = T,
                   colNames = T,
                   sheet = "Sheet1")
str(ppbio)
ppbio_ma <- as.matrix(ppbio) #lê ppbio como uma matriz
str(ppbio_ma)
#ppbio
#ppbio_ma

1.3 Reset point

Aqui substitui-se uma nova matriz de dados, relativizada e/ou transformada, pela matriz de trabalho inicial.
1#ppbio <- (ppbiopart2)
1
Aqui usaremos as matrizes relativizadas/transformadas/particionadas

Podemos exibir a planilha depois de ter sido importada para o ambiente R/RStudio usando as funções View(), print() ou head(). Note que essas funções são case-sensitive. A função ignore.case() é uma função do pacote stringr que modifica um padrão para que ele não considere o caso das letras nas correspondências. Por exemplo, se você quiser encontrar todas as ocorrências da letra “a” em um vetor de caracteres, independente de ser “A” ou “a”, você pode usar essa função.

#View(ppbio)
print(ppbio)
head(ppbio)

A função head() no RStudio é uma forma de ver as primeiras (n=6) linhas de um objeto, como um vetor, uma matriz, um data frame ou uma lista. Ela é útil para ter uma ideia do conteúdo e da estrutura do objeto.

Também podemos explorar as características da planilha usando as funções str(), mode(), class() e length(). O número de observações ou tamanho do vetor depende do tipo de dados, se eles são uma matrix ou um data.frame.

str(ppbio)
mode(ppbio)
class(ppbio)
#?str
'data.frame':   26 obs. of  35 variables:
 $ ap-davis : num  0 0 0 0 0 0 0 0 0 0 ...
 $ as-bimac : num  1 99 194 19 23 142 5 46 206 16 ...
 $ as-fasci : num  0 0 55 0 1 3 1 0 64 0 ...
 $ ch-bimac : num  0 0 0 0 13 3 0 178 0 0 ...
 $ ci-ocela : num  0 0 0 0 0 0 40 0 0 13 ...
 $ ci-orien : num  0 0 5 0 0 69 9 0 25 24 ...
 $ co-macro : num  0 0 0 0 0 0 0 0 0 0 ...
 $ co-heter : num  0 0 1 0 0 0 0 0 0 0 ...
 $ cr-menez : num  0 0 14 0 0 4 0 0 8 0 ...
 $ cu-lepid : num  0 0 0 0 0 0 0 0 0 0 ...
 $ cy-gilbe : num  0 0 0 0 0 0 0 0 0 0 ...
 $ ge-brasi : num  0 0 3 0 0 0 0 0 1 0 ...
 $ he-margi : num  0 0 0 0 0 1 0 0 0 0 ...
 $ ho-malab : num  0 0 1 5 0 17 10 2 31 4 ...
 $ hy-pusar : num  0 0 9 2 0 43 2 0 11 0 ...
 $ le-melan : num  0 0 0 0 0 0 0 0 0 0 ...
 $ le-piau  : num  0 0 3 0 0 1 3 0 2 1 ...
 $ le-taeni : num  0 0 0 0 0 0 0 0 0 0 ...
 $ mo-costa : num  0 0 0 0 0 0 0 0 0 0 ...
 $ mo-lepid : num  0 1 39 0 0 1 0 0 0 0 ...
 $ or-nilot : num  0 2 36 0 0 77 0 0 138 0 ...
 $ pa-manag : num  0 0 0 0 0 0 0 0 0 0 ...
 $ pimel-sp : num  0 0 6 0 0 0 0 0 0 0 ...
 $ po-retic : num  0 0 0 0 0 20 0 0 5 0 ...
 $ po-vivip : num  0 0 47 15 0 221 32 0 326 10 ...
 $ pr-brevi : num  9 0 5 0 1 15 5 2 164 0 ...
 $ ps-rhomb : num  0 0 0 0 0 0 0 0 1 0 ...
 $ ps-genise: num  0 0 0 0 0 0 0 0 1 0 ...
 $ se-heter : num  0 0 40 14 4 60 0 0 38 0 ...
 $ se-piaba : num  0 0 68 0 0 0 0 0 0 0 ...
 $ se-spilo : num  0 0 0 0 0 0 0 0 1 0 ...
 $ st-noton : num  0 0 1 0 0 25 0 0 115 0 ...
 $ sy-marmo : num  0 0 0 0 0 0 1 0 0 0 ...
 $ te-chalc : num  0 0 0 0 0 0 0 0 0 0 ...
 $ tr-signa : num  0 0 18 0 0 15 0 0 7 0 ...
[1] "list"
[1] "data.frame"

O símbolo ? é usado para acessar a documentação de uma função ou um pacote no R. Como mostrado acima você pode saber mais sobre a função str(), usando o comando ?str. Isso vai abrir uma página no menu de ajuda com a descrição, os argumentos, os valores de retorno e os exemplos da função str(). Você também pode usar o símbolo ? para obter informações sobre um pacote inteiro. Por exemplo, se você quiser saber mais sobre o pacote openxlsx, você pode digitar ?openxlsx. Isso vai abrir uma página com a visão geral, a instalação, os recursos e as referências do pacote solicitado.

Podemos agora calcular o número e a proporção de zeros na matriz usando as funções sum() e length() (Você pode pesquisar o que faz a função length() usando o comando ?length).

2 Tamanho da matriz

range(ppbio) #menor e maior valores
length(ppbio) #no. de colunas
ncol(ppbio) #no. de N colunas
nrow(ppbio) #no. de M linhas
sum(lengths(ppbio)) #soma os nos. de colunas
length(as.matrix(ppbio)) #tamanho da matriz m x n
sum(ppbio == 0) # número de observações igual a zero
sum(ppbio > 0) # número de observações maiores que zero
zeros <- (sum(ppbio == 0)/length(as.matrix(ppbio)))*100 # proporção de zeros na matriz
zeros
[1]   0 511
[1] 35
[1] 35
[1] 26
[1] 910
[1] 910
[1] 716
[1] 194
[1] 78.68132

Tabela que resume as informações geradas (Tabela 2).

tamanho <- data.frame(
  Função = c("range", "lenght", "m cols", "n linhas", "Tamanho", "Tamanho",
             "Zeros", "Nao zeros", "% Zeros"),
  Resultado = c(paste(range(ppbio), collapse = " - "), length(ppbio), ncol(ppbio),
                nrow(ppbio), sum(lengths(ppbio)), length(as.matrix(ppbio)), sum(ppbio == 0),
                sum(ppbio > 0), round(zeros, 1))
)
tamanho
     Função Resultado
1     range   0 - 511
2    lenght        35
3    m cols        35
4  n linhas        26
5   Tamanho       910
6   Tamanho       910
7     Zeros       716
8 Nao zeros       194
9   % Zeros      78.7
Tabela 2: Resumo das informações sobre o tamanho da matriz
Função Resultado
range 0 - 511
lenght 35
m cols 35
n linhas 26
Tamanho 910
Tamanho 910
Zeros 716
Nao zeros 194
% Zeros 78.7

Ou seja, temos uma matriz de tamanho m x n igual a 26 objetos por 35 atributos, onde 78.68% dos valores da matriz são iguais a zero!

3 Cálculo de matriz de distâncias Euclidiana (euclid)

Agora vamos calcular a matriz de distâncias euclidianas (Legendre e Legendre 1998, Borcard et al. 2018) entre as UA´s usando a função dist() (pesquise o que faz essa função usando o comando ?dist).

euclid <- dist(ppbio, method = "euclidian", diag = TRUE, upper = FALSE)
#?dist

Pronto, calculamos a matriz de distâncias (Euclidiana). Agora podemos visualizar a matriz.

#euclid
str(euclid)
mode(euclid)
class(euclid)
length(as.matrix(euclid))
 'dist' num [1:325] 98.4 228.5 29.2 27.1 294.1 ...
 - attr(*, "Size")= int 26
 - attr(*, "Labels")= chr [1:26] "S-A-ZA1" "S-R-CC1" "S-R-CT1" "S-R-CP1" ...
 - attr(*, "Diag")= logi TRUE
 - attr(*, "Upper")= logi FALSE
 - attr(*, "method")= chr "euclidean"
 - attr(*, "call")= language dist(x = ppbio, method = "euclidian", diag = TRUE, upper = FALSE)
[1] "numeric"
[1] "dist"
[1] 676

Uma matriz do tipo dist no R é um objeto que armazena as distâncias entre as linhas de uma matriz ou um data frame. Ela é criada pela função dist(), que calcula as distâncias usando diferentes medidas, como “euclidean”, “manhattan”, “canberra”, “binary” ou “minkowski” (Horton e Kleinman 2015) (Tabela 3).

Tabela 3: Medidas de distância disponíves na função dist() para calcular a distância entre dois pontos ou objetos em um espaço multidimensionl.
Distância Descrição
Euclidiana Mede a distância entre dois pontos no espaço, seguindo o teorema de Pitágoras. É uma medida de distância direta entre dois pontos.
Manhattan Também conhecida como distância da cidade, mede a distância como se estivesse dirigindo em uma cidade. A distância é a soma das diferenças absolutas de cada coordenada.
Canberra Leva em consideração a proporção de diferenças em relação ao tamanho total das variáveis.
Binária Mede a semelhança entre dois objetos. É 0 quando dois valores são iguais e 1 caso contrário.
Minkowski É uma generalização da distância euclidiana e da distância de Manhattan. A distância é controlada por um parâmetro P, que determina a ordem da distância.

Note que a matriz euclid está como uma classe dist.

str(euclid)
mode(euclid)
class(euclid)
as.matrix(euclid)[1:6, 1:6] #mostra as 5 primeiras linhas e colunas da matriz
 'dist' num [1:325] 98.4 228.5 29.2 27.1 294.1 ...
 - attr(*, "Size")= int 26
 - attr(*, "Labels")= chr [1:26] "S-A-ZA1" "S-R-CC1" "S-R-CT1" "S-R-CP1" ...
 - attr(*, "Diag")= logi TRUE
 - attr(*, "Upper")= logi FALSE
 - attr(*, "method")= chr "euclidean"
 - attr(*, "call")= language dist(x = ppbio, method = "euclidian", diag = TRUE, upper = FALSE)
[1] "numeric"
[1] "dist"
          S-A-ZA1   S-R-CC1  S-R-CT1   S-R-CP1   S-A-TA1  S-R-CT2
S-A-ZA1   0.00000  98.43780 228.5235  29.24038  27.09243 294.0629
S-R-CC1  98.43780   0.00000 154.2433  82.79493  77.25283 261.3905
S-R-CT1 228.52352 154.24331   0.0000 208.52338 209.69263 224.9133
S-R-CP1  29.24038  82.79493 208.5234   0.00000  23.25941 271.4922
S-A-TA1  27.09243  77.25283 209.6926  23.25941   0.00000 283.7869
S-R-CT2 294.06292 261.39051 224.9133 271.49217 283.78689   0.0000

Visualizando a matriz de distâncias, observamos que ela é uma matriz quadrada que contém as distâncias entre cada par de elementos do conjuto de dados. A matriz de distâncias terá dimensão m x m (m=linhas, n=colunas), e cada elemento da matriz será a distância entre cada par de observações ou objetos. A matriz de distâncias é simétrica, pois a distância entre i e j é igual à distância entre j e i. A matriz de distâncias também tem diagonal zero, pois a distância entre uma observação e ela mesma é zero.

4 Calculando o centróide da matriz de distâncias euclid

Primeiro algumas informações básicas da matriz

range(ppbio)
range(euclid)
min(euclid)
max(euclid)
mean(euclid) #CENTROIDE!! OU Grand mean
sd(euclid)  #Standard deviation
centroide <- mean(euclid)
centroide
[1]   0 511
[1]  16.27882 707.32666
[1] 16.27882
[1] 707.3267
[1] 285.9043
[1] 172.9708
[1] 285.9043

A função mean() calcula a média de todos os valores da matriz de distâncias, ou seja, a média multivariada, que é o centróide. Nesse caso o centroide assume o valor de 285.9.

Usamos agora a fórmula m*(m-1)/2, onde m é o no. de objetos sendo comparados, para calcular quantas distâcias temos na nossa matriz.

length(euclid)
m <- nrow(ppbio)
m
m*(m-1)/2
summary(euclid)
[1] 325
[1] 26
[1] 325
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  16.28  142.70  242.82  285.90  423.64  707.33 

Temos então que m é 26 objetos (ou linhas), e portanto, a matriz de distâncias tem 325 valores.

Fazemos agora um breve sumário do que foi calculado até agora com base na matriz de distâncias euclid.

Sumario1 <- cbind(min(euclid),
                  max(euclid),
                  sd(euclid),
                  mean(euclid),
                  length(euclid))
colnames(Sumario1) <- c("Minimo", "Maximo", "Desv.Padr", "Media", "m(m-1)/2")
rownames(Sumario1) <- ("Valores")
Sumario1
          Minimo   Maximo Desv.Padr    Media m(m-1)/2
Valores 16.27882 707.3267  172.9708 285.9043      325

5 Distribuição de frequências da matriz de distâncias euclid

O código abaixo vai plotar um histograma e um boxplot da distribuição de dados armazenada em euclid. Também é adicionada uma curva normal teórica ao histograma utilizando a média e o desvio padrão dos dados (Figura 4). Atente que o comando par(mfrow=c(2,1)) define o layout dos gráficos, especificando que serão plotados 2 gráficos em uma coluna. As funções floor(min(euclid)), ceiling(max(euclid)) definem os limites dos graficos pelo valores mínimo e máximo do objeto (euclid).

range(euclid)
[1]  16.27882 707.32666
par(mfrow=c(2,1))
hist(euclid,
     breaks = 15, #determina o no. de colunas do histograma
     xlim = range(floor(min(euclid)), ceiling(max(euclid))), 
     xlab = "Distr. de Frequências",
     freq = FALSE)
curve(dnorm(x, mean=mean(euclid), sd=sd(euclid)), add=TRUE)
boxplot.default(euclid, horizontal = TRUE, frame = FALSE,
                xlab="Distr. de Frequências",
                ylim=c(floor(min(euclid)), ceiling(max(euclid)))) #Limites do eixo Y

Figura 4: Distribuições de frequências da matriz de distâncias euclid

O comando abaixo apaga os gráficos, use-o apenas se necessário.

dev.off()

6 Distribuição de frequências da matriz de distâncias as.matrix() (sem os zeros)

A matriz euclid está como uma classe dist, mas podemos transformá-la em uma classe matrix usando a função as.matrix().

euclid_ma <- (as.matrix(euclid))
#View(euclid_ma)
str(euclid_ma)
mode(euclid_ma)
class(euclid_ma)
euclid_ma[1:5, 1:5] #mostra as 5 primeiras linhas e colunas da matriz
 num [1:26, 1:26] 0 98.4 228.5 29.2 27.1 ...
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:26] "S-A-ZA1" "S-R-CC1" "S-R-CT1" "S-R-CP1" ...
  ..$ : chr [1:26] "S-A-ZA1" "S-R-CC1" "S-R-CT1" "S-R-CP1" ...
[1] "numeric"
[1] "matrix" "array" 
          S-A-ZA1   S-R-CC1  S-R-CT1   S-R-CP1   S-A-TA1
S-A-ZA1   0.00000  98.43780 228.5235  29.24038  27.09243
S-R-CC1  98.43780   0.00000 154.2433  82.79493  77.25283
S-R-CT1 228.52352 154.24331   0.0000 208.52338 209.69263
S-R-CP1  29.24038  82.79493 208.5234   0.00000  23.25941
S-A-TA1  27.09243  77.25283 209.6926  23.25941   0.00000

Assim como o caso da matriz euclid, visualizando a matriz de distâncias, observamos que ela:

  • é uma matriz quadrada que contém as distâncias entre cada par de elementos do conjuto de dados;

  • terá a dimensão m x m;

  • e cada elemento da matriz será a distância entre cada par de observações ou objetos.

A matriz de distâncias é simétrica, pois a distância entre i e j é igual à distância entre j e i. A matriz de distâncias também tem diagonal zero, pois a distância entre uma observação e ela mesma é zero.

7 Calculando o centróide da matriz de distâncias as.matrix

Primeiro algumas informações básicas da matriz

range(euclid_ma)
min(euclid_ma)
max(euclid_ma)
mean(euclid_ma) #CENTROIDE!! OU Grand mean
sd(euclid_ma)  #Standard deviation
centroide_ma <- mean(euclid_ma)
centroide_ma
[1]   0.0000 707.3267
[1] 0
[1] 707.3267
[1] 274.908
[1] 178.1842
[1] 274.908

A função mean() calcula a média de todos os valores da matriz de distâncias, ou seja, a média multivariada, que é o centroide. Nesse caso o centróide assume o valor de 274.9.

Usamos agora a fórmula m*(m-1)/2, onde m é o no. de objetos sendo comparados, para calcular quantas distâcias temos na nossa matriz.

length(euclid_ma) #tamanho da matriz
m2 <- nrow(ppbio_ma) #no. de linhas em ppbio_ma
m2
m2*(m2-1)/2
summary(euclid_ma)
[1] 676
[1] 26
[1] 325
    S-A-ZA1          S-R-CC1          S-R-CT1         S-R-CP1      
 Min.   :  0.00   Min.   :  0.00   Min.   :  0.0   Min.   :  0.00  
 1st Qu.: 60.45   1st Qu.: 98.17   1st Qu.:211.1   1st Qu.: 54.38  
 Median :135.66   Median :140.77   Median :228.4   Median :125.07  
 Mean   :194.48   Mean   :198.07   Mean   :256.1   Mean   :188.25  
 3rd Qu.:278.14   3rd Qu.:257.14   3rd Qu.:283.9   3rd Qu.:261.35  
 Max.   :641.28   Max.   :612.29   Max.   :595.5   Max.   :631.37  
    S-A-TA1          S-R-CT2         S-R-CP2          S-A-TA2     
 Min.   :  0.00   Min.   :  0.0   Min.   :  0.00   Min.   :  0.0  
 1st Qu.: 62.68   1st Qu.:264.5   1st Qu.: 59.32   1st Qu.:185.9  
 Median :126.97   Median :292.2   Median :141.65   Median :201.9  
 Mean   :188.32   Mean   :304.9   Mean   :199.18   Mean   :258.2  
 3rd Qu.:270.46   3rd Qu.:337.5   3rd Qu.:260.74   3rd Qu.:285.5  
 Max.   :633.67   Max.   :590.8   Max.   :633.81   Max.   :651.0  
    S-R-CT3         S-R-CP3          S-A-TA3         S-R-CT4     
 Min.   :  0.0   Min.   :  0.00   Min.   :  0.0   Min.   :  0.0  
 1st Qu.:428.1   1st Qu.: 54.13   1st Qu.:310.8   1st Qu.:190.6  
 Median :457.0   Median :131.50   Median :334.0   Median :216.8  
 Mean   :438.1   Mean   :191.53   Mean   :333.7   Mean   :270.1  
 3rd Qu.:477.8   3rd Qu.:264.22   3rd Qu.:373.3   3rd Qu.:291.8  
 Max.   :648.0   Max.   :634.01   Max.   :643.0   Max.   :659.9  
    S-R-CP4          S-A-TA4         B-A-MU1         B-R-ET1      
 Min.   :  0.00   Min.   :  0.0   Min.   :  0.0   Min.   :  0.00  
 1st Qu.: 86.02   1st Qu.:415.7   1st Qu.:192.6   1st Qu.: 69.93  
 Median :155.51   Median :472.6   Median :208.0   Median :135.64  
 Mean   :208.99   Mean   :441.2   Mean   :267.4   Mean   :197.43  
 3rd Qu.:242.71   3rd Qu.:490.5   3rd Qu.:330.9   3rd Qu.:275.38  
 Max.   :626.20   Max.   :674.8   Max.   :506.3   Max.   :627.17  
    B-A-GU1          B-R-PC2          B-A-MU2         B-A-GU2     
 Min.   :  0.00   Min.   :  0.00   Min.   :  0.0   Min.   :  0.0  
 1st Qu.: 61.86   1st Qu.: 97.35   1st Qu.:116.4   1st Qu.:117.4  
 Median :132.50   Median :132.06   Median :147.2   Median :150.7  
 Mean   :192.52   Mean   :206.76   Mean   :202.8   Mean   :220.2  
 3rd Qu.:276.82   3rd Qu.:272.92   3rd Qu.:260.1   3rd Qu.:255.8  
 Max.   :635.41   Max.   :625.57   Max.   :550.8   Max.   :632.8  
    B-R-PC3         B-A-MU3         B-A-GU3         B-R-PC4      
 Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.00  
 1st Qu.:148.0   1st Qu.:457.7   1st Qu.:352.8   1st Qu.: 97.15  
 Median :171.8   Median :518.2   Median :358.7   Median :146.76  
 Mean   :226.2   Mean   :480.4   Mean   :379.5   Mean   :216.44  
 3rd Qu.:254.2   3rd Qu.:533.7   3rd Qu.:397.0   3rd Qu.:282.36  
 Max.   :619.0   Max.   :624.8   Max.   :707.3   Max.   :641.26  
    B-A-MU4         B-A-GU4     
 Min.   :  0.0   Min.   :  0.0  
 1st Qu.:614.0   1st Qu.:230.6  
 Median :633.2   Median :243.5  
 Mean   :600.1   Mean   :286.8  
 3rd Qu.:642.6   3rd Qu.:299.7  
 Max.   :707.3   Max.   :669.4  

Temos então que m é 26, portanto a matriz de distâncias tem 325 valores.

Fazemos agora um breve sumário do que foi calculado até agora.

Sumario2 <- cbind(min(euclid_ma),
                  max(euclid_ma),
                  sd(euclid_ma),
                  mean(euclid_ma),
                  length(euclid_ma))
colnames(Sumario2) <- c("Minimo", "Maximo", "Desv.Padr", "Media", "m(m-1)/2")
rownames(Sumario2) <- ("Valores")
Sumario2
        Minimo   Maximo Desv.Padr   Media m(m-1)/2
Valores      0 707.3267  178.1842 274.908      676

7.1 Removendo os zeros da matriz de distâncias

euclid_ma <- as.matrix(euclid)
#euclid_ma
range(euclid_ma)
mean(euclid_ma)
sd(euclid_ma)
is.na(euclid_ma) <- euclid_ma==0 #atribui n.a. aos valores = 0
colMeans(euclid_ma, na.rm=T) #omite valores n.a. do calculo
rowMeans(euclid_ma, na.rm=T) #omite valores n.a. do calculo
[1]   0.0000 707.3267
[1] 274.908
[1] 178.1842
 S-A-ZA1  S-R-CC1  S-R-CT1  S-R-CP1  S-A-TA1  S-R-CT2  S-R-CP2  S-A-TA2 
202.2608 205.9912 266.3790 195.7828 195.8495 317.0479 207.1435 268.5172 
 S-R-CT3  S-R-CP3  S-A-TA3  S-R-CT4  S-R-CP4  S-A-TA4  B-A-MU1  B-R-ET1 
455.6678 199.1922 347.0119 280.9253 217.3521 458.7988 278.0482 205.3272 
 B-A-GU1  B-R-PC2  B-A-MU2  B-A-GU2  B-R-PC3  B-A-MU3  B-A-GU3  B-R-PC4 
200.2219 215.0274 210.8910 229.0481 235.2979 499.5754 394.6795 225.0953 
 B-A-MU4  B-A-GU4 
624.1237 298.2560 
 S-A-ZA1  S-R-CC1  S-R-CT1  S-R-CP1  S-A-TA1  S-R-CT2  S-R-CP2  S-A-TA2 
202.2608 205.9912 266.3790 195.7828 195.8495 317.0479 207.1435 268.5172 
 S-R-CT3  S-R-CP3  S-A-TA3  S-R-CT4  S-R-CP4  S-A-TA4  B-A-MU1  B-R-ET1 
455.6678 199.1922 347.0119 280.9253 217.3521 458.7988 278.0482 205.3272 
 B-A-GU1  B-R-PC2  B-A-MU2  B-A-GU2  B-R-PC3  B-A-MU3  B-A-GU3  B-R-PC4 
200.2219 215.0274 210.8910 229.0481 235.2979 499.5754 394.6795 225.0953 
 B-A-MU4  B-A-GU4 
624.1237 298.2560 

8 Procurando outliers

8.1 Listas de distâncias

Vamos agora crias uma lista com as distâncias em desvio padrão entre cada objeto e o centróide, baseado na matriz euclid_ma. A distância média do centroide expressa em desvios padrão também podem ser chamadas de z-scores.

library(matrixStats)
library(moments)
av.dist <- (as.matrix(colMeans(euclid_ma, na.rm=T)))
av.desvpad <- (as.matrix(colSds(euclid_ma, na.rm=T)))
dp.centroide_ma <- (av.dist-centroide_ma)/(colSds(av.dist)) #ou z-scores
list <- as.matrix(cbind(av.dist, av.desvpad, dp.centroide_ma))
list
            [,1]      [,2]        [,3]
S-A-ZA1 202.2608 175.36143 -0.64389921
S-R-CC1 205.9912 142.40233 -0.61083578
S-R-CT1 266.3790  93.46194 -0.07559585
S-R-CP1 195.7828 170.97514 -0.70131587
S-A-TA1 195.8495 170.39163 -0.70072510
S-R-CT2 317.0479  82.87727  0.37350168
S-R-CP2 207.1435 167.09006 -0.60062195
S-A-TA2 268.5172 124.64348 -0.05664389
S-R-CT3 455.6678  68.84928  1.60214211
S-R-CP3 199.1922 170.79087 -0.67109728
S-A-TA3 347.0119  92.95522  0.63908396
S-R-CT4 280.9253 131.44373  0.05333414
S-R-CP4 217.3521 157.62618 -0.51013918
S-A-TA4 458.7988  93.50892  1.62989392
B-A-MU1 278.0482 116.17286  0.02783285
B-R-ET1 205.3272 169.74682 -0.61672073
B-A-GU1 200.2219 174.32564 -0.66197044
B-R-PC2 215.0274 152.54520 -0.53074369
B-A-MU2 210.8910 128.79692 -0.56740645
B-A-GU2 229.0481 151.90782 -0.40647373
B-R-PC3 235.2979 130.07777 -0.35107902
B-A-MU3 499.5754  64.70789  1.99131169
B-A-GU3 394.6795 116.02951  1.06158063
B-R-PC4 225.0953 158.58714 -0.44150812
B-A-MU4 624.1237  45.46670  3.09523062
B-A-GU4 298.2560 130.86907  0.20694225

Ordenamos as distâncias da maior para a menor

colnames(list, do.NULL = FALSE)
colnames(list) <- c("Av.Dist", "Av.StDev", "DP.Centroide")
list2 <- list[order(list[,1], decreasing = TRUE),] #[,1] ou o nome da coluna
list2
[1] "col1" "col2" "col3"
         Av.Dist  Av.StDev DP.Centroide
B-A-MU4 624.1237  45.46670   3.09523062
B-A-MU3 499.5754  64.70789   1.99131169
S-A-TA4 458.7988  93.50892   1.62989392
S-R-CT3 455.6678  68.84928   1.60214211
B-A-GU3 394.6795 116.02951   1.06158063
S-A-TA3 347.0119  92.95522   0.63908396
S-R-CT2 317.0479  82.87727   0.37350168
B-A-GU4 298.2560 130.86907   0.20694225
S-R-CT4 280.9253 131.44373   0.05333414
B-A-MU1 278.0482 116.17286   0.02783285
S-A-TA2 268.5172 124.64348  -0.05664389
S-R-CT1 266.3790  93.46194  -0.07559585
B-R-PC3 235.2979 130.07777  -0.35107902
B-A-GU2 229.0481 151.90782  -0.40647373
B-R-PC4 225.0953 158.58714  -0.44150812
S-R-CP4 217.3521 157.62618  -0.51013918
B-R-PC2 215.0274 152.54520  -0.53074369
B-A-MU2 210.8910 128.79692  -0.56740645
S-R-CP2 207.1435 167.09006  -0.60062195
S-R-CC1 205.9912 142.40233  -0.61083578
B-R-ET1 205.3272 169.74682  -0.61672073
S-A-ZA1 202.2608 175.36143  -0.64389921
B-A-GU1 200.2219 174.32564  -0.66197044
S-R-CP3 199.1922 170.79087  -0.67109728
S-A-TA1 195.8495 170.39163  -0.70072510
S-R-CP1 195.7828 170.97514  -0.70131587

8.2 Distribuição de frequências das distâncias médias para o centróide av.dist

Observe o valor maximo e minimo gerados pela função range() e substitua nas linhas de código assinaladas com #. Aqui o menor valor foi 195.7828431 e o maior valor foi 624.1236964. Use valores maiores para facilitar a visualização no gráfico (Figura 5).

par(mfrow=c(3,1))
hist(list2[, "Av.Dist"],
     breaks = 15, #determina o no. de colunas do histograma
     xlab = "Distr. de Frequências das Distâncias (em dp) para o centroide",
     main = "Distribuição de Frequência da distância média para o centroide",
     xlim = range(100, 700), #substitua aqui o menor e maior valor do `range()`
     freq = T)
hist(list2[, "Av.Dist"],
     breaks = 15, #determina o no. de colunas do histograma
     xlab = "Distr. de Frequências das Distâncias (em dp) para o centroide",
     main = "Curva de normalidade ajustada para a Distribuição de Frequência",
     xlim = range(100, 700), #substitua aqui o menor e maior valor do `range()`
     freq = F)
curve(dnorm(x, mean=mean(list2[, "Av.Dist"]), sd=sd(list2[, "Av.Dist"])), add=TRUE)
boxplot.default(list2[, "Av.Dist"], horizontal = TRUE, frame = FALSE,
                xlab="Distr. de Frequências",
                ylim=c(100,700)) #substitua aqui o menor e maior valor do `range()`

Figura 5: Distribuição de frequências das distâncias médias para o centroide.

Se necessário apague os gráficos

dev.off()

9 Lista final de outliers

Agora fazemos a lista final de distâncias com os outliers baseados em um ‘cutoff’.

cutoff <- 2.0

Note que o ‘cutoff’ foi estabelecido no código acima no vetor ‘cutoff <-’. Ou seja, o ‘cutoff’ definindo quem serão considerados outliers, foi estabelecido como sendo valores de +2.0 e -2.0 desvios padrões da média multivariada ou centroide. Valores acima ou abaixo do ‘cutoff’ definido recebem o nome “OUT”, na coluna “Outliers”. Criada com o código abaixo.

library(gt)
format(cutoff, nsmall = 1)
listf <- as.data.frame(list2)
listf$Outliers <- ifelse(listf$DP.Centroide>-cutoff #CUTOFF MENOR QUE -'cutoff
                         & listf$DP.Centroide<cutoff,  #CUTOFF MAIOR QUE 'cutoff'
                         "", "OUT") 
listf
gt(cbind(Sitios=rownames(listf),listf))
[1] "2.0"
         Av.Dist  Av.StDev DP.Centroide Outliers
B-A-MU4 624.1237  45.46670   3.09523062      OUT
B-A-MU3 499.5754  64.70789   1.99131169         
S-A-TA4 458.7988  93.50892   1.62989392         
S-R-CT3 455.6678  68.84928   1.60214211         
B-A-GU3 394.6795 116.02951   1.06158063         
S-A-TA3 347.0119  92.95522   0.63908396         
S-R-CT2 317.0479  82.87727   0.37350168         
B-A-GU4 298.2560 130.86907   0.20694225         
S-R-CT4 280.9253 131.44373   0.05333414         
B-A-MU1 278.0482 116.17286   0.02783285         
S-A-TA2 268.5172 124.64348  -0.05664389         
S-R-CT1 266.3790  93.46194  -0.07559585         
B-R-PC3 235.2979 130.07777  -0.35107902         
B-A-GU2 229.0481 151.90782  -0.40647373         
B-R-PC4 225.0953 158.58714  -0.44150812         
S-R-CP4 217.3521 157.62618  -0.51013918         
B-R-PC2 215.0274 152.54520  -0.53074369         
B-A-MU2 210.8910 128.79692  -0.56740645         
S-R-CP2 207.1435 167.09006  -0.60062195         
S-R-CC1 205.9912 142.40233  -0.61083578         
B-R-ET1 205.3272 169.74682  -0.61672073         
S-A-ZA1 202.2608 175.36143  -0.64389921         
B-A-GU1 200.2219 174.32564  -0.66197044         
S-R-CP3 199.1922 170.79087  -0.67109728         
S-A-TA1 195.8495 170.39163  -0.70072510         
S-R-CP1 195.7828 170.97514  -0.70131587         
Sitios Av.Dist Av.StDev DP.Centroide Outliers
B-A-MU4 624.1237 45.46670 3.09523062 OUT
B-A-MU3 499.5754 64.70789 1.99131169
S-A-TA4 458.7988 93.50892 1.62989392
S-R-CT3 455.6678 68.84928 1.60214211
B-A-GU3 394.6795 116.02951 1.06158063
S-A-TA3 347.0119 92.95522 0.63908396
S-R-CT2 317.0479 82.87727 0.37350168
B-A-GU4 298.2560 130.86907 0.20694225
S-R-CT4 280.9253 131.44373 0.05333414
B-A-MU1 278.0482 116.17286 0.02783285
S-A-TA2 268.5172 124.64348 -0.05664389
S-R-CT1 266.3790 93.46194 -0.07559585
B-R-PC3 235.2979 130.07777 -0.35107902
B-A-GU2 229.0481 151.90782 -0.40647373
B-R-PC4 225.0953 158.58714 -0.44150812
S-R-CP4 217.3521 157.62618 -0.51013918
B-R-PC2 215.0274 152.54520 -0.53074369
B-A-MU2 210.8910 128.79692 -0.56740645
S-R-CP2 207.1435 167.09006 -0.60062195
S-R-CC1 205.9912 142.40233 -0.61083578
B-R-ET1 205.3272 169.74682 -0.61672073
S-A-ZA1 202.2608 175.36143 -0.64389921
B-A-GU1 200.2219 174.32564 -0.66197044
S-R-CP3 199.1922 170.79087 -0.67109728
S-A-TA1 195.8495 170.39163 -0.70072510
S-R-CP1 195.7828 170.97514 -0.70131587

10 Particionando a matriz

Talvez seja necessário particionar a matriz bruta para remover os outliers. Isso pode ser feito com os códigos abaixo. Atente para o vetor part. Ele define quais objetos ou UA’s serão particionados.

part <- c("B-A-MU4", "B-A-MU3", "S-A-TA4", "S-R-CT3")
part
[1] "B-A-MU4" "B-A-MU3" "S-A-TA4" "S-R-CT3"
ppbiopart <- ppbio[!(row.names(ppbio) %in% c(part)),]
#ppbiopart

Criamos uma nova matriz particionada ppbiopart sem B-A-MU4, B-A-MU3, S-A-TA4, S-R-CT3, que apresentavam valores acima do cutoff para outliers.

IMPORTANTE

Quando deletamos linhas ou colunas da matriz de dados comunitária, precisamos ver se isso não gerou linhas ou colunas vazias. Observe por exemplo a espécie Apareiodon davisi 4 (Figura 6). Por exemplo, se uma determinada espécie só ocorre em uma UA, e aquela UA foi removida, essa espécie não consta mais em nenhuma UA e por isso a sua soma vai ser igual a zero. Isso aconteceu com a espécie Pseudancistrus genisetiger 5 (Figura 7). Essa espécie precisará ser removida.

Figura 6: Apareiodon davisi, importante espécie bentopelágica das bacias dos rios Jaguaribe e Paraíba. Brazil, by Ramos, T.P.A. Fonte: https://www.fishbase.se/summary/Astianax-bimaculatus.html

Figura 7: Pseudancistrus genisetiger, uma espécie endêmica das bacias hidrográfcas do nordeste. By eplanetcatfish.com. Fonte: https://www.planetcatfish.com (Provável identificação errada do espécime da foto)

Use o a função View(ppbiopart) e procure linhas ou colunas na matriz ppbiopart onde todos os valores são zero. Quais espéies você encontrou que deixaram de ocorrer na comunidade depois que as UA’s outliers foram removidas?.

Complicado? Os códigos abaixo resolvem isso, e mostram algumas propriedades da nova matriz ppbiopart2 depois de particionada pela segunda vez para remover linhas/colunas “zeradas”.

sum <- colSums(ppbiopart)
sum
zero_sum_cols <- names(which(colSums(ppbiopart) == 0))
zero_sum_cols #nomes das espécies zeradas

ppbiopart2 <- ppbiopart[(colSums(ppbiopart) != 0)] #em != a exclamação inverte o sentido

zero_sum_cols2 <- names(which(colSums(ppbiopart2) == 0))
zero_sum_cols2 #nomes das espécies zeradas
sum<-colSums(ppbiopart2)
sum
#ppbiopart2
#ppbiopart2 <- as.matrix(ppbiopart2)
str(ppbiopart2)
length(as.matrix(ppbiopart2))
 ap-davis  as-bimac  as-fasci  ch-bimac  ci-ocela  ci-orien  co-macro  co-heter 
       27      1040        94       432        70       118         2         1 
 cr-menez  cu-lepid  cy-gilbe  ge-brasi  he-margi  ho-malab  hy-pusar  le-melan 
       19        21       131       364         2        69        60         2 
  le-piau  le-taeni  mo-costa  mo-lepid  or-nilot  pa-manag  pimel-sp  po-retic 
       11         1         1        41       697       554         6        64 
 po-vivip  pr-brevi  ps-rhomb ps-genise  se-heter  se-piaba  se-spilo  st-noton 
      441       111         0         0       258        68         0        90 
 sy-marmo  te-chalc  tr-signa 
        1       134       201 
[1] "ps-rhomb"  "ps-genise" "se-spilo" 
character(0)
ap-davis as-bimac as-fasci ch-bimac ci-ocela ci-orien co-macro co-heter 
      27     1040       94      432       70      118        2        1 
cr-menez cu-lepid cy-gilbe ge-brasi he-margi ho-malab hy-pusar le-melan 
      19       21      131      364        2       69       60        2 
 le-piau le-taeni mo-costa mo-lepid or-nilot pa-manag pimel-sp po-retic 
      11        1        1       41      697      554        6       64 
po-vivip pr-brevi se-heter se-piaba st-noton sy-marmo te-chalc tr-signa 
     441      111      258       68       90        1      134      201 
'data.frame':   22 obs. of  32 variables:
 $ ap-davis: num  0 0 0 0 0 0 0 0 0 0 ...
 $ as-bimac: num  1 99 194 19 23 142 5 46 16 234 ...
 $ as-fasci: num  0 0 55 0 1 3 1 0 0 7 ...
 $ ch-bimac: num  0 0 0 0 13 3 0 178 0 238 ...
 $ ci-ocela: num  0 0 0 0 0 0 40 0 13 0 ...
 $ ci-orien: num  0 0 5 0 0 69 9 0 24 0 ...
 $ co-macro: num  0 0 0 0 0 0 0 0 0 2 ...
 $ co-heter: num  0 0 1 0 0 0 0 0 0 0 ...
 $ cr-menez: num  0 0 14 0 0 4 0 0 0 0 ...
 $ cu-lepid: num  0 0 0 0 0 0 0 0 0 0 ...
 $ cy-gilbe: num  0 0 0 0 0 0 0 0 0 0 ...
 $ ge-brasi: num  0 0 3 0 0 0 0 0 0 0 ...
 $ he-margi: num  0 0 0 0 0 1 0 0 0 0 ...
 $ ho-malab: num  0 0 1 5 0 17 10 2 4 20 ...
 $ hy-pusar: num  0 0 9 2 0 43 2 0 0 0 ...
 $ le-melan: num  0 0 0 0 0 0 0 0 0 0 ...
 $ le-piau : num  0 0 3 0 0 1 3 0 1 0 ...
 $ le-taeni: num  0 0 0 0 0 0 0 0 0 0 ...
 $ mo-costa: num  0 0 0 0 0 0 0 0 0 0 ...
 $ mo-lepid: num  0 1 39 0 0 1 0 0 0 0 ...
 $ or-nilot: num  0 2 36 0 0 77 0 0 0 0 ...
 $ pa-manag: num  0 0 0 0 0 0 0 0 0 0 ...
 $ pimel-sp: num  0 0 6 0 0 0 0 0 0 0 ...
 $ po-retic: num  0 0 0 0 0 20 0 0 0 0 ...
 $ po-vivip: num  0 0 47 15 0 221 32 0 10 0 ...
 $ pr-brevi: num  9 0 5 0 1 15 5 2 0 0 ...
 $ se-heter: num  0 0 40 14 4 60 0 0 0 0 ...
 $ se-piaba: num  0 0 68 0 0 0 0 0 0 0 ...
 $ st-noton: num  0 0 1 0 0 25 0 0 0 0 ...
 $ sy-marmo: num  0 0 0 0 0 0 1 0 0 0 ...
 $ te-chalc: num  0 0 0 0 0 0 0 0 0 0 ...
 $ tr-signa: num  0 0 18 0 0 15 0 0 0 0 ...
[1] 704

11 Exportando a matrix final de trabalho

Agora vamos exportar a matrix de trabalho, nesse casso a matrix ppbiopart2, como um arquivo de valores separados por vírgula (ppbiopart2csv.csv). Na verdade, separado por ";", como definido na funçao sep = ";". O arquivo será exportado para o diretório de trabalho. Na mesma sequência de códigos, importamos ppbiopart2csv.csv como nossa matriz de trabalho m_trab.

df <- data.frame(Sites = rownames(ppbio), ppbio,
                 row.names = NULL,
                 check.names = FALSE) #add titulo a primeira coluna

write.table(ppbiopart2, "m_trabcsv.csv",
            sep = ";", dec = ".", #"\t",
            row.names = TRUE,
            quote = TRUE,
            append = FALSE)

m_trab <- read.csv("m_trabcsv.csv",
                   sep = ";", dec = ".",
                   row.names = 1,
                   header = TRUE, 
                   na.strings = NA,
                   check.names = FALSE, #impede que o R mude os nomes das colunas
                   col.names = gsub("(^|_)([a-z])", "\\1\\U\\2",
                                    names(m_trab), perl = TRUE))

Agora é com você…Refaça toda a análise com a matriz bruta particionada ppbiopart2

12 Referências

Borcard, D., F. Gillet, e P. Legendre. 2018. Numerical Ecology with R. Página 435. Segunda edição. Book, Springer.
Horton, N. J., e K. Kleinman. 2015. Using R and RStudio for Data Management, Statistical Analysis, and Graphics. Página 253. Segunda edição. Book, CRC Press.
Legendre, P., e L. Legendre. 1998. Numerical Ecology. Página 853. 2nd English ed. Book, Amsterdam, The Netherlands ; New York ; Oxford.

Apêndices

Outras formas de fazer a partição

ppbiopart2 <- ppbiopart[colSums(abs(ppbiopart), na.rm = F) > 0] ppbiopart2 <- subset(ppbiopart, colSums != 0) ppbiopart2 <- ppbiopart[, colSums(ppbiopart != 0) > 0]

Código

range(euclidma) par(mfrow=c(2,1)) hist(euclidma, breaks = 15, #determina o no. de colunas do histograma xlim = range(floor(min(euclidma)), ceiling(max(euclidma))), xlab = “Distr. de Frequências”, freq = FALSE) curve(dnorm(x, mean=mean(euclidma), sd=sd(euclidma)), add=TRUE) boxplot.default(euclidma, horizontal = TRUE, frame = FALSE, xlab=“Distr. de Frequências”, ylim=c(floor(min(euclidma)), ceiling(max(euclidma)))) #Limites do eixo Y

Notas de rodapé

  1. Semestre 2023.1↩︎

  2. A etimologia do gênero Astyanax vem da mitologia Grega. Heitor personagem da “Ilíada”, tinha um filho chamado Astíanax.↩︎

  3. Do Grego, hoplon, arma ou armadura, em referência aos dentes caniniformes muito desenvolvidos, e forte estrutura óssea na cabeça.↩︎

  4. A etimologia do nome Apareiodon vem do Grego, a, sem, pareia, lateral ou bochecha, e odous dentição, em referencia a ausência de tentes laterais no aparato bucal dessa espécie.↩︎

  5. A etimologia do nome Pseudancistrus vem do Grego, pseudes, falso, e agkistron, gancho, em referência a falsos ganchos presentes na cabeça em algumas espécies do gênero.↩︎