Introdução

Análise multivariada com dados de solo, clima, espécies e economia.

Carregando os pacotes:

knitr::opts_chunk$set(warning = FALSE, message = FALSE)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   4.0.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.2.0     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(FactoMineR)
library(factoextra)
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(cluster)
library(psych)
## 
## Anexando pacote: 'psych'
## 
## Os seguintes objetos são mascarados por 'package:ggplot2':
## 
##     %+%, alpha
library(GGally)
## Registered S3 method overwritten by 'GGally':
##   method from   
##   +.gg   ggplot2
library(plotly)
## 
## Anexando pacote: 'plotly'
## 
## O seguinte objeto é mascarado por 'package:ggplot2':
## 
##     last_plot
## 
## O seguinte objeto é mascarado por 'package:stats':
## 
##     filter
## 
## O seguinte objeto é mascarado por 'package:graphics':
## 
##     layout
library(corrplot)
## corrplot 0.95 loaded

Arquivos de dados

dados <- read.csv("dataset_agroamazonia.csv")
# Disponivel em: https://raw.githubusercontent.com/leocbc/ANALISE-MULTIVARIADA/refs/heads/main/dataset_agroamazonia.csv
head(dados)
##   Area_ID  Latitude Longitude  Especie      Solo Prod_Anual_Ton Biomassa_t_ha
## 1    A001 -2.685649 -60.43496    Cacau Argissolo          29.96         18.58
## 2    A002 -3.342177 -59.53927    Cacau Argissolo          28.55         17.27
## 3    A003 -3.437038 -59.86948    Cacau Gleissolo          29.39         13.39
## 4    A004 -2.917896 -60.26652  Cupuaçu  Neossolo          23.59         25.01
## 5    A005 -2.648850 -58.97968    Cacau Latossolo          29.33         14.68
## 6    A006 -3.123030 -59.17999 Castanha  Neossolo          31.95         21.11
##   Teor_Carbono_pct Indice_Sustentabilidade Custo_Producao_R..ha
## 1            45.07                    0.67              2906.81
## 2            50.30                    0.89              3225.89
## 3            58.72                    0.69              2408.95
## 4            45.16                    0.42              3433.00
## 5            52.10                    0.65              3891.29
## 6            51.03                    0.81              3507.04
##   Preco_Venda_R..Ton CH4_emissao_kg_ha N2O_emissao_kg_ha Temp_Solo_C
## 1             919.17             57.96              6.06       25.52
## 2             700.74             79.71              6.06       30.29
## 3             970.64             79.79              4.12       25.43
## 4            1059.98             80.59              6.51       30.12
## 5            1207.18             57.19              6.36       26.99
## 6             904.19             42.22              4.34       30.27
##   Umidade_Solo_pct Precipitacao_mm
## 1            44.28         2044.60
## 2            29.09         2443.79
## 3            40.50         1864.04
## 4            47.10         2354.28
## 5            44.94         2263.93
## 6            39.40         2699.78

Estatística Descritiva

summary(dados)
##    Area_ID             Latitude        Longitude        Especie         
##  Length:80          Min.   :-3.774   Min.   :-61.19   Length:80         
##  Class :character   1st Qu.:-3.294   1st Qu.:-60.47   Class :character  
##  Mode  :character   Median :-2.976   Median :-59.95   Mode  :character  
##                     Mean   :-2.998   Mean   :-59.97                     
##                     3rd Qu.:-2.709   3rd Qu.:-59.44                     
##                     Max.   :-2.223   Max.   :-58.81                     
##      Solo           Prod_Anual_Ton  Biomassa_t_ha   Teor_Carbono_pct
##  Length:80          Min.   :14.93   Min.   :12.31   Min.   :37.78   
##  Class :character   1st Qu.:24.49   1st Qu.:17.07   1st Qu.:46.47   
##  Mode  :character   Median :29.02   Median :19.34   Median :49.73   
##                     Mean   :28.97   Mean   :19.59   Mean   :49.48   
##                     3rd Qu.:32.97   3rd Qu.:22.59   3rd Qu.:52.18   
##                     Max.   :50.71   Max.   :28.23   Max.   :58.93   
##  Indice_Sustentabilidade Custo_Producao_R..ha Preco_Venda_R..Ton
##  Min.   :0.3200          Min.   :1648         Min.   : 637.5    
##  1st Qu.:0.5150          1st Qu.:3258         1st Qu.: 818.8    
##  Median :0.6650          Median :3672         Median : 901.4    
##  Mean   :0.6636          Mean   :3633         Mean   : 898.8    
##  3rd Qu.:0.8125          3rd Qu.:4050         3rd Qu.: 971.0    
##  Max.   :0.9700          Max.   :4952         Max.   :1207.2    
##  CH4_emissao_kg_ha N2O_emissao_kg_ha  Temp_Solo_C    Umidade_Solo_pct
##  Min.   : 30.90    Min.   :1.650     Min.   :23.92   Min.   :22.83   
##  1st Qu.: 55.36    1st Qu.:3.605     1st Qu.:26.98   1st Qu.:40.12   
##  Median : 60.46    Median :4.725     Median :27.93   Median :44.41   
##  Mean   : 62.15    Mean   :4.660     Mean   :27.99   Mean   :43.89   
##  3rd Qu.: 69.37    3rd Qu.:5.673     3rd Qu.:29.23   3rd Qu.:48.48   
##  Max.   :102.86    Max.   :7.800     Max.   :33.81   Max.   :57.05   
##  Precipitacao_mm
##  Min.   :1772   
##  1st Qu.:2169   
##  Median :2380   
##  Mean   :2364   
##  3rd Qu.:2566   
##  Max.   :3047

