Artigo escrito com a colaboração de Luis Henrique Velasquez.

De forma bem simples, o Machine Learning se baseia na construção e no uso de algoritmos que “aprendem” a partir dos dados.

Os problemas de Machine Learning são divididos em três subáreas principais: classificação, regressão e clustering. Já falamos aqui no blog sobre a Classificação e no artigo de hoje vamos continuar explicando Regressão e Clustering.

Machine Learning é um assunto vasto e que se aproxima muito da estatística já que os modelos dependem muito das técnicas estatísticas bem desenvolvidas.

Regressão

A Regressão é um dos métodos de previsão mais utilizados no meio estatístico. Tem como principal objetivo verificar como certas variáveis de interesse influenciam uma variável resposta Y e criar um modelo matemático capaz de predizer valores de Y com base em novos valores de variáveis preditoras X.

Regressão Linear Simples

O modelo de regressão simples pode ser escrito da seguinte forma:

yi = β0 + β1xi + εi

Sendo que os erros são identicamente distribuídos, seguindo uma distribuição Normal com média 0 e variância σ². (εi ~ N(0,σ²)).

O foco desse seminário não será entrar em muitos detalhes acerca da teoria estatística por trás da regressão, mas sim mostrar pontos uteis para um melhor uso no R.

Os principais métodos utilizados para avaliar o desempenho dos modelos de regressão são:

  • RMSE: ou Raiz do Erro Quadrático Médio, é comumente usada para expressar a acurácia dos resultados numéricos do modelo. Como já explicado na seção das medidas de desempenho, quando maior seu valor, pior o desempenho do modelo.
  • : expressa a porcentagem de variância explicada pelas variáveis independentes apresentadas no modelo. Quando maior, melhor o desempenho dele. Porém, é importante verificar a significância e a quantidade dessas variáveis antes de verificar o R² do modelo, dado que um aumento do número de variáveis acaba por acarretar um aumento dessa medida.

O código abaixo utiliza o banco de dados “kang.nose” para construirmos uma regressão linear simples, criando um modelo que prevê a largura do nariz de cangurus com base em seu comprimento. Realizaram-se predições do modelo através da função predict() e cálculos para as medidas de desempenho RMSE e .

kang.nose %>% summary()
   nose_width     nose_length   
 Min.   :189,0   Min.   :493,0  
 1st Qu.:220,0   1st Qu.:616,0  
 Median :237,0   Median :677,0  
 Mean   :244,2   Mean   :687,4  
 3rd Qu.:272,0   3rd Qu.:755,0  
 Max.   :308,0   Max.   :864,0  
### Aplicando um regressão linear simples - Witdh explicando por Length
mod.nose <- lm(nose_width ~ nose_length, data= kang.nose)
mod.nose %>% summary()

Call:
lm(formula = nose_width ~ nose_length, data = kang.nose)

Residuals:
    Min      1Q  Median      3Q     Max 
-29,656  -7,479   2,132   8,229  27,344 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  46,4508    16,2998    2,85  0,00669 ** 
nose_length   0,2876     0,0235   12,24 1,34e-15 ***
---
Signif. codes:  0 '***' 0,001 '**' 0,01 '*' 0,05 '.' 0,1 ' ' 1

Residual standard error: 14,44 on 43 degrees of freedom
Multiple R-squared:  0,7769,    Adjusted R-squared:  0,7717 
F-statistic: 149,7 on 1 and 43 DF,  p-value: 1,342e-15
mod.nose$coefficients # retorna os coeficientes
(Intercept) nose_length 
 46,4508136   0,2876124 
new_length <- data.frame(nose_length = c(500, 600, 700)) # Novos dados
predict(mod.nose, new_length, interval = "confidence") # Previsão com base nos novos + IC 95%
       fit      lwr      upr
