Evasão de alunos (UFCG) - Período 1

A partir do problema de evasão que pode ser encontrado aqui, foi feito uma análise de desempenho comparando diferentes modelos para a predição deste problema. Inicialmente foi utilizada a técnica de florestas de árvores aleatórias para o treinamento de um modelo. O resultado da predição foi satisfatório para a competição e pode ser conferido aqui.

Análise de Desempenho de modelos

Foram escolhidos três modelos para a comparação de desempenho: árvores aleatórias, algoritmo KNN e SVM. A ideia é treinar os modelos e após a predição comparar os resultados através de métricas que serão descritas mais adiante.

library(caret)
library(dplyr)
library(kernlab)
set.seed(3456)
training_evasao <- read.csv("~/Documents/ad1/problema6/training_evasao.csv")
alunos_fera <- training_evasao %>% filter(PERIODO_RELATIVO == 1) %>% droplevels()
summary(alunos_fera)
##        ID          MATRICULA           COD_CURSO       
##  Min.   :    2   Min.   :  2636462   Min.   :12204100  
##  1st Qu.: 5452   1st Qu.:249463498   1st Qu.:12204100  
##  Median :10836   Median :504580140   Median :14123100  
##  Mean   :10516   Mean   :498051708   Mean   :13621038  
##  3rd Qu.:15848   3rd Qu.:739617571   3rd Qu.:14123100  
##  Max.   :19536   Max.   :999280527   Max.   :14123100  
##                                                        
##                  CURSO          PERIODO         CODIGO       
##  ENFERMAGEM - D     : 3544   Min.   :2002   Min.   :1105013  
##  ENGENHARIA ELÉTRICA:10002   1st Qu.:2009   1st Qu.:1109103  
##                              Median :2010   Median :1201134  
##                              Mean   :2010   Mean   :1240530  
##                              3rd Qu.:2012   3rd Qu.:1404132  
##                              Max.   :2013   Max.   :1503070  
##                                                              
##                                   DISCIPLINA      CREDITOS    
##  INTRODUCAO A PROGRAMACAO              :1412   Min.   :0.000  
##  INTRODUCAO A ENGENHARIA ELETRICA      :1388   1st Qu.:3.000  
##  CIÊNCIAS DO AMBIENTE                  :1366   Median :4.000  
##  EXPRESSAO GRAFICA                     :1344   Mean   :3.401  
##  ÁLGEBRA VETORIAL E GEOMETRIA ANALÍTICA:1332   3rd Qu.:4.000  
##  CALCULO DIFERENCIAL E INTEGRAL I      :1319   Max.   :8.000  
##  (Other)                               :5385                  
##                                   DEPARTAMENTO      MEDIA       
##  UNID. ACAD. DE CIÊNCIAS DA SAÚDE (UACS):3544   Min.   : 0.000  
##  UNID. ACAD. DE MATEMÁTICA              :2752   1st Qu.: 3.900  
##  UNID. ACAD. DE ENGENHARIA ELÉTRICA     :1598   Median : 7.000  
##  UNID. ACAD. DE FÍSICA                  :1418   Mean   : 5.872  
##  UNID. ACAD. DE SISTEMAS E COMPUTAÇÃO   :1416   3rd Qu.: 8.100  
##  UNID. ACAD. DE ENGENHARIA CIVIL        :1366   Max.   :10.000  
##  (Other)                                :1452   NA's   :332     
##                 SITUACAO    PERIODO_INGRESSO PERIODO_RELATIVO
##  Aprovado           :9557   Min.   :2002     Min.   :1       
##  Reprovado          :2112   1st Qu.:2009     1st Qu.:1       
##  Reprovado por Falta:1527   Median :2010     Median :1       
##  Trancado           : 350   Mean   :2010     Mean   :1       
##                             3rd Qu.:2012     3rd Qu.:1       
##                             Max.   :2013     Max.   :1       
##                                                              
##    COD_EVASAO    
##  Min.   :0.0000  
##  1st Qu.:0.0000  
##  Median :0.0000  
##  Mean   :0.1065  
##  3rd Qu.:0.0000  
##  Max.   :1.0000  
## 