Extraindo apenas as variáveis numéricas:

dados_num <- dados %>% select(where(is.numeric))
head(dados_num)
##    Latitude Longitude Prod_Anual_Ton Biomassa_t_ha Teor_Carbono_pct
## 1 -2.685649 -60.43496          29.96         18.58            45.07
## 2 -3.342177 -59.53927          28.55         17.27            50.30
## 3 -3.437038 -59.86948          29.39         13.39            58.72
## 4 -2.917896 -60.26652          23.59         25.01            45.16
## 5 -2.648850 -58.97968          29.33         14.68            52.10
## 6 -3.123030 -59.17999          31.95         21.11            51.03
##   Indice_Sustentabilidade Custo_Producao_R..ha Preco_Venda_R..Ton
## 1                    0.67              2906.81             919.17
## 2                    0.89              3225.89             700.74
## 3                    0.69              2408.95             970.64
## 4                    0.42              3433.00            1059.98
## 5                    0.65              3891.29            1207.18
## 6                    0.81              3507.04             904.19
##   CH4_emissao_kg_ha N2O_emissao_kg_ha Temp_Solo_C Umidade_Solo_pct
## 1             57.96              6.06       25.52            44.28
## 2             79.71              6.06       30.29            29.09
## 3             79.79              4.12       25.43            40.50
## 4             80.59              6.51       30.12            47.10
## 5             57.19              6.36       26.99            44.94
## 6             42.22              4.34       30.27            39.40
##   Precipitacao_mm
## 1         2044.60
## 2         2443.79
## 3         1864.04
## 4         2354.28
## 5         2263.93
## 6         2699.78

Correlograma

cor_matrix <- cor(dados_num)
p_matrix <- cor.mtest(dados_num)$p
corrplot(
  cor_matrix,
  p.mat = p_matrix,      # Fornecer a matriz de p-valores
  sig.level = 0.05,      # Definir o nível de significância
  insig = "blank",       # Corresponder ao argumento desejado (deixa em branco)
  type = "upper",        # Exemplo: mostrar apenas a parte superior
  order = "hclust",
  tl.col = "black",
  tl.srt = 45
)

Escalonando os dados:

dados_scaled <- scale(dados_num)

Heatmap (mapa de calor)

heatmap(cor(dados_num))

PCA e PCA 3D

Calculo da PCA:

pca <- prcomp(dados_scaled)

Gráfico 2D:

fviz_pca_biplot(pca, label="var")

Gráfico 3D:

plot_ly(x=pca$x[,1], y=pca$x[,2], z=pca$x[,3],
        type="scatter3d", mode="markers",
        color=dados$Especie)

Agrupamento Hierárquico

A Análise de Agrupamento (Cluster Analysis) busca descobrir agrupamentos naturais de observações (áreas, no nosso caso) com base em suas similaridades (ou distâncias/dissimilaridades). O método hierárquico cria uma estrutura em árvore (dendrograma), podendo ser aglomerativo (começa com observações individuais) ou divisivo (começa com um único grupo).

Medidas de Distância (Dissimilaridade)

A escolha da métrica de distância é crucial, pois ela define o que significa “próximo” ou “similar” no seu conjunto de dados.

Distância Euclidiana (Padrão e Simples)

A distância Euclidiana entre dois pontos \(\mathbf{x}\) e \(\mathbf{y}\) é:

\[ D_E(\mathbf{x}, \mathbf{y}) = \sqrt{\sum_{i=1}^{n} (x_i - y_i)^2} \]

