Tutorial 4 - Métodos Não Supervisionados

Neste tutorial vamos aprender dois métodos de machine learning que servem para problemas de agrupamento. Neste tipo de problemas, não temos uma variável de saída conhecida, portanto não podemos usar os métodos supervisionados já conhecidos.

K-means

Vamos aprender inicialmente o método conhecido como ‘k-means’ que basicamente agrupa as observações por uma métrica de similaridade e distância e logo cria os grupos a partir da aproximação entre elas, ou seja, aquelas observações com distância pequena entre elas farão parte do mesmo grupo.

Carregando os pacotes:

library(devtools)
#install_github("thomasp85/patchwork")
#install.packages("skimr")
#install.packages('ggforce')
#install.packages("factoextra")
#install.packages("FactoMineR")
library(tidyverse)
library(patchwork)
library(skimr)
library(ggforce)
library(factoextra)
library(FactoMineR)

theme_set(theme_minimal())
minhascores <- c("#9b5de5","#f15bb5","#fee440","#00bbf9","#00f5d4","#264653","#2A9D8F","#E9C46A","#F4A261",
                 "#E76F51")

Vamos usar o dataset ws_customers.rds

customers <- readRDS("data5/ws_customers.rds")

head(customers)
   Milk Grocery Frozen
1 11103   12469    902
2  2013    6550    909
3  1897    5234    417
4  1304    3643   3045
5  3199    6986   1455
6  4560    9965    934

Vamos plotar os dados:

p1 <- customers %>% 
  ggplot(aes(Milk, Grocery))+
  geom_point(size=2, color=minhascores[1])

p2 <- customers %>% 
  ggplot(aes(Milk, Frozen))+
  geom_point(size=2, color=minhascores[2])

p3 <- customers %>% 
  ggplot(aes(Frozen, Grocery))+
  geom_point(size=2, color=minhascores[5])


p1 + p2 + p3

Podemos ver a estrutura dos dados utilizando a skim() do pacote skimr:

skim(customers)
Data summary
Name customers
Number of rows 45
Number of columns 3
_______________________
Column type frequency:
numeric 3
________________________
Group variables None

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
Milk 0 1 4830.67 5684.39 333 1375 2335 5302 25071 ▇▁▂▁▁
Grocery 0 1 7830.00 6620.53 1330 2743 5332 10790 26839 ▇▃▂▁▁
Frozen 0 1 2869.60 3523.56 264 824 1455 3046 15601 ▇▁▁▁▁

Agora podemos começar o tratamento dos dados.

customers_scaled <- scale(customers)

Rodando o algoritmo k-means:

modelo <- kmeans(customers_scaled, centers = 3)
modelo
K-means clustering with 3 clusters of sizes 35, 5, 5

Cluster means:
        Milk    Grocery     Frozen
1 -0.4458543 -0.4268538  0.1375719
2  0.9889423  2.2234764 -0.4299061
3  2.1320377  0.7645003 -0.5330972

Clustering vector:
 [1] 3 1 1 1 1 1 1 1 2 1 1 2 3 2 1 1 3 1 1 2 1 1 3 1 1 1 3 1 1 1 1 1 1 1 1 1 1 2
[39] 1 1 1 1 1 1 1