Sumarizando os dados e Criando novas variáveis.

alunos_fera_summarised <- alunos_fera %>% group_by(MATRICULA, COD_CURSO, CURSO, PERIODO, 
                                                   PERIODO_INGRESSO,PERIODO_RELATIVO,COD_EVASAO) %>% 
            summarise(
            TOTAL_CREDITOS=sum(CREDITOS), 
            CRA=round(sum(MEDIA, na.rm = TRUE)/(n() -(ifelse(NA %in% MEDIA, count_NAs(MEDIA) ,0))),digits=2), 
            TEM_APROVACAO=ifelse("Aprovado" %in% SITUACAO, TRUE, FALSE),
            TEM_REPROV_POR_NOTA=ifelse("Reprovado" %in% SITUACAO, TRUE, FALSE),
            TEM_REPROV_POR_FALTA=ifelse("Reprovado por Falta" %in% SITUACAO,TRUE,FALSE),

            CRA_ZERO=ifelse(CRA == 0, TRUE, FALSE),
            CRA_DE_EVASAO=ifelse(CRA <= 1.9,TRUE,FALSE),
            
            TRANCAMENTO=ifelse(is.na(CRA),TRUE, FALSE),
            POS_REUNI=ifelse(unique(PERIODO) > "2008.2", TRUE, FALSE),
            C1=(TEM_REPROV_POR_FALTA && CRA_DE_EVASAO && POS_REUNI),
            C2=(TEM_REPROV_POR_FALTA && CRA_ZERO && POS_REUNI),
            C3=(TEM_REPROV_POR_FALTA && CRA_ZERO),
            C4=((TEM_APROVACAO == FALSE) && (TRANCAMENTO == FALSE)),
            C5=((TEM_REPROV_POR_NOTA == FALSE) && (TRANCAMENTO == FALSE)),
            C6=((TEM_APROVACAO == TRUE) && (TRANCAMENTO == FALSE)),
            FALSO_FERA=eh_falso_fera(unique(CURSO),DISCIPLINA))

alunos_fera_summarised<- as.data.frame(alunos_fera_summarised)
## 'data.frame':    1871 obs. of  23 variables:
##  $ MATRICULA           : int  2636462 2714857 2791762 3521919 5062803 5604386 5608990 6147697 6292983 6420105 ...
##  $ COD_CURSO           : int  12204100 14123100 14123100 12204100 14123100 14123100 14123100 12204100 14123100 12204100 ...
##  $ CURSO               : Factor w/ 2 levels "ENFERMAGEM - D",..: 1 2 2 1 2 2 2 1 2 1 ...
##  $ PERIODO             : num  2013 2011 2006 2009 2012 ...
##  $ PERIODO_INGRESSO    : num  2013 2011 2006 2009 2012 ...
##  $ PERIODO_RELATIVO    : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ COD_EVASAO          : Factor w/ 2 levels "0","1": 2 1 1 1 1 1 1 1 1 1 ...
##  $ TOTAL_CREDITOS      : num  28 25 25 28 25 25 17 28 25 28 ...
##  $ CRA                 : num  0 7.84 5.37 7 7.87 8.23 3.35 7.34 7.73 7.78 ...
##  $ TEM_APROVACAO       : Factor w/ 2 levels "FALSE","TRUE": 1 2 2 2 2 2 2 2 2 2 ...
##  $ TEM_REPROV_POR_NOTA : Factor w/ 2 levels "FALSE","TRUE": 1 2 2 1 1 1 2 2 1 1 ...
##  $ TEM_REPROV_POR_FALTA: Factor w/ 2 levels "FALSE","TRUE": 2 1 1 1 1 1 2 1 1 1 ...
##  $ CRA_ZERO            : Factor w/ 2 levels "FALSE","TRUE": 2 1 1 1 1 1 1 1 1 1 ...
##  $ CRA_DE_EVASAO       : Factor w/ 2 levels "FALSE","TRUE": 2 1 1 1 1 1 1 1 1 1 ...
##  $ TRANCAMENTO         : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ POS_REUNI           : Factor w/ 2 levels "FALSE","TRUE": 2 2 1 2 2 2 1 2 2 2 ...
##  $ C1                  : Factor w/ 2 levels "FALSE","TRUE": 2 1 1 1 1 1 1 1 1 1 ...
##  $ C2                  : Factor w/ 2 levels "FALSE","TRUE": 2 1 1 1 1 1 1 1 1 1 ...
##  $ C3                  : Factor w/ 2 levels "FALSE","TRUE": 2 1 1 1 1 1 1 1 1 1 ...
##  $ C4                  : Factor w/ 2 levels "FALSE","TRUE": 2 1 1 1 1 1 1 1 1 1 ...
##  $ C5                  : Factor w/ 2 levels "FALSE","TRUE": 2 1 1 2 2 2 1 1 2 2 ...
##  $ C6                  : Factor w/ 2 levels "FALSE","TRUE": 1 2 2 2 2 2 2 2 2 2 ...
##  $ FALSO_FERA          : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 2 1 1 1 ...