Distancia Euclidiana
Distancia Euclidiana
  • Uso: É a distância mais comum, calculada como a raiz quadrada da soma das diferenças ao quadrado entre os pontos em cada dimensão.
  • Vantagem: Fácil de entender e calcular.
  • Desvantagem: Sensível a diferenças de escala e outliers (por isso a padronização dados_scaled - é essencial).
dist_eucl <- dist(dados_scaled)

Distância de Manhattan (ou “City-Block”)

A distância Manhattan entre dois pontos \(\mathbf{x}\) e \(\mathbf{y}\) é:

\[ D_M(\mathbf{x}, \mathbf{y}) = \sum_{i=1}^{n} \left| x_i - y_i \right| \]

Explicação da Distância de Manhattan (YouTube)

  • Uso: Soma das distâncias absolutas entre os pontos ao longo de cada dimensão.
  • Vantagem: Menos sensível a outliers extremos do que a Euclidiana, pois não eleva as diferenças ao quadrado.
  • Aplicação Agronômica: Útil quando as diferenças em variáveis específicas têm um impacto linear, e não quadrático, na dissimilaridade.
dist_manh <- dist(dados_scaled, method = "manhattan")

Distância de Mahalanobis (Avançada)

A distância de Mahalanobis é dada por:

\[ D_M(\mathbf{x}) = \sqrt{(\mathbf{x} - \boldsymbol{\mu})^\top \mathbf{S}^{-1} (\mathbf{x} - \boldsymbol{\mu})} \]

  • Uso: Leva em conta a correlação entre as variáveis e a escala de cada uma.
  • Vantagem: Elimina o efeito da correlação e da escala. É ideal quando as variáveis não são independentes.
  • Desvantagem: Requer a inversa da matriz de covariância, o que pode ser problemático com muitas variáveis ou alta colinearidade.
dist_mahal <- mahalanobis(dados_scaled, center=FALSE, cov=cov(dados_scaled))

Clusterização Aglomerativa

Após a definição da distância, é necessário escolher o método de ligação (linkage), que define como a distância entre grupos de observações é calculada.

Método de Ward (ward.D2)

  • Uso: Minimização da soma dos quadrados dos erros (variância) dentro de cada cluster.
  • Vantagem: Tende a formar clusters compactos e esféricos, e é um dos mais recomendados em Ciências Agrárias.
hc_ward <- hclust(dist_eucl, method="ward.D2")

Método de Ligação Completa (Complete Linkage)

  • Uso: Distância entre os dois pontos mais distantes dos dois clusters.
  • Vantagem: Tende a produzir clusters mais compactos e de tamanho uniforme.
  • Desvantagem: Muito sensível a outliers, que podem forçar a fusão tardia de clusters.
hc_complete <- hclust(dist_eucl, method="complete")

Método de Ligação Simples (Single Linkage)

  • Uso: Distância entre os dois pontos mais próximos dos dois clusters (Vizinho Mais Próximo).
  • Vantagem: Útil para identificar clusters com formatos não-esféricos ou em formato de cadeia (chaining effect).
  • Desvantagem: Muito sensível a ruído ou outliers; pode criar clusters longos e pouco coesos.
hc_single <- hclust(dist_eucl, method="single")

Método da Média das Distâncias (Average Linkage - UPGMA)

  • Uso: Calcula a distância média entre todos os pares de pontos nos dois clusters.
  • Vantagem: Equilíbrio entre os métodos ‘single’ e ‘complete’; menos sensível a outliers que o ‘single’ e tende a formar grupos com número similar de parcelas.
hc_average <- hclust(dist_eucl, method="average")

Dendrograma e Interpretação

O dendrograma mostra a sequência de fusão dos clusters. A altura do corte (rect.hclust) define o número final de grupos (k).

Plota o dendrograma usando o método de Ward e traça uma linha para sugerir 4 clusters. A escolha de ‘k’ deve ser baseada em critérios científicos/técnicos

plot(hc_ward, labels=dados$Area_ID)

plot(hc_ward, labels=dados$Area_ID)

rect.hclust(hc_ward, k=4, border=2:5)

K-means (Agrupamento Não-Hierárquico)

O K-Means é um algoritmo de clusterização não hierárquica e particional, o que significa que ele divide um conjunto de dados (N observações) em um número pré-determinado (K) de clusters (agrupamentos). O objetivo é minimizar a variação (distância) dentro de cada cluster. Ele requer a definição prévia do número de clusters (k).

Algoritmo:

1. Inicialização

  • Passo 1: Escolha de K: O usuário deve definir o número de clusters desejados, K.

  • Passo 2: Centróides Iniciais: O algoritmo seleciona K pontos aleatórios do conjunto de dados para servir como os centróides iniciais dos clusters (representantes ou centros).