1 190,2570 180,3698 200,1442
2 219,0182 213,0172 225,0193
3 247,7795 243,3970 252,1619
RMSE <- function(error) { sqrt(mean(error^2)) } # Função criada para o cálculo do RMSE
RMSE(mod.nose$residuals) # RMSE
[1] 14,11701
summary(mod.nose)$r.squared # R2
[1] 0,7768914

Regressão Linear Multivariada

regressão linear multivariada é semelhante à simples, porém com mais de uma variável preditora. Para esse tipo de regressão, no lugar do R² utiliza-se o R² ajustado, já que ele consegue penalizar o acréscimo de variáveis ao modelo, fazendo com que não seja diretamente inflacionada nesse contexto.

No código abaixo, trabalharemos com o banco “shop.data”, que apresenta as vendas de uma loja com base em diversas características dos seus clientes. Assim como foi realizado com o caso da regressão linear simples, realizaremos previsões, calcularemos medidas de desempenho (como o R² ajustado) e verificaremos as suposições dos erros do modelo de regressão multivariada.

shop.data %>% summary()
     sales           sq_ft            inv             ads       
 Min.   :  0,5   Min.   :0,500   Min.   :102,0   Min.   : 2,50  
 1st Qu.: 98,5   1st Qu.:1,400   1st Qu.:204,0   1st Qu.: 4,80  
 Median :341,0   Median :3,500   Median :382,0   Median : 8,10  
 Mean   :286,6   Mean   :3,326   Mean   :387,5   Mean   : 8,10  
 3rd Qu.:450,5   3rd Qu.:4,750   3rd Qu.:551,0   3rd Qu.:10,95  
 Max.   :570,0   Max.   :8,600   Max.   :788,0   Max.   :17,40  
   size_dist           comp       
 Min.   : 1,600   Min.   : 0,000  
 1st Qu.: 4,500   1st Qu.: 4,000  
 Median :11,300   Median : 8,000  
 Mean   : 9,693   Mean   : 7,741  
 3rd Qu.:14,050   3rd Qu.:12,000  
 Max.   :16,300   Max.   :15,000  
### Aplicando uma regressão linear multivariada - Sales como variável resposta
mod.shop <- lm(sales ~ . , data = shop.data) # "~." mostra que usaremos todas as demais variáveis 
mod.shop %>% summary()

Call:
lm(formula = sales ~ ., data = shop.data)

Residuals:
    Min      1Q  Median      3Q     Max 
-26,338  -9,699  -4,496   4,040  41,139 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -18,85941   30,15023  -0,626 0,538372    
sq_ft        16,20157    3,54444   4,571 0,000166 ***
inv           0,17464    0,05761   3,032 0,006347 ** 
ads          11,52627    2,53210   4,552 0,000174 ***
size_dist    13,58031    1,77046   7,671 1,61e-07 ***
comp         -5,31097    1,70543  -3,114 0,005249 ** 
---
Signif. codes:  0 '***' 0,001 '**' 0,01 '*' 0,05 '.' 0,1 ' ' 1

Residual standard error: 17,65 on 21 degrees of freedom
Multiple R-squared:  0,9932,    Adjusted R-squared:  0,9916 
F-statistic: 611,6 on 5 and 21 DF,  p-value: < 2,2e-16
mod.shop$coefficients # retorna os coeficientes
(Intercept)       sq_ft         inv         ads   size_dist        comp 
-18,8594073  16,2015726   0,1746352  11,5262679  13,5803127  -5,3109718 
summary(mod.nose)$r.squared # R2 (aumenta com o acréscimo de variáveis)
[1] 0,7768914
summary(mod.nose)$adj.r.squared # R2 Ajustado
[1] 0,7717028
RMSE(mod.shop$residuals) # RMSE
[1] 15,56517
#### Verificando suposições dos resíduos