Seleção das variáveis que serão utilizadas nos modelos.

df <- alunos_fera_summarised[c("MATRICULA","CURSO","CRA_ZERO","CRA_DE_EVASAO","TEM_APROVACAO",
                                      "TEM_REPROV_POR_NOTA","TEM_REPROV_POR_FALTA","TRANCAMENTO",
                                      "POS_REUNI","FALSO_FERA","C1","C2","C3","C4","C5","C6",
                                      "COD_EVASAO")]

trainIndex <- createDataPartition(df$COD_EVASAO, p = .9, list = FALSE, times = 1)

alunosTrain <- df[trainIndex,]
alunosTest <- df[-trainIndex,]

Parâmentro de ajuste

fitControl <- trainControl(## 10-fold CV
                           method = "cv",
                           number = 10)

Para a utilização dos dados de treino, foi necessário realizar um balanceamento nos dados afim de equilibrar o número de classes referentes a evasão, afim de evitar que os modelos dêem prioridade a uma classe majoritária.

table(alunosTrain$COD_EVASAO)
## 
##    0    1 
## 1502  183
probs_balanceads <- ifelse(alunosTrain$COD_EVASAO == 0, .1 / 1502, .9 / 183)
is <- sample(1:NROW(alunosTrain), 500, prob = probs_balanceads, replace = F)
alunosTrain_b <- alunosTrain[is, ]
table(alunosTrain_b$COD_EVASAO)
## 
##   0   1 
## 317 183

KNN

No algoritmo KNN ou dos K vizinhos mais próximos (k-nearest neighbors) não há uma fase de contrução de modelo, onde este é gerado para cada instância de teste, método este conhecido como lazy learner. Neste caso, o algoritmo será testado com o número de vizinhos variando de 2 a 20 (k= 2..20), afim de encontrar um número de vizinhos ideal para este problema.

# o treinamento pode demorar... aqui por exemplo: 
ptm <- proc.time()

knnFit <- train(COD_EVASAO ~ ., data = alunosTrain_b,
                 method = "knn",
                 trControl = fitControl, 
                 preProcess = c("center","scale"), 
                 tuneGrid = data.frame(.k = 2:20))

time_knn <- proc.time() - ptm