2. Atribuição

  • Passo 3: Atribuir Pontos: Cada ponto de dado restante é atribuído ao centróide mais próximo com base em uma métrica de distância (geralmente a Distância Euclidiana).

  • Para cada ponto x, ele é colocado no cluster cujo centróide é o mais próximo.

3. Atualização

  • Passo 4: Recalcular Centróides: Após todos os pontos terem sido atribuídos, o centróide de cada cluster é recalculado. O novo centróide é o ponto médio (média) de todos os pontos de dado atualmente atribuídos àquele cluster

  • Considerando 4 grupos:

k4 <- kmeans(dados_scaled, 4)
k4
## K-means clustering with 4 clusters of sizes 19, 23, 21, 17
## 
## Cluster means:
##      Latitude  Longitude Prod_Anual_Ton Biomassa_t_ha Teor_Carbono_pct
## 1  0.39111779 -0.7656249      0.4224490    -0.3323734       -0.6313788
## 2 -0.01014312  0.6021894     -0.2118889     0.6609333       -0.2890420
## 3 -0.02064460 -0.2692243      0.2136493    -0.1291240        0.3202340
## 4 -0.39790645  0.3735429     -0.4493954    -0.3632216        0.7011324
##   Indice_Sustentabilidade Custo_Producao_R..ha Preco_Venda_R..Ton
## 1              -0.7434415           0.28283088        -0.39258515
## 2               0.3525770           0.29929734        -0.18672704
## 3               0.6689402          -0.65206808         0.63049697
## 4              -0.4724486           0.08445907        -0.08744685
##   CH4_emissao_kg_ha N2O_emissao_kg_ha Temp_Solo_C Umidade_Solo_pct
## 1       -0.21601594        -0.6911993  0.21715562       0.34119081
## 2        0.87313408         0.1322675  0.07804069      -0.05439733
## 3       -0.07767496        -0.0209379 -0.94355289      -0.13997704
## 4       -0.84391805         0.6194311  0.81727754      -0.13482170
##   Precipitacao_mm
## 1      -0.7253260
## 2       0.2589624
## 3      -0.3473664
## 4       0.8893973
## 
## Clustering vector:
##  [1] 3 2 3 2 3 4 1 3 1 4 4 2 2 1 3 2 3 1 1 1 3 2 1 1 4 3 2 3 4 2 2 3 3 2 3 3 3 3
## [39] 1 2 2 4 1 2 4 4 1 3 2 4 4 1 2 2 2 1 3 3 1 2 1 1 3 4 1 2 1 4 4 2 3 4 1 2 4 3
## [77] 4 2 4 2
## 
## Within cluster sum of squares by cluster:
## [1] 202.5683 233.7776 201.3413 157.1057
##  (between_SS / total_SS =  22.6 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

Gráfico:

fviz_cluster(k4, data=dados_scaled)

Interpretação:

Esse resultado, onde a Soma dos Quadrados (SS) entre clusters (Between_SS) representa 22,5% da Soma Total dos Quadrados (Total_SS), indica o quanto os clusters estão separados em relação à dispersão total dos dados. Ou seja, 22,5% da variância total nos dados foi explicada pela separação dos centróides dos clusters, ou seja, 77,5% da variância total dos dados ainda está contida dentro dos próprios clusters. Essa é a variância que o modelo de clusterização não conseguiu explicar através da separação.

  • Em suma, valores baixos (como 22,5%): Sugerem que a clusterização não é muito eficiente na separação dos grupos. Grande parte da dispersão dos dados ainda existe dentro dos clusters, sugerindo que embora a clusterização tenha sido feita, ainda há uma alta dispersão (heterogeneidade) dentro dos clusters formados.

Introdução ao Machine Learning Supervisionado: K-Nearest Neighbors (KNN)

O K-Nearest Neighbors (KNN) é um algoritmo de Aprendizado Supervisionado (necessita de rótulos/classes) e não-paramétrico, usado para classificação.

Algoritmo de Classificação:

Quando um novo ponto (\(X_{novo}\)) de dado precisa ser classificado, o KNN executa os seguintes passos:

  • Passo 1: Definir K: Escolha um valor para K (o número de vizinhos a serem considerados). K é tipicamente um número ímpar para evitar empates na votação.

  • Passo 2: Calcular Distâncias: Calcule a distância de \(X_{novo}\) para todos os pontos no conjunto de treinamento. A métrica de distância mais comum é a Euclidiana, mas a de Manhattan também é usada.

  • Passo 3: Encontrar os K Vizinhos: Selecione os K pontos no conjunto de treinamento que possuem a menor distância em relação a \(X_{novo}\)

  • Passo 4: Votação por Maioria: O \(X_{novo}\) é atribuído à classe (rótulo) que for mais frequente entre esses K vizinhos.