Within cluster sum of squares by cluster:
[1] 51.585843  3.715314  5.097218
 (between_SS / total_SS =  54.2 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
[6] "betweenss"    "size"         "iter"         "ifault"      

pronto, o modelo foi construido, agora vamos incorporar uma coluna no nosso datafram customers_df com o resultado do cluster.

customers <- customers %>% 
  mutate(cluster = factor(modelo$cluster))

skim(customers)
Data summary
Name customers
Number of rows 45
Number of columns 4
_______________________
Column type frequency:
factor 1
numeric 3
________________________
Group variables None

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
cluster 0 1 FALSE 3 1: 35, 2: 5, 3: 5

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
Milk 0 1 4830.67 5684.39 333 1375 2335 5302 25071 ▇▁▂▁▁
Grocery 0 1 7830.00 6620.53 1330 2743 5332 10790 26839 ▇▃▂▁▁
Frozen 0 1 2869.60 3523.56 264 824 1455 3046 15601 ▇▁▁▁▁

Vamos refazer os gráficos, só que agora vamos colorir os pontos pelo cluster a qual pertencem.

p1 <- customers %>% 
  ggplot(aes(Milk, Grocery, color=cluster))+
  geom_point(size=2)+
  scale_color_manual(values=minhascores)+
  theme(legend.position = "none")

p2 <- customers %>% 
  ggplot(aes(Milk, Frozen, color=cluster))+
  geom_point(size=2)+
  scale_color_manual(values=minhascores)+
  theme(legend.position = "none")

p3 <- customers %>% 
  ggplot(aes(Frozen, Grocery, color=cluster))+
  geom_point(size=2)+
  scale_color_manual(values=minhascores)+
  theme(legend.position = "none")

p1+p2+p3

p1cluster <- p1 + 
  geom_mark_ellipse(aes(color=cluster))


p2cluster <- p2 + 
  geom_mark_ellipse(aes(color=cluster))

p3cluster <- p3 + 
  geom_mark_ellipse(aes(color=cluster))
  
  p1cluster+p2cluster+p3cluster

Escolhendo o número ideal de clusters

fviz_nbclust(customers, kmeans, method = "wss")

Escolhe-se o ponto onde o ‘cotovelo’ é mais visível, neste caso, 2 clusters.

modelo_final <- kmeans(customers_scaled, centers = 2)

customers <- customers %>% 
  mutate(cluster = factor(modelo_final$cluster))

Vamos refazer os gráficos mais uma vez.

p1 <- customers %>% 
  ggplot(aes(Milk, Grocery, color=cluster))+
  geom_point(size=2)+
  scale_color_manual(values=minhascores)+
  theme(legend.position = "none")

p2 <- customers %>% 
  ggplot(aes(Milk, Frozen, color=cluster))+
  geom_point(size=2)+
  scale_color_manual(values=minhascores)+
  theme(legend.position = "none")

p3 <- customers %>% 
  ggplot(aes(Frozen, Grocery, color=cluster))+
  geom_point(size=2)+
  scale_color_manual(values=minhascores)+
  theme(legend.position = "none")

p1cluster <- p1 + 
  geom_mark_ellipse(aes(color=cluster))


p2cluster <- p2 + 
  geom_mark_ellipse(aes(color=cluster))

p3cluster <- p3 + 
  geom_mark_ellipse(aes(color=cluster))
  
  p1cluster+p2cluster+p3cluster

Uma melhor forma de gráficar é utilizar a redução de dimensionalidade.

modelo_final <- eclust(customers_scaled, "kmeans", k=2)

Cluster Hierárquico

A diferença com o método anterior é que para o cluster hierárquico não é necessário pré-definir o número de clusters, pois o método agrupa as observações de forma sequencial, facilitando a identificação do número ideal de cluster.

O ideal é que os dados estejam normalizados, pelo menos as colunas numéricas, pois este método aceita também colunas (atributos) categóricos.

Vamos usar a função eclust() do pacote factoextra.

modelo2 <- eclust(customers_scaled, "hclust")
fviz_dend(modelo2)

Análise dos Componentes Principais

A Análise de Componentes Principais (PCA, do inglês “Principal Component Analysis”) é uma técnica estatística usada para reduzir a dimensionalidade de um conjunto de dados, ao mesmo tempo em que preserva a maior quantidade possível de variação presente nesses dados. A PCA consegue isso transformando o conjunto original de variáveis em um novo conjunto de variáveis ortogonais (ou seja, não correlacionadas) chamadas de componentes principais. Esses componentes são ordenados de tal forma que o primeiro componente captura a maior parte da variação nos dados, o segundo componente captura a maior parte da variação restante, e assim por diante.

customers <- readRDS("data5/ws_customers.rds")

modelo_pca <- PCA(customers, graph = FALSE)

Agora podemos aplicar vários tipos de visualizações do pacote factoExtra.

fviz_screeplot(modelo_pca, ncp=10)

fviz_screeplot(modelo_pca, ncp=10,
               barfill = minhascores[4],
               barcolor = minhascores[4])

fviz_pca_var(modelo_pca)

fviz_pca_var(modelo_pca,
             col.var="contrib")+
  scale_color_gradient2(low=minhascores[1],
                        mid=minhascores[2],
                        high=minhascores[3],
                        midpoint = 34)

customers <- customers %>% 
  mutate(cluster=factor(modelo2$cluster))

fviz_pca_ind(modelo_pca, 
             label="none",
             habillage = customers$cluster,
             addEllipses = TRUE)+
  scale_fill_manual(values = minhascores)+
  scale_color_manual(values=minhascores)

fviz_pca_biplot(modelo_pca,
  label="var",
             habillage = customers$cluster,
             addEllipses = TRUE)+
  scale_fill_manual(values = minhascores)+
  scale_color_manual(values=minhascores)