knnFit
## k-Nearest Neighbors 
## 
## 500 samples
##  16 predictor
##   2 classes: '0', '1' 
## 
## Pre-processing: centered, scaled 
## Resampling: Cross-Validated (10 fold) 
## 
## Summary of sample sizes: 431, 431, 430, 431, 431, 432, ... 
## 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa      Accuracy SD  Kappa SD 
##    2  0.8019730  0.5703831  0.06848870   0.1483221
##    3  0.8586662  0.6736923  0.07361868   0.1711975
##    4  0.8564961  0.6706215  0.06061954   0.1419305
##    5  0.8753365  0.7086785  0.07081351   0.1700532
##    6  0.8710812  0.6995714  0.06029199   0.1450493
##    7  0.8836699  0.7256252  0.06883501   0.1654170
##    8  0.8857532  0.7302015  0.06885872   0.1652622
##    9  0.8836699  0.7242029  0.06813082   0.1658246
##   10  0.8836273  0.7253838  0.06543722   0.1578932
##   11  0.8877940  0.7344370  0.06614952   0.1594025
##   12  0.8814997  0.7192650  0.06149164   0.1479646
##   13  0.8836699  0.7229455  0.06813082   0.1653541
##   14  0.8836699  0.7229455  0.06813082   0.1653541
##   15  0.8836699  0.7229455  0.06813082   0.1653541
##   16  0.8836699  0.7229455  0.06813082   0.1653541
##   17  0.8815422  0.7179848  0.06509725   0.1583168
##   18  0.8815422  0.7179848  0.06509725   0.1583168
##   19  0.8815422  0.7179848  0.06509725   0.1583168
##   20  0.8794589  0.7135079  0.06417508   0.1561183
## 
## Accuracy was used to select the optimal model using  the largest value.
## The final value used for the model was k = 11.

Após o treino ser realizado e testado com números de vizinhos diferentes (k=2..20), o modelo considerado ótimo utilizou 11 vizinhos, atingindo um maior valor de acurácia quando comparado aos outros modelos testados no treino. Através do gráfico abaixo é possível observar que há um número de vizinhos onde se obtém uma melhor acurácia, e a partir de um determinado valor, a acurácia se mantém constante.

plot(knnFit)

alunosTest$CRA_ZERO[is.na(alunosTest$CRA_ZERO)] <- FALSE
alunosTest$CRA_DE_EVASAO[is.na(alunosTest$CRA_DE_EVASAO)] <- FALSE

knnPredict <- predict(knnFit,newdata = alunosTest)
confusionMatrix(knnPredict, alunosTest$COD_EVASAO)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 161   7
##          1   5  13
##                                         
##                Accuracy : 0.9355        
##                  95% CI : (0.89, 0.9662)
##     No Information Rate : 0.8925        
##     P-Value [Acc > NIR] : 0.03153       
##                                         
##                   Kappa : 0.6484        
##  Mcnemar's Test P-Value : 0.77283       
##                                         
##             Sensitivity : 0.9699        
##             Specificity : 0.6500        
##          Pos Pred Value : 0.9583        
##          Neg Pred Value : 0.7222        
##              Prevalence : 0.8925        
##          Detection Rate : 0.8656        
##    Detection Prevalence : 0.9032        
##       Balanced Accuracy : 0.8099        
##                                         
##        'Positive' Class : 0             
## 

Analisando a predição, foi obtido um bom resultado e, verificando a matriz de confusão, o número de falsos positivos é baixo porém é o erro que, no geral, é considerado mais grave. Um fato interessante é em relação as métricas de Accuracy e Kappa, onde após a predição ouve um aumento no Accuracy e um decaimento no Kappa.

SVM

Para este modelo, foi utilizado o tamanho do parâmentro de ajuste igual a 8, pois utilizar valores maiores sairia mais custoso no quesito tempo, inviabilizando o treino com este modelo. O accuracy foi mantido como métrica para o treino pois esta foi a utilizada em outros modelos para a comparação.

ptm <- proc.time()

svmFit <- train(COD_EVASAO ~ ., data = alunosTrain_b,
                method = "svmRadial",
                trControl = fitControl, 
                preProcess = c("center","scale"), 
                tuneLength = 8, 
                metric = "accuracy") 