1. Separação em conjunto de Treinamento e Teste.

  • Variável de interesse (Resposta) é ‘Especie’, que é categórica.
resposta <- dados$Especie

Criação um vetor de índices. Exemplo: 80% para treino.

indice <- sample(1:nrow(dados_scaled), size = 0.8 * nrow(dados_scaled))
indice
##  [1] 13 73 61  7 53 17 35 41 56 44 69 65 16  6 21 31 55 76 14 15 46 66 71 12 72
## [26] 77 22 52 48  2  1  9 60 78  5 23 18  4 42 45 11  3 64 37 19 75 70 79 51 39
## [51] 59 27 49 43 80 32 29 62 54 50 57 38 40 58

Obtenção dos Dados de Treinamento (80%): usando os indices obtidos no passo anterior

treino_var <- dados_scaled[indice, ] # variáveis (numéricas e padronizadas)
treino_res <- resposta[indice]  # Resposta (Especie)
head(treino_var)
##        Latitude  Longitude Prod_Anual_Ton Biomassa_t_ha Teor_Carbono_pct
## [1,] -0.2555237 -0.5742922      1.1201860     2.1052977       -0.3926804
## [2,]  0.5167360 -0.8270382      1.5162841    -0.9115900        0.2785145
## [3,]  0.6889085 -1.5309047      1.2215134    -1.9101186       -0.3675890
## [4,]  1.9636847 -0.5688907      0.7808927    -1.0367390       -2.2452621
## [5,]  0.4177303  0.3174583      0.7916396     0.2600168        0.8702534
## [6,] -1.3036692 -1.3203358     -1.1919212     0.9230398        0.9350728
##      Indice_Sustentabilidade Custo_Producao_R..ha Preco_Venda_R..Ton
## [1,]               0.3953375            0.2626500          0.9277997
## [2,]               1.5858791            1.9310566         -2.1893533
## [3,]              -0.5363908           -1.0597421         -0.7115193
## [4,]              -1.5198817            1.9321120          0.2439819
## [5,]               0.6023882            1.0469358          0.1064642
## [6,]               1.2235403           -0.6547589          0.2767482
##      CH4_emissao_kg_ha N2O_emissao_kg_ha Temp_Solo_C Umidade_Solo_pct
## [1,]        0.71824654        -0.4284167  -0.2342844        1.2380356
## [2,]       -0.73046249        -0.8269439   1.0749702        1.7305313
## [3,]        0.21928500         0.6994904   1.9461473       -0.1927624
## [4,]        1.07440185         1.6318937  -0.4334106       -0.5331417
## [5,]        0.12637492        -0.2404322   1.0202105       -0.5376600
## [6,]       -0.06460692        -1.1502773  -0.9162916        1.1792975
##      Precipitacao_mm
## [1,]       0.6464328
## [2,]      -1.9707806
## [3,]      -0.7259107
## [4,]      -1.3075177
## [5,]       0.8522479
## [6,]       0.9172958
head(treino_res)
## [1] "Cupuaçu"  "Castanha" "Cupuaçu"  "Cacau"    "Castanha" "Açaí"

Obtenção dos Dados de Teste (20%)

test_var <- dados_scaled[-indice, ]
test_res <- resposta[-indice] 

Execução do KNN

  • Usaremos a função knn() do pacote ‘class’
  • train e test: Matrizes de variáveis
  • cl: Classes (rótulos) do conjunto de treino
  • k=5: Define k=5 vizinhos mais próximos.
library(class)
knn_prediction <- knn(
    train = treino_var,
    test = test_var,
    cl = treino_res,
    k = 3
)
summary(knn_prediction)
##     Açaí    Cacau Castanha  Cupuaçu 
##        5        6        2        3

3. Avaliação: Matriz de Confusão

Compara as classes preditas com as classes reais (do conjunto de teste).

confusion_matrix <- table(Classe_Real = test_res, Classe_Predita = knn_prediction)
confusion_matrix
##            Classe_Predita
## Classe_Real Açaí Cacau Castanha Cupuaçu
##    Açaí        2     3        0       1
##    Cacau       1     2        2       0
##    Castanha    2     0        0       0
##    Cupuaçu     0     1        0       2

Cálculo da Acurácia (Taxa de Acerto)

accuracy <- sum(diag(confusion_matrix)) / sum(confusion_matrix)
accuracy
## [1] 0.375