Primeiramente vamos importar as bibliotecas necessárias para esse script ser executado.
library(dplyr)
library(reshape2)
library(GGally)
library(ggplot2)
library(corrplot)
library(caret)
Os seguintes passos serão seguidos nesse exercício:
Baixe os dados de treino e teste.
Calcule o CRA dos alunos com base no script de preprocessamento (Links para um site externo) do lab anterior.
Usando todas as variáveis disponíveis (disciplinas do primeiro e segundo período), use validação cruzada (nos dados de treino) para tunar um modelo de regressão Ridge.
Mesmo que o item acima mas usando um modelo de regressão Lasso.
Mesmo que o item acima mas usando um modelo de regressão Linear sem regularização.
Re-treine o melhor modelo (dessa vez nos dados de treino sem validação cruzada) e reporte o RMSE no teste.
Compare os modelos nos dados de teste em termos de RMSE.
Quais as variáveis mais importantes segundo o modelo de regressão Lasso? Alguma variável foi descartada? Quais?
Use o modelo treinado em 6 e aplique nos dados de teste que vamos disponibilizar.
Crie novos atributos a partir dos existentes para tentar melhorar o seu modelo.
Vamos baixar os dados e verificar como estes estão organizados.
graduados.treino = read.csv("~/graduados_treino.csv")
graduados.teste = read.csv("~/graduados_teste.csv")
# Renomeando colunas
nomes.colunas <- c("matricula", "ano_de_termino", "semestre", "codigo_disciplina", "disciplina", "creditos", "media")
colnames(graduados.treino) <- nomes.colunas
colnames(graduados.teste) <- nomes.colunas
# Retiramos as linhas que tem NA na media
graduados.treino.clean <- graduados.treino %>% na.omit()
graduados.teste.clean <- graduados.teste %>% na.omit()
summary(graduados.treino)
## matricula ano_de_termino semestre
## 85974cb8795c635a3f2ded1660219726: 73 Min. :2002 Min. :1.000
## 355e8d7d1c8679dcb0b09b9a3ace29df: 68 1st Qu.:2005 1st Qu.:1.000
## 51a0c689765218e52f0ad96f906049fb: 68 Median :2008 Median :1.000
## 9ca8e219a6912f807324ac8de21d7244: 68 Mean :2008 Mean :1.499
## c112f9a66e587fcf4ac8ff999b64c306: 68 3rd Qu.:2011 3rd Qu.:2.000
## daaa919fb9a1952e1b6df8324c45c38d: 65 Max. :2013 Max. :2.000
## (Other) :22396
## codigo_disciplina disciplina creditos
## Min. :1108089 Probabilidade e Estatistica : 663 Min. :2.000
## 1st Qu.:1305220 Análise e Técnica de Algoritmos: 662 1st Qu.:4.000
## Median :1411176 Fundamentos de Física Clássica : 647 Median :4.000
## Mean :1342914 Métodos Estatisticos : 622 Mean :3.863
## 3rd Qu.:1411187 Compiladores : 595 3rd Qu.:4.000
## Max. :1411197 Sistemas Operacionais : 565 Max. :6.000
## (Other) :19052
## media
## Min. : 0.000
## 1st Qu.: 6.600
## Median : 7.600
## Mean : 7.277
## 3rd Qu.: 8.500
## Max. :10.000
## NA's :492
summary(graduados.teste)
## matricula ano_de_termino semestre
## 3b3c1d5f7a47df614511c13e0c2a7f5a: 65 Min. :2014 Min. :1.000
## 1298de387b2af5489ce432fe854ae0f7: 55 1st Qu.:2014 1st Qu.:1.000
## ee3d9477b624b8ccdfb43c60e7b5f216: 55 Median :2014 Median :2.000
## dc7cc6fc23a869f2f8aff00f379a506d: 51 Mean :2014 Mean :1.595
## 7ef43ad9fbfe0b9703daf664cf938650: 48 3rd Qu.:2014 3rd Qu.:2.000
## f5d50bbc167b67b1a957be226455cf35: 48 Max. :2014 Max. :2.000
## (Other) :1412
## codigo_disciplina disciplina
## Min. :1108089 Probabilidade e Estatistica : 57
## 1st Qu.:1305219 Cálculo Diferencial e Integral I : 46
## Median :1411175 Compiladores : 45
## Mean :1336395 Banco de Dados II : 43
## 3rd Qu.:1411187 Métodos Estatisticos : 43
## Max. :1411197 Cálculo Diferencial e Integral II: 42
## (Other) :1458
## creditos media
## Min. :2.000 Min. : 0.000
## 1st Qu.:4.000 1st Qu.: 6.100
## Median :4.000 Median : 7.200
## Mean :3.875 Mean : 7.063
## 3rd Qu.:4.000 3rd Qu.: 8.200
## Max. :6.000 Max. :10.000
## NA's :33
As colunas foram renomeadas para ter nomes mais descritivos, assim ambos os data frames estão organizados da seguinte forma:
# Cálculo do CRA
graduados.teste.cra <- graduados.teste.clean %>%
group_by(matricula) %>%
mutate(cra.contrib = media*creditos) %>%
summarise(cra = sum(cra.contrib)/sum(creditos))
graduados.treino.cra <- graduados.treino.clean %>%
group_by(matricula) %>%
mutate(cra.contrib = media*creditos) %>%
summarise(cra = sum(cra.contrib)/sum(creditos))
# Selecionando apenas a nota final como media de um aluno em uma certa disciplina
# Renomando colunas da disciplina para um padrão mais fácil de se trabalhar
# Trocando linhas por colunas e adicionando coluna do CRA
graduados.teste.model.input <- graduados.teste.clean %>%
group_by(matricula, disciplina) %>%
filter(media == max(media))%>%
ungroup() %>%
select(matricula, disciplina, media) %>%
mutate(disciplina = as.factor(gsub(" ", ".", disciplina))) %>%
dcast(matricula ~ disciplina, mean) %>%
merge(graduados.teste.cra)
## Using media as value column: use value.var to override.
graduados.treino.model.input <- graduados.treino.clean %>%
group_by(matricula, disciplina) %>%
filter(media == max(media))%>%
ungroup() %>%
select(matricula, disciplina, media) %>%
mutate(disciplina = as.factor(gsub(" ", ".", disciplina))) %>%
dcast(matricula ~ disciplina, mean) %>%
merge(graduados.treino.cra)
## Using media as value column: use value.var to override.
# Selecionado apenas disciplinas do primeiro período
primeiro.periodo.teste <- graduados.teste.model.input %>% select(matricula, cra, Cálculo.Diferencial.e.Integral.I, Álgebra.Vetorial.e.Geometria.Analítica, Leitura.e.Produção.de.Textos, Programação.I, Introdução.à.Computação, Laboratório.de.Programação.I)
primeiro.periodo.treino <- graduados.treino.model.input %>% select(matricula, cra, Cálculo.Diferencial.e.Integral.I, Álgebra.Vetorial.e.Geometria.Analítica, Leitura.e.Produção.de.Textos, Programação.I, Introdução.à.Computação, Laboratório.de.Programação.I)
colnames(primeiro.periodo.teste) <- c("matricula", "cra", "Cálculo1", "Vetorial", "LPT", "P1", "IC", "LP1")
colnames(primeiro.periodo.treino) <- c("matricula", "cra", "Cálculo1", "Vetorial", "LPT", "P1", "IC", "LP1")
segundo.periodo.teste <- graduados.teste.model.input %>%
select(matricula, cra, Cálculo.Diferencial.e.Integral.II, Matemática.Discreta, Programação.II, Teoria.dos.Grafos, Fundamentos.de.Física.Clássica, Laboratório.de.Programação.II)
segundo.periodo.treino <- graduados.treino.model.input %>%
select(matricula, cra, Cálculo.Diferencial.e.Integral.II, Matemática.Discreta, Programação.II, Teoria.dos.Grafos, Fundamentos.de.Física.Clássica, Laboratório.de.Programação.II)
colnames(segundo.periodo.teste) <- c("matricula", "cra", "Cálculo2", "Discreta", "P2", "Grafos", "Fís.Clássica", "LP2")
colnames(segundo.periodo.treino) <- c("matricula", "cra", "Cálculo2", "Discreta", "P2", "Grafos", "Fís.Clássica", "LP2")
dados.teste <- merge(primeiro.periodo.teste, segundo.periodo.teste) %>% na.omit()
dados.treino <- merge(primeiro.periodo.treino, segundo.periodo.treino) %>% na.omit()
Antes de realizar a validação cruzada, segue uma breve discussão do porquê utiliza-lá e como funciona o modelo Ridge.
Nossa preocupação não é mais modelar os dados e sim prever resultados. Assim apenas usar as mesmas observações, utilizadas para estimar o modelo, para validar sua acurácia não é mais suficiente. Com esse tipo de teste apenas sabemos como o modelo se comporta para os dados já estudados, mas e para novas observações?
Na verdade queremos analisar nosso modelo através do erro de generalização que é a estimativa do erro sobre todos os pontos de dados possíveis, porém a obtenção de tal erro é normalmente impraticável devido ao volume de dados existentes.
Assim, parar melhor avaliar a “performance preditiva” dos modelos devemos usar um outro conjunto de dados independentes (dados de teste) dos utilizados para gerar o modelo (dados de treino), de modo que o modelo passa a ser “avaliado” agora pelos dados de teste, onde o modelo com menor erro nos dados de teste é o “melhor”. Essa é a ideia básica do método chamado validação cruzada.
Existem vários métodos de validação cruzada, como por exemplo: holdout, k-fold, leave-one-out. Destacarei apenas o k-fold que será utilizado nesse exercício (mais sobre os outros métodos pode ser lido neste link).
Na validação cruzada k-fold ocorrerá 2 particionamentos nos dados, assim haverá dados de: treino e teste. Os dados de treino são usados para estimar o modelo, já os dados de teste não são usados de nenhuma forma para gerar o modelo, são utilizados apenas para verificação da acurácia deste.
No k-fold os dados de treino são na verdade particonados em k conjuntos chamados de folders, a cada iteração um dos k conjuntos é escolhido como conjunto de validação e será feito o “merge” dos demais k-1 conjuntos para serem usados como treino (e portanto são usados para gerar o modelo), ao final dessa interação é calculado o erro em relação ao bloco de validação. Ao final é calculada a média dos erros de cada interação.
A vantagem desse modelo é que não importa tanto como os dados são divididos, cada dado será usado uma única vez como validação. A desvantagem é que na medida que k aumenta, aumenta-se a precisão mas também aumenta-se a complexidade (tempo) das operações.
A regressão Ridge é uma regressão que além de levar em conta o erro do treino também leva em conta a medida da magnitude, buscando assim evitar o overffiting (uma das características do overffiting são altos valores de magnitude) e levar em conta o trade-off bias e variância atráves do lambda. Quanto maior o lambda -> bias grande, baixa variância; quando menor o lambda -> bias pequeno, alta variância.
Podemos utilizar a validação cruzada para “tunar” (melhor ajustar os parâmetros) o modelo. E foi exatamente isso que fizemos, segue o resultado abaixo.
# Selecionando k-folder cross validation com 5 repetições e 5 folders
ctrl <- trainControl(method = "repeatedcv", repeats = 5, number = 5)
lambda.grid <- expand.grid(lambda = seq(0, 2, by=0.05))
ridge <- train(cra ~ ., data = dados.treino %>% select(-matricula),
method='ridge',
tuneGrid = lambda.grid, # lambdas testados
trControl = ctrl, # k-folder,
metric='RMSE',
preProcess=c('scale', 'center') # mais sobre isso em [2]
)
## Loading required package: elasticnet
## Loading required package: lars
## Loaded lars 1.2
ridge
## Ridge Regression
##
## 88 samples
## 12 predictors
##
## Pre-processing: scaled (12), centered (12)
## Resampling: Cross-Validated (5 fold, repeated 5 times)
## Summary of sample sizes: 69, 69, 72, 71, 71, 70, ...
## Resampling results across tuning parameters:
##
## lambda RMSE Rsquared
## 0.00 0.5816224 0.5538690
## 0.05 0.5753527 0.5669310
## 0.10 0.5724723 0.5759537
## 0.15 0.5718727 0.5825734
## 0.20 0.5730034 0.5876163
## 0.25 0.5755339 0.5915599
## 0.30 0.5792403 0.5947043
## 0.35 0.5839570 0.5972494
## 0.40 0.5895536 0.5993344
## 0.45 0.5959227 0.6010592
## 0.50 0.6029729 0.6024976
## 0.55 0.6106247 0.6037052
## 0.60 0.6188078 0.6047248
## 0.65 0.6274594 0.6055898
## 0.70 0.6365229 0.6063264
## 0.75 0.6459475 0.6069557
## 0.80 0.6556869 0.6074948
## 0.85 0.6656993 0.6079573
## 0.90 0.6759469 0.6083549
## 0.95 0.6863952 0.6086968
## 1.00 0.6970134 0.6089909
## 1.05 0.7077732 0.6092439
## 1.10 0.7186494 0.6094611
## 1.15 0.7296190 0.6096474
## 1.20 0.7406615 0.6098068
## 1.25 0.7517583 0.6099426
## 1.30 0.7628927 0.6100578
## 1.35 0.7740498 0.6101550
## 1.40 0.7852161 0.6102362
## 1.45 0.7963797 0.6103035
## 1.50 0.8075298 0.6103584
## 1.55 0.8186568 0.6104024
## 1.60 0.8297521 0.6104367
## 1.65 0.8408081 0.6104626
## 1.70 0.8518180 0.6104808
## 1.75 0.8627758 0.6104923
## 1.80 0.8736762 0.6104979
## 1.85 0.8845145 0.6104982
## 1.90 0.8952865 0.6104938
## 1.95 0.9059885 0.6104852
## 2.00 0.9166176 0.6104729
##
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was lambda = 0.15.
plot(ridge, xlab = "Lambda", ylab = "RMSE")
Assim, o melhor valor para o lambda entre os valores testados foi ~0.15 levando em conta o RMSE como métrica para definir o “melhor modelo”, com erro de ~0.57. O maior R² encontrado foi de ~0.61 que é bastante razoável considerando um modelo puramente linear. Um RMSE de ~0.57 significa que em média estamos errando o CRA de um aluno em ~0.57 para cima ou para baixo o que é um resultado considerado bom levando em conta a simplicidade do modelo.
ridge.pred <- predict(ridge, dados.teste %>% select(-matricula) %>% select(-cra))
ridge.df <- data.frame(pred = ridge.pred, obs = dados.teste$cra)
ridge.df$model <- "Ridge"
ridge.round <- round(defaultSummary(ridge.df), digits = 3)
ridge.round
## RMSE Rsquared
## 0.400 0.666
O modelo apresentando RMSE mais baixo que no treino (~0.4) e R² mais alto (~0.66). Tal resultado é bastante inesperado e indica que o modelo se sai melhor nos dados de teste que nos dados de treino. E dados os valores prediz relativamente bem o CRA para novos dados.
Antes de iniciar a análise prática segue uma breve explicação sobre a regressão utilizando Lasso e as diferenças dessa regressão para o método Ridge.
Lasso (least absolute shrinkage and selection operator) é um método de regressão que faz tanto seleção de variáveis como regularização buscando aumentar a acurácia da previsão e tornar o modelo mais facilmente interpretável.
O Lasso utiliza um modo diferente de “penalização” do aumento dos coeficientes, em vez de usar a soma de quadrados como o Ridge ele utiliza a soma dos valores absolutos de valores. De modo que no Ridge os paramêtros podem ser penalizados, mas nunca são zerados de fato, já no Lasso isso pode acontecer, ou seja, uma variável pode ser retirada do modelo.
Porém não há um melhor algoritmo em geral, o ideal é testar as técnicas e utilizar aquela quer gerar um modelo que melhor se adequa aos dados.
lasso <- train(cra ~ ., data = dados.treino %>% select(-matricula),
method='lasso',
trControl = ctrl, # k-folder
metric='RMSE',
tuneLength = 100, # numero de comb. de parametros para serem testadas
preProcess=c('scale', 'center') # mais sobre isso em [2]
)
lasso
## The lasso
##
## 88 samples
## 12 predictors
##
## Pre-processing: scaled (12), centered (12)
## Resampling: Cross-Validated (5 fold, repeated 5 times)
## Summary of sample sizes: 70, 69, 71, 70, 72, 70, ...
## Resampling results across tuning parameters:
##
## fraction RMSE Rsquared
## 0.1000000 0.7688730 0.5047519
## 0.1080808 0.7634809 0.5087798
## 0.1161616 0.7581268 0.5122238
## 0.1242424 0.7527774 0.5155949
## 0.1323232 0.7474515 0.5190262
## 0.1404040 0.7421243 0.5230055
## 0.1484848 0.7368552 0.5264608
## 0.1565657 0.7316455 0.5294781
## 0.1646465 0.7264494 0.5323943
## 0.1727273 0.7212180 0.5356577
## 0.1808081 0.7159722 0.5391416
## 0.1888889 0.7107365 0.5427776
## 0.1969697 0.7054600 0.5465829
## 0.2050505 0.7002562 0.5501241
## 0.2131313 0.6951630 0.5533328
## 0.2212121 0.6901219 0.5563393
## 0.2292929 0.6851416 0.5591536
## 0.2373737 0.6802649 0.5617033
## 0.2454545 0.6754582 0.5640431
## 0.2535354 0.6707232 0.5661936
## 0.2616162 0.6660457 0.5683621
## 0.2696970 0.6614281 0.5704507
## 0.2777778 0.6569026 0.5723596
## 0.2858586 0.6524264 0.5742947
## 0.2939394 0.6480357 0.5760969
## 0.3020202 0.6437243 0.5777664
## 0.3101010 0.6395008 0.5793315
## 0.3181818 0.6353902 0.5807833
## 0.3262626 0.6313818 0.5821369
## 0.3343434 0.6274550 0.5834051
## 0.3424242 0.6236214 0.5846218
## 0.3505051 0.6198739 0.5857771
## 0.3585859 0.6162195 0.5868620
## 0.3666667 0.6126568 0.5878951
## 0.3747475 0.6091375 0.5889435
## 0.3828283 0.6056927 0.5899420
## 0.3909091 0.6023447 0.5908989
## 0.3989899 0.5990874 0.5918316
## 0.4070707 0.5959216 0.5928015
## 0.4151515 0.5928241 0.5937878
## 0.4232323 0.5898082 0.5947404
## 0.4313131 0.5868726 0.5956492
## 0.4393939 0.5840283 0.5964915
## 0.4474747 0.5812248 0.5974119
## 0.4555556 0.5784982 0.5983201
## 0.4636364 0.5758557 0.5992230
## 0.4717172 0.5733106 0.6001236
## 0.4797980 0.5709040 0.6008504
## 0.4878788 0.5686156 0.6015034
## 0.4959596 0.5664369 0.6021129
## 0.5040404 0.5644324 0.6025856
## 0.5121212 0.5625464 0.6029869
## 0.5202020 0.5607543 0.6033744
## 0.5282828 0.5590692 0.6036959
## 0.5363636 0.5575078 0.6039724
## 0.5444444 0.5560865 0.6042128
## 0.5525253 0.5547637 0.6044103
## 0.5606061 0.5536373 0.6044359
## 0.5686869 0.5527537 0.6041709
## 0.5767677 0.5521329 0.6035949
## 0.5848485 0.5516530 0.6029592
## 0.5929293 0.5512550 0.6022811
## 0.6010101 0.5509295 0.6015513
## 0.6090909 0.5506583 0.6007724
## 0.6171717 0.5504470 0.6000181
## 0.6252525 0.5503163 0.5992372
## 0.6333333 0.5502921 0.5984320
## 0.6414141 0.5503759 0.5975792
## 0.6494949 0.5504161 0.5968333
## 0.6575758 0.5505358 0.5960248
## 0.6656566 0.5507175 0.5951817
## 0.6737374 0.5510468 0.5942115
## 0.6818182 0.5514988 0.5931617
## 0.6898990 0.5520152 0.5920594
## 0.6979798 0.5526208 0.5909527
## 0.7060606 0.5532623 0.5898388
## 0.7141414 0.5539001 0.5887880
## 0.7222222 0.5545796 0.5877039
## 0.7303030 0.5553489 0.5866083
## 0.7383838 0.5561212 0.5855760
## 0.7464646 0.5569311 0.5845797
## 0.7545455 0.5577268 0.5835789
## 0.7626263 0.5585043 0.5824901
## 0.7707071 0.5593000 0.5813450
## 0.7787879 0.5601917 0.5801063
## 0.7868687 0.5611227 0.5788477
## 0.7949495 0.5620376 0.5776358
## 0.8030303 0.5629746 0.5763949
## 0.8111111 0.5639374 0.5751365
## 0.8191919 0.5648747 0.5739013
## 0.8272727 0.5657710 0.5727164
## 0.8353535 0.5666705 0.5715496
## 0.8434343 0.5675552 0.5704505
## 0.8515152 0.5684737 0.5693693
## 0.8595960 0.5694462 0.5682582
## 0.8676768 0.5704582 0.5671173
## 0.8757576 0.5714442 0.5659931
## 0.8838384 0.5724477 0.5648492
## 0.8919192 0.5734205 0.5637527
## 0.9000000 0.5744043 0.5626481
##
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was fraction = 0.6333333.
plot(lasso, xlab = "Lambda", ylab = "RMSE")
Assim, o melhor valor para o lambda dos 100 testados foi ~0.63 levando em conta o RMSE como métrica para definir o “melhor modelo”, com erro de ~0.55 e R² de ~0.59 que é razoável considerando um modelo puramente linear. Um resultado levemente melhor que o Ridge, porém ainda sim bastante similar.
lasso.pred <- predict(lasso, dados.teste %>% select(-matricula) %>% select(-cra))
lasso.df <- data.frame(pred = lasso.pred, obs = dados.teste$cra)
lasso.df$model <- "Lasso"
lasso.round <- round(defaultSummary(lasso.df), digits = 3)
lasso.round
## RMSE Rsquared
## 0.409 0.671
Esse modelo também apresenta resultados similares ao Ridge nos dados de teste, apresentando RMSE (~0.41) inferior ao do treino, e levemente superior ao do Ridge e em relação ao R² este também é um pouco mais alto (~0.67) que no treino e também levemente superior ao R² do Ridge. De acordo com os resultados acima podemos dizer que o Ridge se saiu levemente melhor que o Lasso para prever o CRA, porém a diferença é bastante pequena então de certo modo não é errado dizer que ambos tiveram resultados equiparáveis.
lm <- train(cra ~ ., data = dados.treino %>% select(-matricula),
method='lm',
trControl = ctrl, # k-folder,
metric='RMSE',
preProcess=c('scale', 'center') # mais sobre isso em [2]
)
lm
## Linear Regression
##
## 88 samples
## 12 predictors
##
## Pre-processing: scaled (12), centered (12)
## Resampling: Cross-Validated (5 fold, repeated 5 times)
## Summary of sample sizes: 70, 71, 70, 70, 71, 71, ...
## Resampling results:
##
## RMSE Rsquared
## 0.5636736 0.5953064
##
## Tuning parameter 'intercept' was held constant at a value of TRUE
##
Assim, utilizando apenas a regressão linear obtivesse um RMSE de ~0.56 e R² de ~0.6, resultado esse bastante similar aos resultados do Ridge e Lasso.
lm.pred <- predict(lm, dados.teste %>% select(-matricula) %>% select(-cra))
lm.df <- data.frame(pred = lm.pred, obs = dados.teste$cra)
lm.df$model <- "Linear"
lm.round <- round(defaultSummary(lm.df), digits = 3)
lm.round
## RMSE Rsquared
## 0.408 0.644
O modelo linear sem regularização se saiu aproximadamente tão bem quanto os modelos analisados anteriormente apresentando RMSE de ~0.4 e R² de ~0.64.
Tanto o Ridge quanto o Lasso apresentaram resultados similares, então como dito anteriormente não há um modelo vencedor aparente. Assim, utilizarei o método Ridge sem vlidação cruzada para comparar com o Ridge com validação cruzada.
ridge.no.cv <- train(cra ~ ., data = dados.treino %>% select(-matricula),
method='ridge',
tuneGrid = lambda.grid,
metric='RMSE',
preProcess=c('scale', 'center'))
ridge.no.cv
## Ridge Regression
##
## 88 samples
## 12 predictors
##
## Pre-processing: scaled (12), centered (12)
## Resampling: Bootstrapped (25 reps)
## Summary of sample sizes: 88, 88, 88, 88, 88, 88, ...
## Resampling results across tuning parameters:
##
## lambda RMSE Rsquared
## 0.00 0.6345403 0.5089187
## 0.05 0.6221812 0.5283120
## 0.10 0.6178931 0.5402898
## 0.15 0.6176060 0.5486890
## 0.20 0.6198929 0.5549505
## 0.25 0.6240482 0.5597926
## 0.30 0.6296528 0.5636320
## 0.35 0.6364262 0.5667329
## 0.40 0.6441651 0.5692738
## 0.45 0.6527134 0.5713801
## 0.50 0.6619463 0.5731430
## 0.55 0.6717609 0.5746303
## 0.60 0.6820706 0.5758937
## 0.65 0.6928015 0.5769734
## 0.70 0.7038897 0.5779007
## 0.75 0.7152795 0.5787007
## 0.80 0.7269224 0.5793935
## 0.85 0.7387757 0.5799954
## 0.90 0.7508016 0.5805198
## 0.95 0.7629669 0.5809778
## 1.00 0.7752423 0.5813787
## 1.05 0.7876016 0.5817301
## 1.10 0.8000218 0.5820385
## 1.15 0.8124825 0.5823095
## 1.20 0.8249655 0.5825477
## 1.25 0.8374548 0.5827572
## 1.30 0.8499362 0.5829413
## 1.35 0.8623972 0.5831032
## 1.40 0.8748265 0.5832452
## 1.45 0.8872144 0.5833698
## 1.50 0.8995521 0.5834788
## 1.55 0.9118321 0.5835739
## 1.60 0.9240475 0.5836567
## 1.65 0.9361926 0.5837284
## 1.70 0.9482621 0.5837902
## 1.75 0.9602516 0.5838432
## 1.80 0.9721571 0.5838883
## 1.85 0.9839752 0.5839262
## 1.90 0.9957031 0.5839576
## 1.95 1.0073383 0.5839833
## 2.00 1.0188787 0.5840038
##
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was lambda = 0.15.
plot(ridge.no.cv, xlab = "Lambda", ylab = "RMSE")
O menor RMSE encontrado foi com o lambda ~0.15, com um RMSE de ~0.61 e R² de ~0.54, resultados bastante similares ao do Ridge e Lasso utilizando validação cruzada.
ridge.no.cv.pred <- predict(ridge.no.cv, dados.teste %>% select(-matricula) %>% select(-cra))
ridge.no.cv.df <- data.frame(pred = ridge.no.cv.pred, obs = dados.teste$cra)
ridge.no.cv.df$model <- "Ridge sem CV"
ridge.no.cv.round <- round(defaultSummary(ridge.no.cv.df), digits = 3)
ridge.no.cv.round
## RMSE Rsquared
## 0.400 0.666
O ridge sem validação cruzada apresentou R² e RMSE basicamente iguais aos do Ridge com validação cruzada (RMSE levemente maior e R² também um pouco maior), tal resultado mostra que a validação cruzada pode não estar ajudando tanto a escolher um modelo com maior acurácia nas previsões.
Todos os modelos analisados apresentaram resultados igualmente satisfatórios, os resultados foram tão similares que não faz muito sentido definir um “vencedor”.
comparacao <- rbind(ridge.df, lasso.df, lm.df, ridge.no.cv.df)
ggplot(comparacao, aes(x = pred, y = obs)) +
geom_point(alpha = 0.5, position = position_jitter(width=0.2)) +
facet_grid(. ~ model) +
geom_abline(color="red")
ridge.round
## RMSE Rsquared
## 0.400 0.666
lasso.round
## RMSE Rsquared
## 0.409 0.671
lm.round
## RMSE Rsquared
## 0.408 0.644
ridge.no.cv.round
## RMSE Rsquared
## 0.400 0.666
Resultados tão similares podem significar que provavelmente o uso de regularização não está fazendo uma grande diferença para geração dos modelos, e que o modelo linear convencional não está “dando” overfitting. Tal resultado é de certa forma esperado considerando o contexto em que estamos trabalhando em que remover variáveis do modelo (no nosso caso disciplinas) realmente não deve contribuir muito para um melhor modelo.
Além disso é válido enfatizar que as variáveis utilizadas são apenas as disciplinas no primeiro e segundo período, e sabemos apenas essas variáveis não são responsáveis pelo desempenho final do aluno, assim não é surpresa que o modelo não apresentar resultados muito significativos.
O modelo lasso define uma importância para uma variável de acordo com “a dificuldade” (maior lâmbda) para “zerar”/desconsiderar tal variável do modelo associando um valor de [0, 100] a essa variável, quanto maior mais importante a variável é para o modelo.
varImp(lasso)
## loess r-squared variable importance
##
## Overall
## P2 100.000
## Grafos 98.848
## Discreta 97.775
## IC 62.396
## Vetorial 57.294
## P1 45.759
## LP1 40.452
## LP2 39.467
## Fís.Clássica 30.331
## LPT 13.382
## Cálculo1 7.273
## Cálculo2 0.000
ggplot(varImp(lasso)) + geom_bar(stat="identity", fill="#56B4E9", colour="black")
Cálculo 2 é sem dúvida a disciplina menos importante seguida por Cálculo 1 e LPT, as próximas disciplinas têm um nível de importância relativamente próximo, onde se destacam pelo nível de importância P2, Grafos e Discreta que são consideras extremamente importantes para o modelo (~100).
Além disso a única variável retirada do modelo foi Cálculo 2.
Como dito na sessão anterior todos os modelos apresentam resultados similares então vamos utilizar o Lasso + CV para verificar seus resultados nos dados de teste final.
treino.final <- read.csv("~/train.csv") %>% na.omit()
teste.final <- read.csv("~/test.csv")
# consideraremos NAs = 0
teste.final[is.na(teste.final)] <- 0
colnames(teste.final) <- c("matricula", "Cálculo1", "Vetorial", "LPT", "P1", "IC", "LP1", "Cálculo2", "Discreta", "P2", "Grafos", "Fís.Clássica", "LP2")
colnames(treino.final) <- c("matricula", "Cálculo1", "Vetorial", "LPT", "P1", "IC", "LP1", "Cálculo2", "Discreta", "P2", "Grafos", "Fís.Clássica", "LP2", "cra")
lasso.final <- train(cra ~ ., data = treino.final %>% select(-matricula),
method='lasso',
trControl = ctrl, # k-folder
metric='RMSE',
tuneLength = 100, # numero de comb. de parametros para serem testadas
preProcess=c('scale', 'center') # mais sobre isso em [2]
)
lasso.final.pred <- predict(lasso.final, teste.final %>% select(-matricula))
df.final <- data.frame(matricula = teste.final$matricula, cra = lasso.final.pred)
write.csv(df.final, "test.csv", row.names = F)
O Lasso apresentou um RMSE de 0.46782 nos dados de testes finais (utilizados pelo Kaggle) que é um valor razoável. Tentaremos diminuir esse RMSE na próxima sessão.
Como todos os modelos utilizados nas sessões anteriores apresentaram resultados bastante similares foi escolhido utilizar Lasso + validação cruzada para gerar os novos modelos já que foi mais recomendado pelos monitores e pela literatura. Além disso é possível que novos modelos sejam testados.
Para a tentativa 1 irei utilizar o modelo que consegui um melhor RMSE na parte 2, assim podemos verificar se esse modelo também é bom para a previsão de CRA, além da modelagem apenas.
Esse modelo usa as seguintes variáveis:
df.t1 <- dados.treino %>% select(Cálculo1, Vetorial, LPT, LP1, Discreta, Grafos, P2, matricula, cra) %>%
na.omit()
lasso.t1 <- train(cra ~ ., data = df.t1 %>% select(-matricula),
method='lasso',
trControl = ctrl, # k-folder
metric='RMSE',
tuneLength = 100, # numero de comb. de parametros para serem testadas
preProcess=c('scale', 'center') # mais sobre isso em [2]
)
pred.t1 <- predict(lasso.t1, dados.teste %>% select(-matricula) %>% select(-cra))
df.pred.t1 <- data.frame(pred = pred.t1, obs = dados.teste$cra)
df.pred.t1.round <- round(defaultSummary(df.pred.t1), digits = 3)
df.pred.t1.round
## RMSE Rsquared
## 0.420 0.644
Aparentemente o modelo não se saiu tão bem para prever os dados, então continuaremos tentando com outras estratégias.
Para a tentativa 2 irei utilizar apenas as variáveis mais representativas encontradas pelo modelo lasso. Essas são:
df.t1 <- dados.treino %>% select(IC, Vetorial, Discreta, Grafos, P2, matricula, cra) %>%
na.omit()
lasso.t1 <- train(cra ~ ., data = df.t1 %>% select(-matricula),
method='lasso',
trControl = ctrl, # k-folder
metric='RMSE',
tuneLength = 100, # numero de comb. de parametros para serem testadas
preProcess=c('scale', 'center') # mais sobre isso em [2]
)
pred.t1 <- predict(lasso.t1, dados.teste %>% select(-matricula) %>% select(-cra))
df.pred.t1 <- data.frame(pred = pred.t1, obs = dados.teste$cra)
df.pred.t1.round <- round(defaultSummary(df.pred.t1), digits = 3)
df.pred.t1.round
## RMSE Rsquared
## 0.392 0.673
t1 <- predict(lasso.t1, teste.final %>% select(-matricula))
df.final <- data.frame(matricula = teste.final$matricula, cra = t1)
write.csv(df.final, "test10.csv", row.names = F)
Aparentemente o modelo se saiu um pouco melhor para a predição de dados, vamos verificar como se sai nos dados de teste no Kaggle. Infelizmente o modelo obteve um RMSE 0.48054 nos testes, não demonstrando melhora.
Para a tentativa 3 irei utilizar as variáveis mais importantes para o Lasso e adicionar variáveis quadráticas de modo a deixar o modelo mais “complexo” e além disso disciplinas de laboratório foram multiplicadas, assim como P1 e LP1 que são bastante similares (observamos isso na parte 2) e Vetorial e Cálculo 1.
Desse modo foi encontrado o seguite modelo (a partir de alguns testes manuais):
Discreta² + Grafos² + IC + P2 + LP1 * LP2 + Vetorial * Cálculo1 + P1 * LP1
lasso.t1 <- train(cra ~ poly(Discreta, 2) + poly(Grafos, 2) + IC + P2 + LP1 * LP2 + Vetorial * Cálculo1 + P1 * LP1, data = dados.treino %>% select(-matricula),
method='lasso',
trControl = ctrl, # k-folder
metric='RMSE',
tuneLength = 100, # numero de comb. de parametros para serem testadas
preProcess=c('scale', 'center') # mais sobre isso em [2]
)
t1 <- predict(lasso.t1, teste.final %>% select(-matricula))
df.final <- data.frame(matricula = teste.final$matricula, cra = t1)
write.csv(df.final, "test10.csv", row.names = F)
Esse modelo se saiu melhor que todos os já testados, apresentando RMSE de ~0.44 no Kaggle.
Para a tentativa 4, continuaremos usando o modelo da tentativa 3 e adicionaremos a média de todas as disciplinas como variável.
dados.treino$media <- rowMeans(dados.treino %>% select(-matricula, -cra))
dados.teste$media <- rowMeans(dados.teste %>% select(-matricula, -cra))
treino.final$media <- rowMeans(treino.final %>% select(-matricula, -cra))
teste.final$media <- rowMeans(teste.final %>% select(-matricula))
lasso.t1 <- train(cra ~ poly(Discreta, 2) + poly(Grafos, 2) + IC + P2 + LP1 * LP2 + Vetorial * Cálculo1 + P1 * LP1 + media, data = dados.treino %>% select(-matricula),
method='lasso',
trControl = ctrl, # k-folder
metric='RMSE',
tuneLength = 100, # numero de comb. de parametros para serem testadas
preProcess=c('scale', 'center') # mais sobre isso em [2]
)
t1 <- predict(lasso.t1, dados.teste %>% select(-matricula) %>% select(-cra))
df.t1 <- data.frame(pred = t1, obs = dados.teste$cra)
round(defaultSummary(df.t1), digits = 3)
## RMSE Rsquared
## 0.381 0.715
t1 <- predict(lm, teste.final %>% select(-matricula))
df.final <- data.frame(matricula = teste.final$matricula, cra = t1)
write.csv(df.final, "test10.csv", row.names = F)
Esse foi o melhor modelo encontrado de acordo com os testes no Kaggle, apresentando RMSE de ~0.43.
Melhorias podem ser feitas como mostram os resultados encontrados pelos colegas, porém não consegui melhorar o modelo de forma representativa.