# Residuos independentemente distribuídos em torno de 0
plot(mod.shop$fitted.values, mod.shop$residuals) 
abline(h=0, col="red", lty= 3) 
scatterplot da regressão linear multivariada
# Normalidade dos resíduos
if(!require(car)){ install.packages("car"); require(car) }
qqPlot(mod.shop$residuals)
scatterplot da regressão linear multivariada
Uma visão geral sobre machine learning –
[1]  6 17
mod.shop$residuals %>% shapiro.test() # Rejeita a hipóte nula de normalidade

    Shapiro-Wilk normality test

data:  .
W = 0,91859, p-value = 0,03651

K-Nearest Neighbors (KNN)

É importante observar que, assim como no método de Classificação, é possível utilizar o k-Nearest Neighbors (KNN) como uma forma de regressão não-paramétrica.

No código abaixo, usaremos um training e um test set já construídos para o banco de dados “world”, apresentando o cgdp (similar ao PIB) de diversos países e a sua porcentagem de população urbana. Utilizaremos a função knn.reg() (pacote “FNN”) para fazer previsões de “cgdp” (variável resposta) no test set após seu treinamento no training set. Utilizaram-se 20% do total de observações alocadas no training set para a definição do número k de vizinhos.

# Separando os preditores e a variável resposta dos sets
world.test.x <- world.test[,-1] %>% as.data.frame()
world.train.x <- world.train[,-1] %>% as.data.frame()

world.train.y <- world.train[,1] %>% as.data.frame()
world.test.y <- world.test[,1] %>% as.data.frame()

# KNN = knn("Training set","test set", "classificação real do training", "K vizinhos consiederados")
if(!require(FNN)){ install.packages("FNN"); require(FNN) }
knn.world = FNN::knn.reg(train = world.train.x, test = world.test.x, y = world.train.y, k = 28) # k=20% total obs training
knn.world
Prediction:
 [1]  2510,690  2966,211  3153,116  4604,018  6490,574  2510,690  6490,574
 [8] 18704,486  2553,522 32266,901 23111,132  3753,158  6532,045 16700,703
[15] 26601,322 32266,901 29289,700 16277,721 28704,561 28704,561 11953,832
[22] 24495,555  6490,574  2553,522 32266,901 18704,486 28704,561 29005,821
[29] 32266,901 32266,901 17764,754  5941,413  3047,800  3120,619 26673,573
[36] 24495,555 32266,901 32266,901 15285,950  3135,717  3038,616 23083,414
[43] 12493,242 11982,323 28704,561  5813,593 28704,561 28617,902  6939,055
[50]  7045,579 32266,901  5961,592  4123,500 12260,437 18704,486 32266,901
[57]  2975,100 32266,901  2915,870  2553,522  2868,928

Clustering

Clustering é uma subárea do Machine Learning de aprendizado não-supervisionado, visto que suas técnicas não necessitam de rótulos de classes (como no caso da classificação e regressão) para realizar suas previsões. Um Cluster é um objeto que contém diversas observações que são semelhantes entre si dentro desse cluster específico e diferentes de outras observações que foram alocadas em outros clusters. Dessa forma, o Clustering nada mais é que agrupar os dados em clusters baseado em suas características/variáveis. Como já comentado anteriormente, não existe propriamente uma clusterização certa ou errada dos dados, sendo que o tipo de clusterização utilizada resulta em diferentes tipos de clusters, e a escolha dessas técnicas devem ser previamente analisadas pelo pesquisador.

O objetivo do uso do Clustering é uma melhor visualização dos seus dados, estudando padrões de comportamento e detectando outliers. Para realizarmos o Clustering, usamos medidas de similaridade dos dados (como a distância Euclidiana para os dados numéricos ou variáveis dummys para variáveis categóricas) e técnicas como k-means e Clustering Hierárquico, que serão explicadas mais a frente.

Para que seja possível alcançar o melhor desempenho no processo de clusterização, necessitamos que os clusters apresentem a maior similaridade possível entre si em seu interior e que apresentem a maior diferença possível entre si ao serem comparados uns com os outros. Essa similaridade e dissimilaridade podem ser medidas a partir da “soma de quadrados dentro do Cluster” (WSS) e pela “soma de quadrados entre os clusters” (BSS), que medem a compacidade e a separação dos clusters, respectivamente. Suas fórmulas são apresentadas na imagem abaixo:

cálculo do WSS e do BSS

K-means

A técnica K-means tem como objetivo separar os dados em k clusters diferentes, com base em k-centroides. Seu algoritmo funciona da seguinte forma:

1. Gera-se aleatoriamente k-centroides.
2. Atribuí-se os dados aos centroides mais próximos, criando-se clusters.
3. Move-se os centroides para a localização média de cada um dos k clusters criados no passo 2, colocando-os no centro real desses clusters criados.
4. Repetem-se os passos 2 e 3 n vezes (a escolha do usuário) ou até que não se ocorra mais mudanças significativas nas posições dos k centroides.

melhor escolha do “k” (número de clusters) é baseado na escolha que apresente a minimização do WSS. Porém, quanto maior o k, menor tende a ser o WSS. Para resolver esse problema, escolhemos o k quando a sua diminuição começa a ser muito pequena mesmo com o aumento no número de clusters. O critério usualmente utilizado para essa diminuição é escolher K quando a razão entre o WSS e o TSS (que consiste na soma do WSS com o BSS) for menor que 0,2. O Scree Plot apresenta o gráfico dessa razão em relação a k, e a principal forma gráfica de selecionar-se o k ideal: o k ideal será quando se forma o “cotovelo” da curva apresentada, pois é o momento em que a razão começa a decrescer de forma mais suave.

A imagem abaixo mostra um exemplo desse gráfico: a partir do ponto k = 3, existe uma diminuição bem menos expressiva da razão WSS/TSS, sendo assim a melhor escolha para o número de clusters nesse caso.

gráfico da razão WSS/TSS

O código abaixo utiliza o banco de dados seeds, porém sem sua classificação anteriormente apresentada, e utiliza a função kmeans() (pacote “stats”) para construirmos 3 clusters diferentes. É importante salientar que, quando não indicado na função, o R seleciona aleatoriamente o centroide dos dados, o que pode alterar o cálculo dos clusters. Além disso, construiremos um algoritmo para a construção de um Scree Plot.

# Semente aleatória
set.seed(100)

# K-means construido para 3 clusters, repetindo 20 vezes (nstart), com centroide aleatoriamente selecionado ("centers" não definido)
seeds_km <- kmeans(seeds,3,nstart=20)
seeds_km
K-means clustering with 3 clusters of sizes 72, 77, 61

Cluster means:
      area perimeter compactness   length    width asymmetry groove_length
1 14,64847  14,46042   0,8791667 5,563778 3,277903  2,613892      5,192319
2 11,96442  13,27481   0,8522000 5,229286 2,872922  4,759740      5,088519
3 18,72180  16,29738   0,8850869 6,208934 3,722672  3,603590      6,066098

