Avaliação 04
Packages
source("~/Python Scripts/AV4/src/features.R", encoding = 'UTF-8')library(fossil)
library(meanShiftR)
library(tidyverse) # Gráficos, manipulação e transformação dos dados
library(cluster) # Avaliação dos grupos
library(clValid) # Avaliação dos grupos
library(e1071) # Fuzzy K-médias
library(factoextra) # Vizualização de grupos
library(skimr) # Análise exploratória de dados
library(gridExtra) # Ferramentas gráficas
library(ggforce) # Ferramentas gráficasCarregando os dados
DIR = 'data'; FILE = 'data.csv'
URL = file.path(DIR, FILE)
data = read.csv(URL, sep = ';')Separando banco de variáveis continuas
continuos = c("Previous.qualification..grade.","Admission.grade",names(data)[22:33],
"Unemployment.rate", "Inflation.rate", "GDP")
data_c = data[continuos]
data = data[,!(colnames(data) %in% continuos)]
dim(data_c)## [1] 4424 17
colnames(data)## [1] "ï..Marital.status" "Application.mode"
## [3] "Application.order" "Course"
## [5] "Daytime.evening.attendance." "Previous.qualification"
## [7] "Nacionality" "Mother.s.qualification"
## [9] "Father.s.qualification" "Mother.s.occupation"
## [11] "Father.s.occupation" "Displaced"
## [13] "Educational.special.needs" "Debtor"
## [15] "Tuition.fees.up.to.date" "Gender"
## [17] "Scholarship.holder" "Age.at.enrollment"
## [19] "International" "Target"
colnames(data_c) = c('PrevQualifiGrade', "AdmissionGrade","1stCredited",
"1stEnrolled","1stEvaluations",
"1stApproved","1stGrade","1stWithoutEva",
"2ndCredited",
"2ndEnrolled","2ndEvaluations",
"2ndApproved","2ndGrade","2ndWithoutEva",
colnames(data_c)[15:17])attach(data)
attach(data_c)Pre-Processing
Verificando existência de NaN’s
sum(is.na(data)) ## [1] 0
sum(is.na(data_c)) ## [1] 0
knitr::kable(summary(data))| ï..Marital.status | Application.mode | Application.order | Course | Daytime.evening.attendance. | Previous.qualification | Nacionality | Mother.s.qualification | Father.s.qualification | Mother.s.occupation | Father.s.occupation | Displaced | Educational.special.needs | Debtor | Tuition.fees.up.to.date | Gender | Scholarship.holder | Age.at.enrollment | International | Target | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Min. :1.000 | Min. : 1.00 | Min. :0.000 | Min. : 33 | Min. :0.0000 | Min. : 1.000 | Min. : 1.000 | Min. : 1.00 | Min. : 1.00 | Min. : 0.00 | Min. : 0.00 | Min. :0.0000 | Min. :0.00000 | Min. :0.0000 | Min. :0.0000 | Min. :0.0000 | Min. :0.0000 | Min. :17.00 | Min. :0.00000 | Length:4424 | |
| 1st Qu.:1.000 | 1st Qu.: 1.00 | 1st Qu.:1.000 | 1st Qu.:9085 | 1st Qu.:1.0000 | 1st Qu.: 1.000 | 1st Qu.: 1.000 | 1st Qu.: 2.00 | 1st Qu.: 3.00 | 1st Qu.: 4.00 | 1st Qu.: 4.00 | 1st Qu.:0.0000 | 1st Qu.:0.00000 | 1st Qu.:0.0000 | 1st Qu.:1.0000 | 1st Qu.:0.0000 | 1st Qu.:0.0000 | 1st Qu.:19.00 | 1st Qu.:0.00000 | Class :character | |
| Median :1.000 | Median :17.00 | Median :1.000 | Median :9238 | Median :1.0000 | Median : 1.000 | Median : 1.000 | Median :19.00 | Median :19.00 | Median : 5.00 | Median : 7.00 | Median :1.0000 | Median :0.00000 | Median :0.0000 | Median :1.0000 | Median :0.0000 | Median :0.0000 | Median :20.00 | Median :0.00000 | Mode :character | |
| Mean :1.179 | Mean :18.67 | Mean :1.728 | Mean :8857 | Mean :0.8908 | Mean : 4.578 | Mean : 1.873 | Mean :19.56 | Mean :22.28 | Mean : 10.96 | Mean : 11.03 | Mean :0.5484 | Mean :0.01153 | Mean :0.1137 | Mean :0.8807 | Mean :0.3517 | Mean :0.2484 | Mean :23.27 | Mean :0.02486 | NA | |
| 3rd Qu.:1.000 | 3rd Qu.:39.00 | 3rd Qu.:2.000 | 3rd Qu.:9556 | 3rd Qu.:1.0000 | 3rd Qu.: 1.000 | 3rd Qu.: 1.000 | 3rd Qu.:37.00 | 3rd Qu.:37.00 | 3rd Qu.: 9.00 | 3rd Qu.: 9.00 | 3rd Qu.:1.0000 | 3rd Qu.:0.00000 | 3rd Qu.:0.0000 | 3rd Qu.:1.0000 | 3rd Qu.:1.0000 | 3rd Qu.:0.0000 | 3rd Qu.:25.00 | 3rd Qu.:0.00000 | NA | |
| Max. :6.000 | Max. :57.00 | Max. :9.000 | Max. :9991 | Max. :1.0000 | Max. :43.000 | Max. :109.000 | Max. :44.00 | Max. :44.00 | Max. :194.00 | Max. :195.00 | Max. :1.0000 | Max. :1.00000 | Max. :1.0000 | Max. :1.0000 | Max. :1.0000 | Max. :1.0000 | Max. :70.00 | Max. :1.00000 | NA |
knitr::kable(summary(data_c))| PrevQualifiGrade | AdmissionGrade | 1stCredited | 1stEnrolled | 1stEvaluations | 1stApproved | 1stGrade | 1stWithoutEva | 2ndCredited | 2ndEnrolled | 2ndEvaluations | 2ndApproved | 2ndGrade | 2ndWithoutEva | Unemployment.rate | Inflation.rate | GDP | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Min. : 95.0 | Min. : 95.0 | Min. : 0.00 | Min. : 0.000 | Min. : 0.000 | Min. : 0.000 | Min. : 0.00 | Min. : 0.0000 | Min. : 0.0000 | Min. : 0.000 | Min. : 0.000 | Min. : 0.000 | Min. : 0.00 | Min. : 0.0000 | Min. : 7.60 | Min. :-0.800 | Min. :-4.060000 | |
| 1st Qu.:125.0 | 1st Qu.:117.9 | 1st Qu.: 0.00 | 1st Qu.: 5.000 | 1st Qu.: 6.000 | 1st Qu.: 3.000 | 1st Qu.:11.00 | 1st Qu.: 0.0000 | 1st Qu.: 0.0000 | 1st Qu.: 5.000 | 1st Qu.: 6.000 | 1st Qu.: 2.000 | 1st Qu.:10.75 | 1st Qu.: 0.0000 | 1st Qu.: 9.40 | 1st Qu.: 0.300 | 1st Qu.:-1.700000 | |
| Median :133.1 | Median :126.1 | Median : 0.00 | Median : 6.000 | Median : 8.000 | Median : 5.000 | Median :12.29 | Median : 0.0000 | Median : 0.0000 | Median : 6.000 | Median : 8.000 | Median : 5.000 | Median :12.20 | Median : 0.0000 | Median :11.10 | Median : 1.400 | Median : 0.320000 | |
| Mean :132.6 | Mean :127.0 | Mean : 0.71 | Mean : 6.271 | Mean : 8.299 | Mean : 4.707 | Mean :10.64 | Mean : 0.1377 | Mean : 0.5418 | Mean : 6.232 | Mean : 8.063 | Mean : 4.436 | Mean :10.23 | Mean : 0.1503 | Mean :11.57 | Mean : 1.228 | Mean : 0.001969 | |
| 3rd Qu.:140.0 | 3rd Qu.:134.8 | 3rd Qu.: 0.00 | 3rd Qu.: 7.000 | 3rd Qu.:10.000 | 3rd Qu.: 6.000 | 3rd Qu.:13.40 | 3rd Qu.: 0.0000 | 3rd Qu.: 0.0000 | 3rd Qu.: 7.000 | 3rd Qu.:10.000 | 3rd Qu.: 6.000 | 3rd Qu.:13.33 | 3rd Qu.: 0.0000 | 3rd Qu.:13.90 | 3rd Qu.: 2.600 | 3rd Qu.: 1.790000 | |
| Max. :190.0 | Max. :190.0 | Max. :20.00 | Max. :26.000 | Max. :45.000 | Max. :26.000 | Max. :18.88 | Max. :12.0000 | Max. :19.0000 | Max. :23.000 | Max. :33.000 | Max. :20.000 | Max. :18.57 | Max. :12.0000 | Max. :16.20 | Max. : 3.700 | Max. : 3.510000 |
Podemos notar que a base não possui NaN’s. Além disso, apartir da ultima tabela gerada acima, podemos notar que não existe nenhum valor, em sua respectiva variavel, que aparenta estar fora do seu range de valores. Esse ultimo ponto de verificar se existe alguma variavel fora do range da sua natureza, foi utilizado com o intuito para verificar se existiam NaN’s tratados como 999 ou -1 por exemplo, como sabemos que muitas situações é comum tratarem observações com numeros bem discripantes da natureza da sua variavel para representar dados faltantes.
Definindo variável target
Vamos definir a nossa variável target para o nosso problema de classificação
target <- as.factor(data$Target)
levels(target)## [1] "Dropout" "Enrolled" "Graduate"
Vamos analisar a distribuição pelas classes da variável target, versus a variavel Unemployment.rate, Inflation.rate e Age.at.enrollment:
- Unemployment.rate:
boxplot(Unemployment.rate ~ target)Acima podemos notar os grupos Dropout e Graduate aparentam ter comportamento semelhante com respetio a variável Unemployment.rate, porém ambos tem comportamento distinto da classe Enrolled, sendo esta ultima apresentando um menor intervalo interquartilico, aparentando ter uma variação menor dentre os membros da sua classe, com respeito a taxa de desemprego. Vale ressaltar também que a mediana manteve-se igual para os 3 grupos.
boxplot(Inflation.rate ~ target)Podemos notar que para o cenário acima, agora a classe Graduate apresenta uma mudança quando comparado as outras duas classes, evidenciando uma mediana inferior quando comparado aos outros grupos, com respeito a variável inflation.rate.
names(data)## [1] "ï..Marital.status" "Application.mode"
## [3] "Application.order" "Course"
## [5] "Daytime.evening.attendance." "Previous.qualification"
## [7] "Nacionality" "Mother.s.qualification"
## [9] "Father.s.qualification" "Mother.s.occupation"
## [11] "Father.s.occupation" "Displaced"
## [13] "Educational.special.needs" "Debtor"
## [15] "Tuition.fees.up.to.date" "Gender"
## [17] "Scholarship.holder" "Age.at.enrollment"
## [19] "International" "Target"
boxplot(Age.at.enrollment ~ target)Podemos notar que agora com respeito a variável Age.at.enrollment um comportamento diferente entre as 3 classes, notando que o menor valor encontra-se na classe Graduate, e também a presença maior de outliers, analogo podemos notar que a classe Dropout possui em sua predominância valores mais altos. Esta variável referencia a idade na hora de inscrição do curso, podemos notar que estudantes que se inscrevem com idades menores se enquadram na classe de Graduate, ou seja, se graduam de fato, porém jovens com idades maiores ou mais avançadas que se inscrevem no curso, tendem a realizar o Dropout do curso, ou seja, desistem ou abandonam o curso.
- Trocando o nome das variáveis:
Vamos substituir os nomes das classes da variável target por valores numericos 0, 1 e 2, respectivamente
levels(target) <- c(0,1,2)
levels(target)## [1] "0" "1" "2"
Proporção das classes da variável target
round((table(target)/length(target))*100,2)## target
## 0 1 2
## 32.12 17.95 49.93
Podemos notar que existe uma desproporção entre as classes, não estando balanceadas, sendo a classe majoritaria a classe 2, 49.93% dos dados, Graduate, e a minoritária é a classe 1, Enrolled, com 17.95% dos dados.
Padronizando variaveis continuas
Agora vamos padronizar as variáveis continuas na base de dados, por apresentarem escalas distintas.
data_c_std = data.frame(scale(data_c))
knitr::kable(head(data_c_std))| PrevQualifiGrade | AdmissionGrade | X1stCredited | X1stEnrolled | X1stEvaluations | X1stApproved | X1stGrade | X1stWithoutEva | X2ndCredited | X2ndEnrolled | X2ndEvaluations | X2ndApproved | X2ndGrade | X2ndWithoutEva | Unemployment.rate | Inflation.rate | GDP |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| -0.8047503 | 0.0222263 | -0.3007791 | -2.5282738 | -1.9858437 | -1.5210854 | -2.1968541 | -0.1992505 | -0.2824104 | -2.8380158 | -2.0423990 | -1.4713606 | -1.9632667 | -0.1994184 | -0.2876059 | 0.1243724 | 0.7656743 |
| 2.0765846 | 1.0718050 | -0.3007791 | -0.1090928 | -0.5501298 | 0.4180026 | 0.6935202 | -0.1992505 | -0.2824104 | -0.1057141 | -0.5226233 | 0.5188450 | 0.6594872 | -0.1994184 | 0.8761230 | -1.1050966 | 0.3471602 |
| -0.8047503 | -0.1504018 | -0.3007791 | -0.1090928 | -1.9858437 | -1.5210854 | -2.1968541 | -0.1992505 | -0.2824104 | -0.1057141 | -2.0423990 | -1.4713606 | -1.9632667 | -0.1994184 | -0.2876059 | 0.1243724 | 0.7656743 |
| -0.8047503 | -0.5094682 | -0.3007791 | -0.1090928 | -0.0715585 | 0.4180026 | 0.5755457 | -0.1992505 | -0.2824104 | -0.1057141 | 0.4905605 | 0.1871441 | 0.4164027 | -0.1994184 | -0.8131610 | -1.4667052 | -1.3753558 |
| -2.4728915 | 1.0027538 | -0.3007791 | -0.1090928 | 0.1677271 | 0.0948213 | 0.3494280 | -0.1992505 | -0.2824104 | -0.1057141 | -0.5226233 | 0.5188450 | 0.5315479 | -0.1994184 | 0.8761230 | -1.1050966 | 0.3471602 |
| 0.0369028 | -0.8409141 | -0.3007791 | -0.5122897 | 0.4070128 | 0.0948213 | 0.2511160 | -0.1992505 | -0.2824104 | -0.5610977 | 2.2636322 | 0.1871441 | 0.2436847 | 6.4338689 | 1.7395349 | -0.6711664 | -0.4061652 |
round(colMeans(data_c_std),4)## PrevQualifiGrade AdmissionGrade X1stCredited X1stEnrolled
## 0 0 0 0
## X1stEvaluations X1stApproved X1stGrade X1stWithoutEva
## 0 0 0 0
## X2ndCredited X2ndEnrolled X2ndEvaluations X2ndApproved
## 0 0 0 0
## X2ndGrade X2ndWithoutEva Unemployment.rate Inflation.rate
## 0 0 0 0
## GDP
## 0
Agrupamentos
Abaixo será aplicado os métodos de agrupamento seguintes:
Kmeans
Fuzzy Kmeans
Kmeans Hierarquico
Foram utilizados outros métodos de agrupamento, porém devido ao tempo e custo computacional, sobre a base de dados utilizada. Além dos métodos supracitados, foram utilizados o MeanShift e Spectral Clustering.
- Tarefa de agrupamento: Além disso, a tarefa de agrupamento a ser desenvolvida será encontrar o numero de grupos ideias sobre a base escolhida, e além disso, analisar o quão bem métodos de agrupamentos conseguem indentificar os 3 grupos, Enrolled, Graduate e Dropout existentes na base de dados.
Selecionando K otimo
Abaixo, utilizaremos o metodo visto em sala, usando o elbow plot e também o metodo de maximização do valor da silhueta, para os métodos anteriores, com o intuito de encontrar o K ideal. Será selecionado apenas um valor de k entre os métodos, entre os modelos.
Selecionando K pelo Elbow Plot
K-Means
set.seed(13)
p1 <- elbow.plot(data_c_std)
p1Fuzzy K-Means
set.seed(13)
p2 <- elbow.plot(data_c_std, alg = "cmeans")
p2Hierarchiqual K-Means
set.seed(13)
p3 <- elbow.plot(data_c_std, alg = "hclust")
p3Resultado
n_cluster_p1 = p1$data$k[p1$data$d==max(p1$data$d)]
n_cluster_p2 = p2$data$k[p2$data$d==max(p2$data$d)]
n_cluster_p3 = p3$data$k[p3$data$d==max(p3$data$d)]
n_clusters_elbow = data.frame('kmeans'=n_cluster_p1,
'fuzzy.kmeans'=n_cluster_p2,
'hierarchical'=n_cluster_p3,
row.names = 'elbow')
knitr::kable(n_clusters_elbow)| kmeans | fuzzy.kmeans | hierarchical | |
|---|---|---|---|
| elbow | 4 | 6 | 4 |
grid.arrange(p1, p2, p3, nrow = 2)Selecionando K pela maximização da medida de Silhueta
K-Means
(clusters_km_sil = fviz_nbclust(data_c_std, kmeans, method = "silhouette"))n_c_km_sil = clusters_km_sil$data$clusters[clusters_km_sil$data$y == max(clusters_km_sil$data$y)]Fuzzy K-Means
(clusters_fuzzy_sil = fviz_nbclust(data_c_std, cmeans, method = "silhouette"))n_c_fuzzy_sil = clusters_fuzzy_sil$data$clusters[clusters_fuzzy_sil$data$y == max(clusters_fuzzy_sil$data$y)]Hierarquical K-Means
(clusters_hier_sil = fviz_nbclust(data_c_std, hcut, method = "silhouette"))n_c_hier_sil = clusters_hier_sil$data$clusters[clusters_hier_sil$data$y == max(clusters_hier_sil$data$y)]Resultado
n_clusters_silhuete = data.frame('kmeans'=n_c_km_sil,
'fuzzy.kmeans'=n_c_fuzzy_sil,
'hierarchical'=n_c_hier_sil,
row.names = 'silhuete')
knitr::kable(n_clusters_silhuete)| kmeans | fuzzy.kmeans | hierarchical | |
|---|---|---|---|
| silhuete | 3 | 2 | 4 |
grid.arrange(clusters_km_sil, clusters_fuzzy_sil, clusters_hier_sil, nrow = 2)Resultado K otimo
knitr::kable(rbind(n_clusters_elbow,n_clusters_silhuete))| kmeans | fuzzy.kmeans | hierarchical | |
|---|---|---|---|
| elbow | 4 | 6 | 4 |
| silhuete | 3 | 2 | 4 |
Acima podemos notar que, ao utilizarmos métodos de seleção diferentes, como o elbow utilizando a soma de quadrados dentro dos cluster versus a maximização da medida de silhueta, obtemos valores de K otimos distintos para os métodos K-Means e Fuzzy KMeans, já para o método Hierarquico obtemos o mesmo tamanho tanto sob o elbow quanto a maximização da medida de silhueta. Vale ressaltar também que pelo metodo do Elbow com o intuito de minimizar a soma de quadrados, obtivemos a deteccção de mais grupos para os métodos Kmeans e Fuzzy kmeans.
Por fim, visto que, relembrando os outros trabalhos realizados, temos indicios de que a base se divide em algo em torno de 3 grupos, dado essa informação, iremos utilizar os grupos otimos encontrados pela maximização da medida de silhueta.
Ajustando modelos de Agrupamento
K-Means
Instanciando o modelo
set.seed(13)
fit.kmeans <- kmeans(data_c_std, as.integer(n_clusters_silhuete$kmeans)) # Ajustar K de acordo com o gráfico
#fit.kmeans
g1 <- cluster_viz(data_c_std, as.factor(fit.kmeans$cluster), geom = "point",
palette= c("#00AFBB", "#E7B800","#FC4E07"),
main = "Cluster plot for the K-means method")Fuzzy-KMeans
Instanciando o modelo
set.seed(13)
fit.cmeans <- cmeans(data_c_std, as.integer(n_clusters_silhuete$fuzzy.kmeans)) # Ajustar K de acordo com o gráfico
#fit.cmeans
g2 <- cluster_viz(data_c_std, as.factor(fit.cmeans$cluster), geom = "point",
palette= c("#00AFBB","#B266FF"),
main = "Cluster plot for the Fuzzy K-means method")Hierarchical
Instanciando o modelo
set.seed(13)
fit.hclust <- hcut(data_c_std, as.integer(n_clusters_silhuete$hierarchical)) # Ajustar K de acordo com o gráfico
#fit.hclust
g3 <- cluster_viz(data_c_std, as.factor(fit.hclust$cluster), geom = "point",
palette= c("#00AFBB", "#E7B800","#FC4E07","#B266FF"),
main = "Cluster plot for the Hierarchical method")Comparando todos
grid.arrange(g1, g2, g3, nrow = 2)Acima, considerando o metodo KMeans, temos uma separação siginficante entre os 3 grupos, porém ainda com uma leve interseção entre os poligos da região dos grupos. Para o modelo Fuzzy, temos dois grupos muito bem separados, porém ainda com uma leve interseção entre seus poligonos. Por fim, temos o metodo hierarquico que foram encontrados 4 grupos, apresentando aparentemente uma grande interseção entre todos os grupos, aparentando não estar tão bem separado. Vale ressaltar que os pontos mais distantes, com respeito a componente 1, foram agrupados em um grupo diferente para o metodo hierarquico, quando comparamos o mesmo com os outros dois metodos Kmeans, fuzzy e normal.
Comparando resultados com os rotulos reais
Nessa seção, vamos realizar o PCA e separar em cores os grupos pelos respectivos rotulos. Aém disso, será comprado com o desepenho dos modelos anteriores, em identificar a verdadeira separação entre os grupos.
Gerando PCA
pca1 = prcomp(data_c_std);P = pca1$rotation ;sdev = pca1$sdev fviz_pca_ind(pca1,
col.ind = data$Target,
palette = c("#00AFBB", "#E7B800", "#FC4E07"),
addEllipses = TRUE,
ellipse.type = "confidence",
legend.title = "Engine shape",
repel = TRUE
) Acima podemos rever um gráfico feito na primeira prova, aonde temos as duas primeiras componentes obtidas pelo PCA, e separado pelos grupos de interesse, Dropout, Enrolled e Graduate. Dessa forma, como visto nas outras avaliações, notamos que o grupo enrolled é um grupo “indeciso”, que aparentemente apresenta caracteristicas similares em ambos os grupos, tornando uma tarefa de agrupamento bem complicada para separar esses 3 grupos. Para tanto, vamos mudar o objetivo, vamos mesclar as classes Enrolled e Graduate em uma classe “Others” e mantermos a classe Dropout, dessa forma teremos dois grupos, e assim rever o PCA acima separado por esses 2 grandes grupos.
Y = factor(data$Target)
levels(Y) = c("Dropout","Other","Other")
pca_fviz = fviz_pca_ind(pca1,
col.ind = Y,
palette = c("red","#B266FF"),
addEllipses = TRUE,
ellipse.type = "confidence",
legend.title = "Engine shape",
repel = TRUE
)
pca_fvizAgora com 2 grupos bem separados, vamos comparar os resultados obtidos pelos outros modelos com os rotulos pre-existentes.
grid.arrange(pca_fviz,g1, g2, g3, nrow = 2)## Warning: ggrepel: 4424 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
#expand.grid(pca_fviz, g1,g2,g3)Visto que agora temos dois rotulos reais na base, “Others” e “Dropout”, temos dois grupos bem separados, porém os modelos Hierarquico e K-means classico identificaram mais do que 2 grupos. Dessa forma, afim de comparação graficas e para metricas futuras, iremos retreinar os modelos e considerar 2 clusters.
Reajustando modelos
K-Means
set.seed(13)
fit.kmeans.f <- kmeans(data_c_std, 2) # Ajustar K de acordo com o gráfico
#fit.kmeans
g1.f <- cluster_viz(data_c_std, as.factor(fit.kmeans.f$cluster), geom = "point",
palette= c("red","#B266FF"),
main = "Cluster plot for the K-means method")Fuzzy-KMeans
set.seed(13)
fit.cmeans.f <- cmeans(data_c_std, 2) # Ajustar K de acordo com o gráfico
#fit.cmeans
g2.f <- cluster_viz(data_c_std, as.factor(fit.cmeans.f$cluster), geom = "point",
palette= c("red","#B266FF"),
main = "Cluster plot for the Fuzzy K-means method")Hierarchical
set.seed(13)
fit.hclust.f <- hcut(data_c_std, 2) # Ajustar K de acordo com o gráfico
#fit.hclust
g3.f <- cluster_viz(data_c_std, as.factor(fit.hclust.f$cluster), geom = "point",
palette= c("red","#B266FF"),
main = "Cluster plot for the Hierarchical method")Comparando modelos reajustados
grid.arrange(pca_fviz,g1.f, g2.f, g3.f, nrow = 2)## Warning: ggrepel: 4424 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
Acima podemos notar a separação dos dois grupos, para os rotulos reais e para os agrupamentos de cada modelo. Graficamente, podemos notar que o pior modelo, quando comparado aos rotulos reais, é o modelo hierarquico, super agrupando a classe 2, referente ao grupo “Others”, e sub agrupando o grupo 1, “Dropout”. Aparentemente, o modelo que melhor separou os dois grupos foi o modelo Fuzzy K-Means.
Vamos agora, primeiramente para o “K” otimo encontrado pelos modelos e depois para os dois grupos finais, “Others” e “Dropout”, verificar qual dos modelos melhor agrupou os dados.
Avaliação dos modelos finais
Conectividade
K otimo
c1 <- connectivity(clusters = fit.kmeans$cluster, Data = data_c_std)
c2 <- connectivity(clusters = fit.cmeans$cluster, Data = data_c_std)
c3 <- connectivity(clusters = fit.hclust$cluster, Data = data_c_std)K=2 (Dropout e Others)
c1.f <- connectivity(clusters = fit.kmeans.f$cluster, Data = data_c_std)
c2.f <- connectivity(clusters = fit.cmeans.f$cluster, Data = data_c_std)
c3.f <- connectivity(clusters = fit.hclust.f$cluster, Data = data_c_std)Dunn
K otimo
d1 <- dunn(clusters = fit.kmeans$cluster, Data = data_c_std)
d2 <- dunn(clusters = fit.cmeans$cluster, Data = data_c_std)
d3 <- dunn(clusters = fit.hclust$cluster, Data = data_c_std)K=2 (Dropout e Others)
d1.f <- dunn(clusters = fit.kmeans.f$cluster, Data = data_c_std)
d2.f <- dunn(clusters = fit.cmeans.f$cluster, Data = data_c_std)
d3.f <- dunn(clusters = fit.hclust.f$cluster, Data = data_c_std)Silhueta
K otimo
s.kmeans <- silhouette(fit.kmeans$cluster, dist = dist(data_c_std)^2)
s.cmeans <- silhouette(fit.cmeans$cluster, dist = dist(data_c_std)^2)
s.hclust <- silhouette(fit.hclust$cluster, dist = dist(data_c_std)^2)s1 <- summary(s.kmeans)$avg.width
s2 <- summary(s.cmeans)$avg.width
s3 <- summary(s.hclust)$avg.widthK=2 (Dropout e Others)
s.kmeans.f <- silhouette(fit.kmeans.f$cluster, dist = dist(data_c_std)^2)
s.cmeans.f <- silhouette(fit.cmeans.f$cluster, dist = dist(data_c_std)^2)
s.hclust.f <- silhouette(fit.hclust.f$cluster, dist = dist(data_c_std)^2)s1.f <- summary(s.kmeans.f)$avg.width
s2.f <- summary(s.cmeans.f)$avg.width
s3.f <- summary(s.hclust.f)$avg.widthIndice de Rand
Como temos conhecimento dos rotulos verdadeiros dos dados, vamos utilizar do indice de rand também a nivel de comparação da similaridade entre os grupos, verdadeiro e agrupado pelo respectivo modelo.
Y_f = Y
levels(Y_f)=c(1,2)
Y_f = as.integer(Y_f)
kmeans_rand = rand.index(Y_f, fit.kmeans.f$cluster)
cmeans_rand = rand.index(Y_f, fit.cmeans.f$cluster)
hclust_rand = rand.index(Y_f, fit.hclust.f$cluster)rand_results = t(data.frame('kmeans'=kmeans_rand,
'fuzzy'=cmeans_rand,
'hierarchical'=hclust_rand,row.names = 'rand'))
knitr::kable(rand_results)| rand | |
|---|---|
| kmeans | 0.6820501 |
| fuzzy | 0.6532674 |
| hierarchical | 0.6828697 |
Resultado da avaliação
results <- matrix(c(c1, c2, c3, d1, d2, d3, s1, s2, s3), nrow = 3)
colnames(results) <- c("Connectivity", "Dunn", "Silhouette")
row.names(results) <- c(paste0("K-means (K_optim = ",n_clusters_silhuete[1],")"),
paste0("Fuzzy K-means (K_optim = ",n_clusters_silhuete[2],")"),
paste0("Hierarchical (K_optim = ",n_clusters_silhuete[3],")"))
knitr::kable(results) | Connectivity | Dunn | Silhouette | |
|---|---|---|---|
| K-means (K_optim = 3) | 265.5651 | 0.0152675 | 0.5441557 |
| Fuzzy K-means (K_optim = 2) | 972.1337 | 0.0144935 | 0.2914210 |
| Hierarchical (K_optim = 4) | 183.9960 | 0.0305319 | 0.5008628 |
results.f <- matrix(c(c1.f, c2.f, c3.f, d1.f, d2.f, d3.f, s1.f, s2.f, s3.f), nrow = 3)
colnames(results.f) <- c("Connectivity", "Dunn", "Silhouette")
row.names(results.f) <- c(paste0("K-means (K = ",2,")"),
paste0("Fuzzy K-means (K = ",2,")"),
paste0("Hierarchical (K = ",2,")"))
knitr::kable(results.f) | Connectivity | Dunn | Silhouette | |
|---|---|---|---|
| K-means (K = 2) | 159.11349 | 0.0262033 | 0.4762094 |
| Fuzzy K-means (K = 2) | 972.13373 | 0.0144935 | 0.2914210 |
| Hierarchical (K = 2) | 25.88214 | 0.0621647 | 0.4150056 |
all_result = rbind(results,results.f)
knitr::kable(all_result)| Connectivity | Dunn | Silhouette | |
|---|---|---|---|
| K-means (K_optim = 3) | 265.56508 | 0.0152675 | 0.5441557 |
| Fuzzy K-means (K_optim = 2) | 972.13373 | 0.0144935 | 0.2914210 |
| Hierarchical (K_optim = 4) | 183.99603 | 0.0305319 | 0.5008628 |
| K-means (K = 2) | 159.11349 | 0.0262033 | 0.4762094 |
| Fuzzy K-means (K = 2) | 972.13373 | 0.0144935 | 0.2914210 |
| Hierarchical (K = 2) | 25.88214 | 0.0621647 | 0.4150056 |
knitr::kable(rand_results)| rand | |
|---|---|
| kmeans | 0.6820501 |
| fuzzy | 0.6532674 |
| hierarchical | 0.6828697 |
Ao analisarmos a tabela acima, podemos notar que o “pior” modelo é o fuzzy K-means, por apresentar a maior conectividade, o menor valor de Dunn e os menores valores da medida de silhueta, para ambos os cenarios de K, otimo e K=2. Entretanto, quando analisamos graficamente, para K=2, podemos notar, aparentemente que os modelos que melhor separa os dois grupos “Others” e “Dropout” são os modelos Fuzzy e Kmeans, sendo o hierarquico oque pior performa.
Percebemos contradições claras entre as métricas e a analise gráfica, na analise grafica, é notavel que os modelos fuzzy e kmeans normal são os que melhor conseguem separar os dois conjuntos, porém quando analisamos as metricas, notamos que, considerando os grupos Others e Dropout, K = 2, a menor conectividade, maior valor de Dunn são do modelo que graficamente, foi o pior, o modelo hierarquico. Porém quando olhamos isoladamente para a medida silhueta o melhor modelo é, tanto para o caso do K otimo, quanto para o modelo com os dois grupos, é o K-Means basico.
Dessa forma, foi tentado trazer o indice de rand, indice para calcular a similaridade entre os grupos, essa metrica é mais utilizada para problemas que se assemalham a aprendizagem semi supervisionado, onde temos os rotulos, e podemos comparar o que o modelo agrupou com o verdadeiro rotulo. Dessa forma, podemos notar que pelo indice de rand, os modelos K-Means e Hierarquicos tiveram um empate técnico.
Antes de concluirmos, podemos notar algo importante, considerando o modelo hierarquico e seu agrupamento, e o indice de rand do mesmo. Podemos notar que o modelo sub agrupou o grupo 1 e super agrupou o grupo 2, isso pode ter afetado o valor da medida de rand, pois dentro do grupo menor, existe uma valores muito similares, compensando a discrepancia do grupo maior, com valores diferentes.
Concluimos então, considerando a medida de silhueta e o indice de rand, o modelo selecionado para o agrupamento dos grupos “Other” e “Dropout”, será o modelo K-Means basico, por apresentar o maior valor da medida de silhueta e apresentar o segundo maior valor do indice de rand (Visto que o hierarquico não agrupou de forma significante, mesmo tendo valores de métricas bons).
Um adendo muito importante foi visto nesta seção, o deficit com respeito a metricas de avaliação de metodos de agrupamento, mesmo tendo valores “bons” para o modelo de agrupamento hierarquico, podemos ver no grafico que ele não separou de forma significante os grupos, tendo um problema forte na hora de agrupar grupos sobrepostos.