time_svm <- proc.time() - ptm

svmFit
## Support Vector Machines with Radial Basis Function Kernel 
## 
## 500 samples
##  16 predictor
##   2 classes: '0', '1' 
## 
## Pre-processing: centered, scaled 
## Resampling: Cross-Validated (10 fold) 
## 
## Summary of sample sizes: 430, 431, 431, 431, 431, 431, ... 
## 
## Resampling results across tuning parameters:
## 
##   C      Accuracy   Kappa      Accuracy SD  Kappa SD  
##    0.25  0.8871771  0.7331759  0.04339274   0.10792415
##    0.50  0.8850494  0.7273484  0.04470289   0.11216287
##    1.00  0.8850494  0.7273484  0.04470289   0.11216287
##    2.00  0.8850494  0.7273484  0.04470289   0.11216287
##    4.00  0.8725051  0.7008105  0.04286300   0.10748091
##    8.00  0.8662107  0.6874111  0.04157992   0.10553459
##   16.00  0.8641274  0.6831635  0.04043700   0.10269212
##   32.00  0.8620441  0.6789493  0.03659051   0.09494256
## 
## Tuning parameter 'sigma' was held constant at a value of 0.1049139
## Accuracy was used to select the optimal model using  the largest value.
## The final values used for the model were sigma = 0.1049139 and C = 0.25.
plot(svmFit)

Através do gráfico acima é possível observar que ao aumentar o custo, o desempenho do modelo em relação a acurácia cai bastante. Com isso, o modelo ótimo utilizado possui um valor de custo baixo.

svmPredict <- predict(svmFit,newdata = alunosTest)
confusionMatrix(svmPredict, alunosTest$COD_EVASAO)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 160   7
##          1   6  13
##                                           
##                Accuracy : 0.9301          
##                  95% CI : (0.8834, 0.9623)
##     No Information Rate : 0.8925          
##     P-Value [Acc > NIR] : 0.05584         
##                                           
##                   Kappa : 0.6277          
##  Mcnemar's Test P-Value : 1.00000         
##                                           
##             Sensitivity : 0.9639          
##             Specificity : 0.6500          
##          Pos Pred Value : 0.9581          
##          Neg Pred Value : 0.6842          
##              Prevalence : 0.8925          
##          Detection Rate : 0.8602          
##    Detection Prevalence : 0.8978          
##       Balanced Accuracy : 0.8069          
##                                           
##        'Positive' Class : 0               
## 

C50

O modelo de floresta de árvores aleatórias foi utilizado para a solução do problema e também será comparado com os já citados. Como parâmetro de ajuste, o modelo é construído para uma floresta com dez árvores, onde o algoritmo verifica se realmente se faz necessária a criação do número de árvores especificado.

ptm <- proc.time()

treeFit <- train(COD_EVASAO ~ ., data = alunosTrain_b,
                method = "C5.0",
                trControl = fitControl,
                tuneGrid=expand.grid(model = "tree", winnow = FALSE, trials = c(1:10)))

rand_forest_time <- proc.time() - ptm

treeFit
## C5.0 
## 
## 500 samples
##  16 predictor
##   2 classes: '0', '1' 
## 
## No pre-processing
## Resampling: Cross-Validated (10 fold) 
## 
## Summary of sample sizes: 431, 432, 430, 432, 431, 431, ... 
## 
## Resampling results across tuning parameters:
## 
##   trials  Accuracy   Kappa      Accuracy SD  Kappa SD  
##    1      0.8893029  0.7395710  0.03249358   0.07988502
##    2      0.8893029  0.7395710  0.03249358   0.07988502
##    3      0.8913862  0.7447227  0.03360757   0.08268148
##    4      0.8913862  0.7447227  0.03360757   0.08268148
##    5      0.8893454  0.7404360  0.03512639   0.08551358
##    6      0.8913862  0.7447227  0.03360757   0.08268148
##    7      0.8872621  0.7352843  0.03392313   0.08251598
##    8      0.8913862  0.7447227  0.03360757   0.08268148
##    9      0.8893029  0.7395710  0.03249358   0.07988502
##   10      0.8893029  0.7395710  0.03249358   0.07988502
## 
## Tuning parameter 'model' was held constant at a value of tree
## 
## Tuning parameter 'winnow' was held constant at a value of FALSE
## Accuracy was used to select the optimal model using  the largest value.
## The final values used for the model were trials = 3, model = tree
##  and winnow = FALSE.
plot(treeFit)

Através do gráfico acima é possível observar que não são se faz necessário um alto número de iterações para obter uma maior acurácia, pois já se obtém um bom resultado com poucas iterações.

treePredict <- predict(treeFit,newdata = alunosTest)
confusionMatrix(treePredict, alunosTest$COD_EVASAO)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 159   6
##          1   7  14
##                                           
##                Accuracy : 0.9301          
##                  95% CI : (0.8834, 0.9623)
##     No Information Rate : 0.8925          
##     P-Value [Acc > NIR] : 0.05584         
##                                           
##                   Kappa : 0.6437          
##  Mcnemar's Test P-Value : 1.00000         
##                                           
##             Sensitivity : 0.9578          
##             Specificity : 0.7000          
##          Pos Pred Value : 0.9636          
##          Neg Pred Value : 0.6667          
##              Prevalence : 0.8925          
##          Detection Rate : 0.8548          
##    Detection Prevalence : 0.8871          
##       Balanced Accuracy : 0.8289          
##                                           
##        'Positive' Class : 0               
## 

Os resultados obtidos nesta predição também foram satisfatórios. Entretanto, quando comparados os valores de Accuracy e Kappa das predições, o modelo que utiliza o algoritmo KNN possui um resultado levemente superior.

Comparando os modelos

Após realizados os treinos e predições, foram comparados os três modelos utilizados através das métricas Accuracy e Kappa. Ao comparar os resultados obtidos abaixo, é evidente o destaque para o modelo KNN, onde este obtém os melhores resultados para as métricas em questão.

resamps <- resamples(list(KNN = knnFit, SVM = svmFit, C50=treeFit))
resamps
## 
## Call:
## resamples.default(x = list(KNN = knnFit, SVM = svmFit, C50 = treeFit))
## 
## Models: KNN, SVM, C50 
## Number of resamples: 10 
## Performance metrics: Accuracy, Kappa 
## Time estimates for: everything, final model fit
summary(resamps)
## 
## Call:
## summary.resamples(object = resamps)
## 
## Models: KNN, SVM, C50 
## Number of resamples: 10 
## 
## Accuracy 
##       Min. 1st Qu. Median   Mean 3rd Qu.   Max. NA's
## KNN 0.7708  0.8542 0.8958 0.8878  0.9167 0.9787    0
## SVM 0.8298  0.8549 0.8945 0.8872  0.9167 0.9583    0
## C50 0.8542  0.8600 0.8936 0.8914  0.9101 0.9592    0
## 
## Kappa 
##       Min. 1st Qu. Median   Mean 3rd Qu.   Max. NA's
## KNN 0.4634  0.6485 0.7543 0.7344  0.8113 0.9519    0
## SVM 0.5831  0.6593 0.7437 0.7332  0.8076 0.9091    0
## C50 0.6316  0.6795 0.7499 0.7447  0.7886 0.9099    0

Realizando nova submissão

Após a comparação entre os modelos, foi constatado uma leve melhora no desempenho da predição com as técnicas de KNN e SVM. Com isso, será feita uma nova submissão na competição da plataforma Kaggle e espera-se uma pontuação mais alta do que a última obtida.

Sumarização dos dados de teste

test_first_round_kaggle <- read.csv("~/Documents/ad1/problema6/test_first_round_kaggle.csv")

detach("package:plyr", unload=TRUE)
alunos_teste <- test_first_round_kaggle %>% group_by(MATRICULA, COD_CURSO, CURSO, PERIODO, 
                                                   PERIODO_INGRESSO,PERIODO_RELATIVO) %>% 
            summarise(
            TOTAL_CREDITOS=sum(CREDITOS), 
            CRA=round(sum(MEDIA, na.rm = TRUE)/(n() -(ifelse(NA %in% MEDIA, count_NAs(MEDIA) ,0))),digits=2), 
            TEM_APROVACAO=ifelse("Aprovado" %in% SITUACAO, TRUE, FALSE),
            TEM_REPROV_POR_NOTA=ifelse("Reprovado" %in% SITUACAO, TRUE, FALSE),
            TEM_REPROV_POR_FALTA=ifelse("Reprovado por Falta" %in% SITUACAO,TRUE,FALSE),

            CRA_ZERO=ifelse(CRA == 0, TRUE, FALSE),
            CRA_DE_EVASAO=ifelse(CRA <= 1.9,TRUE,FALSE),
            
            TRANCAMENTO=ifelse(is.na(CRA),TRUE, FALSE),
            POS_REUNI=ifelse(unique(PERIODO) > "2008.2", TRUE, FALSE),
            C1=(TEM_REPROV_POR_FALTA && CRA_DE_EVASAO && POS_REUNI),
            C2=(TEM_REPROV_POR_FALTA && CRA_ZERO && POS_REUNI),
            C3=(TEM_REPROV_POR_FALTA && CRA_ZERO),
            C4=((TEM_APROVACAO == FALSE) && (TRANCAMENTO == FALSE)),
            C5=((TEM_REPROV_POR_NOTA == FALSE) && (TRANCAMENTO == FALSE)),
            C6=((TEM_APROVACAO == TRUE) && (TRANCAMENTO == FALSE)),
            FALSO_FERA=eh_falso_fera(unique(CURSO),DISCIPLINA))

alunos_teste <- as.data.frame(alunos_teste)

Ajuste nos tipos das variáveis do teste

## 'data.frame':    123 obs. of  22 variables:
##  $ MATRICULA           : int  1565650 8696570 9822368 11928230 35551592 38116320 38449794 51710560 58841481 59967279 ...
##  $ COD_CURSO           : int  14123100 12204100 14123100 14123100 14123100 12204100 14123100 14123100 12204100 14123100 ...
##  $ CURSO               : Factor w/ 2 levels "ENFERMAGEM - D",..: 2 1 2 2 2 1 2 2 1 2 ...
##  $ PERIODO             : num  2014 2014 2014 2014 2014 ...
##  $ PERIODO_INGRESSO    : num  2014 2014 2014 2014 2014 ...
##  $ PERIODO_RELATIVO    : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ TOTAL_CREDITOS      : num  25 28 9 25 25 28 25 25 28 25 ...
##  $ CRA                 : num  3.36 8.34 5 7.81 4.37 1.73 9.21 9.41 7.64 6.29 ...
##  $ TEM_APROVACAO       : Factor w/ 2 levels "FALSE","TRUE": 2 2 2 2 2 2 2 2 2 2 ...
##  $ TEM_REPROV_POR_NOTA : Factor w/ 2 levels "FALSE","TRUE": 2 1 2 1 2 1 1 1 1 2 ...
##  $ TEM_REPROV_POR_FALTA: Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 2 1 1 1 1 ...
##  $ CRA_ZERO            : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ CRA_DE_EVASAO       : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 2 1 1 1 1 ...
##  $ TRANCAMENTO         : Factor w/ 1 level "FALSE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ POS_REUNI           : Factor w/ 1 level "TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ C1                  : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 2 1 1 1 1 ...
##  $ C2                  : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ C3                  : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ C4                  : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ C5                  : Factor w/ 2 levels "FALSE","TRUE": 1 2 1 2 1 2 2 2 2 1 ...
##  $ C6                  : Factor w/ 2 levels "FALSE","TRUE": 2 2 2 2 2 2 2 2 2 2 ...
##  $ FALSO_FERA          : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
df_test <- alunos_teste[c("MATRICULA","CURSO","CRA","CRA_ZERO","CRA_DE_EVASAO","TEM_APROVACAO", "TEM_REPROV_POR_NOTA","TEM_REPROV_POR_FALTA","TRANCAMENTO", "POS_REUNI","FALSO_FERA","C1","C2","C3","C4","C5","C6")]



df_teste <- replace(df_test, is.na(df_test), FALSE)
str(df_test)
## 'data.frame':    123 obs. of  17 variables:
##  $ MATRICULA           : int  1565650 8696570 9822368 11928230 35551592 38116320 38449794 51710560 58841481 59967279 ...
##  $ CURSO               : Factor w/ 2 levels "ENFERMAGEM - D",..: 2 1 2 2 2 1 2 2 1 2 ...
##  $ CRA                 : num  3.36 8.34 5 7.81 4.37 1.73 9.21 9.41 7.64 6.29 ...
##  $ CRA_ZERO            : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ CRA_DE_EVASAO       : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 2 1 1 1 1 ...
##  $ TEM_APROVACAO       : Factor w/ 2 levels "FALSE","TRUE": 2 2 2 2 2 2 2 2 2 2 ...
##  $ TEM_REPROV_POR_NOTA : Factor w/ 2 levels "FALSE","TRUE": 2 1 2 1 2 1 1 1 1 2 ...
##  $ TEM_REPROV_POR_FALTA: Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 2 1 1 1 1 ...
##  $ TRANCAMENTO         : Factor w/ 1 level "FALSE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ POS_REUNI           : Factor w/ 1 level "TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ FALSO_FERA          : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ C1                  : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 2 1 1 1 1 ...
##  $ C2                  : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ C3                  : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ C4                  : Factor w/ 2 levels "FALSE","TRUE": 1 1 1 1 1 1 1 1 1 1 ...
##  $ C5                  : Factor w/ 2 levels "FALSE","TRUE": 1 2 1 2 1 2 2 2 2 1 ...
##  $ C6                  : Factor w/ 2 levels "FALSE","TRUE": 2 2 2 2 2 2 2 2 2 2 ...

Etapa de predição

#Sys.setlocale(locale = "C") #Ajuste para o C5.0
knn_predict <- predict(knnFit,newdata = df_teste)
summary(knn_predict)
##   0   1 
## 116   7
#Sys.setlocale(locale = "en_IE.UTF-8")

Submissão

pred <- cbind(df_teste["MATRICULA"], COD_EVASAO=knn_predict)
#Alternativa para modelo sem utilizar MATRICULA
#pred <- cbind(alunos_test_summarised["MATRICULA"], COD_EVASAO=prediction)
ids <- test_first_round_kaggle[c("ID","MATRICULA")]

submissao <- left_join(x=ids, y=pred, by="MATRICULA")
submissao <- submissao[c("ID", "COD_EVASAO")]
write.table(submissao, file="submissao-v10 (knn).csv", row.names=FALSE, sep=",")

Conclusão

Após a submissão da predição na competição do Kaggle, o resultado obtido para o modelo KNN foi bem inferior ao mais bem rankeado anteriormente, contradizendo os resultados obtidos nos testes deste relatório. Há várias hipóteses que podem ser consideradas para explicar o ocorrido. A primeira diz respeito ao balanceamento dos dados, pois é possível que se tenha perdido informação ao realizar o balanceamento, fazendo com que as variáveis derivadas dos dados de treino percam força e façam o modelo errar mais. Outro ponto que pode ser considerado é em relação ao modelo mais adequado para este problema não ser o de vizinhos mais próximos, onde mesmo com o modelo obtendo bons resultados nos testes pré-submissão, a mecânica aplicada no algoritmo pode não funcionar tão bem para este problema em específico.