Clustering vector:
  [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1
 [38] 3 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 1 1 1 1 1 2 3 3 3 3
 [75] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 3 3 3 3 3 3 3 3 3 3
[112] 3 3 3 3 3 3 3 3 3 3 3 1 3 1 3 3 3 3 3 3 3 1 1 1 1 3 1 1 1 2 2 2 2 2 2 2 2
[149] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2
[186] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2

Within cluster sum of squares by cluster:
[1] 218,6106 195,7453 184,1086
 (between_SS / total_SS =  78,1 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
[6] "betweenss"    "size"         "iter"         "ifault"      
seeds_km$betweenss # BSS
[1] 2137,896
seeds_km$tot.withinss # WSS
[1] 598,4645
# Comparando a clusterização realizada com a classificação real das sementes
table(seeds_km$cluster,seeds_type$seeds_type)
   
     1  2  3
  1 60 10  2
  2  9  0 68
  3  1 60  0
# Plotando o comprimento das sementes em função da sua largura e colorindo de acordo com os clusters criados
plot(seeds$width,seeds$length,col=seeds_km$cluster)
scatterplot do comprimento das sementes
# Criando o Scree Plot para as sementes
Razão.seed <- rep(0,7) # Número total de clusters a serem testados no Scree Plot

for (k in 1:7) {
  seeds_km <- kmeans(seeds,nstart=20,k) # Aplicando K-means
  Razão.seed[k] <- seeds_km$tot.withinss/seeds_km$totss # Salvando a Razão WSS/TSS para cada k utilizado
}

plot(Razão.seed,type="b",xlab="k", main="Scree Plot para o banco Seeds") # K = 3 ou 4
abline(h=0.2, col="red", lty= 3)
scree plot para o banco seeds

Uma alternativa para se medir o desempenho da clusterização similar ao uso do BSS e WSS é o Dunn Index: essa estatística apresenta a razão entre a distância mínima entre os clusters e o diâmetro máximo dos clusters. Assim, um valor alto do Dunn Index mostra que os clusters em questão estão bem separados entre si e bem compactos. Porém, essa estatística tem um custo computacional alto (quando maior o número de clusters, maior o custo) e deve ser utilizada no pior caso.

O código abaixo utiliza o banco de dados run_record, apresentando o recorde de diversos tipos de maratonas. Usaremos a função dunn() (pacote “clValid”) para o cálculo do Dunn Index e a função scale() para o escalonamento das variáveis (iremos padronizar os dados, pois a escala entre os recordes se diferenciava substancialmente).

summary(run_record) # as escalas dos records se diferenciam  muito!
      Country       X100m           X200m           X400m           X800m      
 Argentina: 1   Min.   : 9,78   Min.   :19,32   Min.   :43,18   Min.   :101,4  
 Australia: 1   1st Qu.:10,10   1st Qu.:20,17   1st Qu.:44,91   1st Qu.:103,8  
 Austria  : 1   Median :10,20   Median :20,43   Median :45,58   Median :105,6  
 Belgium  : 1   Mean   :10,22   Mean   :20,54   Mean   :45,83   Mean   :106,1  
 Bermuda  : 1   3rd Qu.:10,32   3rd Qu.:20,84   3rd Qu.:46,32   3rd Qu.:108,0  
 Brazil   : 1   Max.   :10,97   Max.   :22,46   Max.   :51,40   Max.   :116,4  
 (Other)  :48                                                                  
     X1500m          X5000m          X10000m        marathon    
 Min.   :206,4   Min.   : 759,6   Min.   :1588   Min.   : 7473  
 1st Qu.:213,0   1st Qu.: 788,9   1st Qu.:1653   1st Qu.: 7701  
 Median :216,6   Median : 805,2   Median :1675   Median : 7819  
 Mean   :219,2   Mean   : 817,1   Mean   :1712   Mean   : 8009  
 3rd Qu.:224,2   3rd Qu.: 834,5   3rd Qu.:1739   3rd Qu.: 8050  
 Max.   :254,4   Max.   :1002,0   Max.   :2123   Max.   :10276  
                                                                
# Semente aleatoria
set.seed(16)

# K-means para valores numéricos do run_record: 5 clusters, repetir 20 vezes
run_km <- kmeans(run_record[,2:9],nstart=20,5)

# Calculando o Dunn's index
if(!require(clValid)){ install.packages("clValid"); require(clValid) }
dunn_km <- dunn(clusters=run_km$cluster,Data=run_record[,2:9])
dunn_km
[1] 0,05651773
# Escalonizando os dados
run_record_sc <- as.data.frame(scale(run_record[2:9]))

# K-means: Run record escolonado
run_km_sc <- kmeans(run_record_sc,nstart = 20,5)

# Comparando os clusters do run record escalonado e não-escalonado
table(run_km$cluster,run_km_sc$cluster)
   
     1  2  3  4  5
  1  7  0  0  1 10
  2  1  0  0 13 10
  3  0  0  6  0  0
  4  0  2  0  0  0
  5  2  0  2  0  0
# Calculando o Dunn index para o run record escalonizado
dunn_km_sc<-dunn(cluster=run_km_sc$cluster,Data=run_record_sc)
dunn_km_sc # O dunn escalonado é bem superior ao não escalonado
[1] 0,1453556

Clustering Hierárquico

Além da técnica do K-means, outra técnica importante no Clustering é o Clustering Hierárquico. Diferentemente da técnica K-means, o Clustering Hierárquico apresenta a ordem de junção dos objetos de cada cluster, assim como quais clusters se fundiram para a formação de um novo cluster, seguindo um comportamento hierárquico dos clusters. A hierarquia de formação dos clusters dependerá dos tipos de distâncias utilizadas para medir a similaridade entre os objetos. É importante observar que essa técnica consiste na formação de cluster através de passos, e cada cluster é formado separadamente seguindo-se uma hierarquia.

O algoritmo utilizado no Clustering Hierárquico funciona da seguinte forma:

  • Antes de tudo, calcula-se a distância entre os objetos/observações.
    1. Coloca-se cada objeto em seu próprio cluster.
    2. Mescla-se o par de objetos mais próximos entre si. Demais objetos continuarão iguais.
    3. Recalcula-se a distância entre o novo cluster formado e os demais objetos restantes.
    4. Repetem-se os passos 2 e 3 até um critério de parada (geralmente, até a formação de um único cluster final).

Existem três métodos utilizados para determinar a ligação entre os objetos e formação dos clusters, sendo que cada um deles afeta diretamente na formação dos clusters:

  1. Simple-Linkage: a distância entre dois clusters é definida como a distância mínima encontrada entre os objetos de um dos clusters para os demais objetos do outro cluster.
  2. Complete-Linkage: a distância entre dois clusters é definida como a distância máxima encontrada entre os objetos de um dos clusters para os demais objetos do outro cluster.
  3. Average-Linkage: a distância entre dois clusters é definida como a distância média encontrada entre os objetos dos dois clusters.

Após a escolha do método de linkagem, construímos um gráfico chamado Dendrograma. Esse gráfico consegue nos mostrar a ordem das mesclas entre os objetos (barras horizontais), assim como a distância entre os clusters antes deles serem mesclados (altura do dendrograma). Pode-se “cortar” o dendrograma de acordo com o número de clusters desejado pelo pesquisador. A imagem abaixo nos dá a ideia de como esse gráfico é apresentado:

exemplo de dendograma de clustering hierárquico

O código abaixo apresente a aplicação da técnica de Clustering Hierárquico no banco de dados “seeds”, que apresenta diversas características de 3 tipos de sementes, assim como sua classificação. Iremos utilizar esse banco de dados retirando a coluna referente a espécie das sementes para realizarmos previsões para suas classificações e depois as compararemos com suas classificações originais. Utilizaremos a função hclust() (pacote “stats”) para realizar o clustering hierárquico e a função cutree() (pacote “dendextend”) para o corte do dendrograma no número de clusters desejado (k = 3, referente ao número de espécies originalmente classificadas).

summary(seeds) # Analisando o banco de dados - verificando as escalas das variaveis
      area         perimeter      compactness         length     
 Min.   :10,59   Min.   :12,41   Min.   :0,8081   Min.   :4,899  
 1st Qu.:12,27   1st Qu.:13,45   1st Qu.:0,8569   1st Qu.:5,262  
 Median :14,36   Median :14,32   Median :0,8734   Median :5,524  
 Mean   :14,85   Mean   :14,56   Mean   :0,8710   Mean   :5,629  
 3rd Qu.:17,30   3rd Qu.:15,71   3rd Qu.:0,8878   3rd Qu.:5,980  
 Max.   :21,18   Max.   :17,25   Max.   :0,9183   Max.   :6,675  
     width         asymmetry        groove_length  
 Min.   :2,630   Min.   :0,000077   Min.   :4,519  
 1st Qu.:2,944   1st Qu.:2,561500   1st Qu.:5,045  
 Median :3,237   Median :3,599000   Median :5,223  
 Mean   :3,259   Mean   :3,688187   Mean   :5,408  
 3rd Qu.:3,562   3rd Qu.:4,768750   3rd Qu.:5,877  
 Max.   :4,033   Max.   :8,456000   Max.   :6,550  
#### Como as variáveis estavam em escalas diferentes, escalonamos ela a partir da normalização
seeds_sc <- seeds %>% scale %>% as.data.frame() 
summary(seeds_sc) # Todas escolonadas com média 0 e dp 1
      area           perimeter        compactness          length       
 Min.   :-1,4632   Min.   :-1,6458   Min.   :-2,6619   Min.   :-1,6466  
 1st Qu.:-0,8858   1st Qu.:-0,8494   1st Qu.:-0,5967   1st Qu.:-0,8267  
 Median :-0,1693   Median :-0,1832   Median : 0,1037   Median :-0,2371  
 Mean   : 0,0000   Mean   : 0,0000   Mean   : 0,0000   Mean   : 0,0000  
 3rd Qu.: 0,8446   3rd Qu.: 0,8850   3rd Qu.: 0,7100   3rd Qu.: 0,7927  
 Max.   : 2,1763   Max.   : 2,0603   Max.   : 2,0018   Max.   : 2,3619  
     width           asymmetry        groove_length    
 Min.   :-1,6642   Min.   :-2,41116   Min.   :-1,8090  
 1st Qu.:-0,8329   1st Qu.:-0,73659   1st Qu.:-0,7387  
 Median :-0,0572   Median :-0,05831   Median :-0,3766  
 Mean   : 0,0000   Mean   : 0,00000   Mean   : 0,0000  
 3rd Qu.: 0,8026   3rd Qu.: 0,70644   3rd Qu.: 0,9541  
 Max.   : 2,0502   Max.   : 3,11704   Max.   : 2,3234  
### Calculando a distância entre os objetos (distância Euclidiana)
dist_mat <- dist(seeds_sc, method = 'euclidean')

#### Criando o dendrograma e testando cada um dos três métodos de ligação
if(!require(stats)){ install.packages("stats"); require(stats) }

hclust_single <- hclust(dist_mat, method = 'single')  # Usa a Distancia mínima entre objetos
plot(hclust_single)
dendograma de clustering
hclust_complete <- hclust(dist_mat, method = 'complete')  # Usa a Distancia máxima entre objetos
plot(hclust_complete)
dendograma de clustering
hclust_avg <- hclust(dist_mat, method = 'average') # Usa a Distancia média entre objetos
plot(hclust_avg)
dendograma de clustering
### Dado que ja sabemos que os dados originais continham 3 tipos de sementes, vamos cortar o gráfico com k=3
if(!require(dendextend)){ install.packages("dendextend"); require(dendextend) }

cut_avg <- cutree(hclust_avg, k = 3) # Cortando o dendrograma que utilizou o médio "average"

### Colorindo os três clusters formados no dendograma via método "average"
avg_col_dend <- hclust_avg %>% as.dendrogram() %>%  color_branches(h = 3) # Função que colore os clusters
plot(avg_col_dend)
dendograma de clustering
### Comparando com os clusters com seus rotulos originais
seeds_sc <- seeds_sc %>% mutate(cluster = cut_avg)
conf.seeds <- table(seeds_sc$cluster,seeds_type$seeds_type) # Cluster originais nas colunas
conf.seeds
   
     1  2  3
  1 52  2  8
  2 10 68  0
  3  8  0 62
accuracy <- function(x){sum(diag(x)/(sum(rowSums(x)))) * 100} # Função para calcular a acurácia da previsão
accuracy(conf.seeds) # 86,67 % de acurácia 
[1] 86,66667
0 respostas

Deixe uma resposta

Quer participar dessa discussão?
Sinta-se livre para contribuir!

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *