A fim de analisar qual o melhor número de vizinhos para uma Filtragem Colaborativa, analisou-se qual é o menor erro para diferentes números de vizinhos considerando o mesmo algoritmo.

Bibliotecas Utilizadas

library(dplyr)
library(corrplot)
library(GGally)
library(ggplot2)
library(reshape2)
library(caret)
library(mlbench)
library(hydroGOF)

Os dados

Os dados são tratados como anteriormente, veja em http://rpubs.com/liviaCavalcanti/337528.

dados_alunos <- read.csv("../alunosUFCGAnon.csv") 
dados_aluno_cc <- dados_alunos %>% filter(Cod_Curso == 14102100 & Cod_Evasao == 0 & Tipo == "Obrigatória")
dados_aluno_cc <- dados_aluno_cc %>% mutate(Matricula = factor(Matricula)) %>% arrange(Matricula) %>% 
  select(Matricula, Cod_Disciplina, Nome_Disciplina, Periodo, Creditos, Media_Disciplina, Situacao, Periodo_Ingresso, Periodo_Relativo)
dados_aluno_cc <- dados_aluno_cc %>% group_by(Matricula) %>% mutate(Media = round(mean(Media_Disciplina), digits = 2)) %>% filter(!is.na(Media))
# storing data as factors insures that the modeling functions will treat such data correctly. 
# Factors in R are stored as a vector of integer values with a corresponding set of character values to use when the factor is displayed

# Calulo do CRA
alunos_cra <- dados_aluno_cc %>% mutate(Cra.Crontibute = Media*Creditos) %>% summarise(cra = sum(Cra.Crontibute)/sum(Creditos))
alunos_max_media <- dados_aluno_cc %>% group_by(Matricula, Media_Disciplina) %>% filter(Media_Disciplina == max(Media_Disciplina)) %>% ungroup() %>%
  select(Nome_Disciplina, Matricula, Media_Disciplina) %>% mutate(Nome_Disciplina = as.factor(gsub(" ", ".", Nome_Disciplina))) %>%
  dcast(Matricula ~ Nome_Disciplina, mean) %>% merge(alunos_cra)
## Using Media_Disciplina as value column: use value.var to override.
alunos_max_media <- bind_cols(alunos_max_media,distinct(dados_aluno_cc %>% select(Matricula, Periodo_Ingresso))%>% select(Periodo_Ingresso)) %>% select(-Matricula1)
## Adding missing grouping variables: `Matricula`
alunos_graduados <- alunos_max_media[complete.cases(alunos_max_media), ]

##Organizando os data frames principais
# separando alunos por periodo 
primeiro_periodo <- alunos_max_media %>% select(Matricula, cra, CALCULO.DIFERENCIAL.E.INTEGRAL.I, ÁLGEBRA.VETORIAL.E.GEOMETRIA.ANALÍTICA, PROGRAMAÇÃO.I, 
                                                LABORATÓRIO.DE.PROGRAMAÇÃO.I, INTRODUÇÃO.A.COMPUTAÇÃO, LEITURA.E.PRODUCAO.DE.TEXTOS, Periodo_Ingresso) %>%
  na.omit(primeiro_periodo) %>% arrange(Matricula) %>%
  rename(matricula = Matricula, cra = cra,calculo1 = CALCULO.DIFERENCIAL.E.INTEGRAL.I, vetorial = ÁLGEBRA.VETORIAL.E.GEOMETRIA.ANALÍTICA, p1 = PROGRAMAÇÃO.I,
         lp1 = LABORATÓRIO.DE.PROGRAMAÇÃO.I, ic = INTRODUÇÃO.A.COMPUTAÇÃO, lpt = LEITURA.E.PRODUCAO.DE.TEXTOS)
head(primeiro_periodo)
##   matricula  cra calculo1 vetorial  p1  lp1   ic lpt Periodo_Ingresso
## 1    B10079 6.37     5.75     5.00 5.0 5.75 7.10 9.5           2007.1
## 2    B10087 1.05     0.00     0.00 0.0 0.00 1.95 7.6           2008.2
## 3    B10088 2.10     0.00     0.15 0.7 0.00 5.20 7.7           2009.2
## 4    B10092 7.10     6.90     4.25 5.0 7.00 7.50 8.5           2009.1
## 5    B10172 4.68     2.70     5.35 6.9 7.10 7.30 8.2           2011.2
## 6    B10192 6.55     5.85     5.00 8.4 8.40 7.80 8.8           2006.1
segundo_periodo <- alunos_max_media %>% 
  select(Matricula,cra, CALCULO.DIFERENCIAL.E.INTEGRAL.II, FUNDAMENTOS.DE.FÍSICA.CLÁSSICA, TEORIA.DOS.GRAFOS, PROGRAMAÇÃO.II,
         LABORATÓRIO.DE.PROGRAMAÇÃO.II, MATEMÁTICA.DISCRETA) %>% na.omit() %>% 
  arrange(Matricula) %>%
  rename(matricula = Matricula, cra = cra,calculo2 = CALCULO.DIFERENCIAL.E.INTEGRAL.II, classica = FUNDAMENTOS.DE.FÍSICA.CLÁSSICA,
         grafos = TEORIA.DOS.GRAFOS, p2 = PROGRAMAÇÃO.II, lp2 = LABORATÓRIO.DE.PROGRAMAÇÃO.II, discreta = MATEMÁTICA.DISCRETA)
head(segundo_periodo)
##   matricula  cra calculo2 classica grafos   p2 lp2 discreta
## 1    B10079 6.37 4.200000      5.7    7.8 8.90 8.3 4.050000
## 2    B10092 7.10 5.400000      5.0    5.1 6.70 8.2 5.000000
## 3    B10172 4.68 2.033333      5.5    5.5 4.15 3.0 4.666667
## 4    B10192 6.55 5.400000      6.4    5.0 6.00 8.2 5.000000
## 5    B10199 5.86 5.100000      7.8    5.0 6.30 8.7 5.100000
## 6     B1024 5.91 5.000000      5.3    7.6 8.30 8.7 7.000000
terceiro_periodo <- alunos_max_media %>%
  select(Matricula,cra, ESTRUTURA.DE.DADOS.E.ALGORITMOS, LAB.DE.ESTRUTURA.DE.DADOS.E.ALGORITMOS, FUNDAMENTOS.DE.FÍSICA.MODERNA, 
         ALGEBRA.LINEAR.I,PROBABILIDADE.E.ESTATISTICA, TEORIA.DA.COMPUTAÇÃO, GERÊNCIA.DA.INFORMAÇÃO) %>% 
  na.omit() %>% 
  arrange(Matricula) %>%
  rename(matricula = Matricula, eda = ESTRUTURA.DE.DADOS.E.ALGORITMOS, leda =  LAB.DE.ESTRUTURA.DE.DADOS.E.ALGORITMOS, moderna =  FUNDAMENTOS.DE.FÍSICA.MODERNA, 
         linear = ALGEBRA.LINEAR.I, prob = PROBABILIDADE.E.ESTATISTICA, tc = TEORIA.DA.COMPUTAÇÃO, gi = GERÊNCIA.DA.INFORMAÇÃO)
head(terceiro_periodo)
##   matricula  cra  eda leda moderna linear prob  tc  gi
## 1    B10092 7.10 6.60  7.9     8.3    6.1  6.0 7.2 7.7
## 2    B10284 7.14 7.00  7.2     8.3    6.1  5.5 6.9 7.0
## 3    B10304 6.17 5.15  7.0     8.5    6.2  1.2 6.9 8.6
## 4    B10443 7.15 7.00  7.7     8.7    7.2  6.8 7.3 7.9
## 5    B10504 7.12 6.70  8.2     8.3    5.0  6.7 7.0 7.1
## 6    B10644 6.07 5.10  5.2     5.0    5.1  5.0 5.3 4.7
quarto_periodo <- alunos_max_media %>% select(Matricula, cra, PARADIGMAS.DE.LING..DE.PROGRAMAÇÃO, METODOS.ESTATISTICOS, ORG.E.ARQUITETURA.DE.COMPUTADORES.I, 
                                              LAB.DE.ORG.E.ARQUITETURA.DE.COMPUTADORES, LÓGICA.MATEMÁTICA, ENGENHARIA.DE.SOFTWARE.I, SISTEMAS.DE.INFORMAÇÃO.I) %>%
  na.omit() %>%
  arrange(Matricula)%>% 
  rename(matricula = Matricula, plp = PARADIGMAS.DE.LING..DE.PROGRAMAÇÃO, metodos = METODOS.ESTATISTICOS, oac = ORG.E.ARQUITETURA.DE.COMPUTADORES.I, 
         loac = LAB.DE.ORG.E.ARQUITETURA.DE.COMPUTADORES, logica = LÓGICA.MATEMÁTICA, es = ENGENHARIA.DE.SOFTWARE.I, si1 = SISTEMAS.DE.INFORMAÇÃO.I)
head(quarto_periodo)
##   matricula  cra plp metodos oac loac logica  es si1
## 1    B10092 7.10 7.0     5.0 7.6  7.1    7.0 6.6 9.3
## 2    B10192 6.55 7.3     5.1 5.8  7.3    6.6 6.3 9.6
## 3    B10199 5.86 5.6     6.5 5.2  8.6    6.2 7.0 5.7
## 4    B10447 8.66 8.1     8.7 8.3  9.2   10.0 9.2 9.6
## 5    B10504 7.12 9.3     6.0 7.2  9.6    8.3 8.1 9.7
## 6    B10644 6.07 5.5     6.4 7.3  8.7    7.0 8.3 8.4
# Unindo os periodos
primeiro_segundo_periodos <- merge(primeiro_periodo, segundo_periodo)
head(primeiro_segundo_periodos)
##   matricula  cra calculo1 vetorial  p1  lp1  ic lpt Periodo_Ingresso
## 1    B10079 6.37 5.750000     5.00 5.0 5.75 7.1 9.5           2007.1
## 2    B10092 7.10 6.900000     4.25 5.0 7.00 7.5 8.5           2009.1
## 3    B10172 4.68 2.700000     5.35 6.9 7.10 7.3 8.2           2011.2
## 4    B10192 6.55 5.850000     5.00 8.4 8.40 7.8 8.8           2006.1
## 5    B10199 5.86 3.666667     6.20 6.1 5.60 7.8 7.0           2005.2
## 6     B1024 5.91 0.000000     5.45 7.5 8.40 7.7 7.0           2010.1
##   calculo2 classica grafos   p2 lp2 discreta
## 1 4.200000      5.7    7.8 8.90 8.3 4.050000
## 2 5.400000      5.0    5.1 6.70 8.2 5.000000
## 3 2.033333      5.5    5.5 4.15 3.0 4.666667
## 4 5.400000      6.4    5.0 6.00 8.2 5.000000
## 5 5.100000      7.8    5.0 6.30 8.7 5.100000
## 6 5.000000      5.3    7.6 8.30 8.7 7.000000
# Primeiro, segundo e terceiro periodo
primeiro_a_terceiro_periodo <- merge(primeiro_segundo_periodos, terceiro_periodo)
periodos_dados <- merge(primeiro_a_terceiro_periodo, quarto_periodo) %>% select(matricula, everything())
head(periodos_dados)
##   matricula  cra calculo1 vetorial  p1 lp1  ic  lpt Periodo_Ingresso
## 1    B10092 7.10     6.90     4.25 5.0 7.0 7.5  8.5           2009.1
## 2    B10504 7.12     4.65     6.30 5.3 7.9 7.6  7.2           2009.1
## 3    B10644 6.07     3.70     5.80 7.0 7.2 8.3  7.2           2010.2
## 4    B10973 6.73     5.60     5.60 7.0 7.7 8.4  6.7           2010.1
## 5    B11044 8.47     8.70     8.60 9.0 8.6 9.1 10.0           2008.1
## 6    B11365 8.35     6.20     8.20 7.9 7.9 9.2  9.3           2010.2
##   calculo2 classica grafos  p2 lp2 discreta eda leda moderna linear prob
## 1 5.400000 5.000000    5.1 6.7 8.2      5.0 6.6  7.9     8.3    6.1  6.0
## 2 5.000000 5.750000    6.3 7.7 5.0      6.3 6.7  8.2     8.3    5.0  6.7
## 3 4.033333 3.266667    7.9 7.6 7.0      6.5 5.1  5.2     5.0    5.1  5.0
## 4 5.900000 7.400000    5.9 7.4 7.0      6.8 7.0  5.0     7.7    6.7  5.2
## 5 8.400000 7.900000    8.2 8.8 9.4      8.3 8.4  9.4     9.4    9.3  7.2
## 6 6.900000 6.900000    9.2 9.1 9.3      7.6 7.1  8.6     8.2    8.3  7.0
##    tc  gi plp metodos oac loac logica   es si1
## 1 7.2 7.7 7.0     5.0 7.6  7.1    7.0 6.60 9.3
## 2 7.0 7.1 9.3     6.0 7.2  9.6    8.3 8.10 9.7
## 3 5.3 4.7 5.5     6.4 7.3  8.7    7.0 8.30 8.4
## 4 7.6 7.7 7.0     8.6 6.6  5.0    5.8 4.75 8.4
## 5 7.8 7.8 6.8     9.0 8.2  8.8   10.0 8.50 8.4
## 6 7.9 7.7 9.4     8.1 8.2 10.0    8.4 9.10 9.4
COL_QUARTO_PER <- colnames(quarto_periodo %>% select(-cra, -matricula))
COL_QUARTO_PER
## [1] "plp"     "metodos" "oac"     "loac"    "logica"  "es"      "si1"
## /// FUNCOES E CONSTANTES \\\##
#K= 10
NEIGH = 0.7

get_sim <- function(df) {
  
  row.names(df) <- df$matricula
  df <- df %>% subset(select=-c(matricula))
  
  inv_df <- as.data.frame(t(df))
  
  res <- cor(inv_df[sapply(inv_df, is.numeric)], use="p", method='pearson')
  return(res);
}

# retorna um vector de Named num, cujo nome é a matrícula e o valor a similaridade
get_neigh <- function(df, index, corr, K) {
  
  matr <- (df[index, 1])
  
  # todos os vizinhos, porém temos que "invalidar" ele mesmo
  corr[as.double(matr), as.double(matr)] = 0
  all_neigh <- corr[matr, ]
  
  k_neigh <- sort(all_neigh, decreasing = T)[1:K]
  
  return(k_neigh);
}

# calcula score ignorando vizinhos com NAs
get_score <- function(df, k_neigh, item) {
  
  notas <- subset(df, matricula %in% names(k_neigh))
  
  # removendo vizinhos que não possuem notas
  notas <- na.omit(notas) 
  
  # se todas as notas dos vizinhos forem NAs ou nenhum vizinho com
  # nota tenha similaridade > NEIGH consideramos que esse aluno
  # não tem vizinhos
  if(nrow(notas) == 0) {
    return(NA)
  }
  
  # atualizando similaridade
  notas$sim <- 0
  for(i in 1:length(notas$matricula)) {
    notas$sim[i] <- k_neigh[as.character(notas$matricula[i])] 
  }
  
  # se todas as notas dos vizinhos forem NAs ou nenhum vizinho com
  # nota tenha similaridade > NEIGH consideramos que esse aluno
  # não tem vizinhos
  eh_valido <- notas[notas$sim > NEIGH,]
  if(nrow(eh_valido) == 0) {
    return(NA)
  }
  
  res <- sum(notas[, item] * notas$sim) / sum(notas$sim)
  return(res)
}

rmse_cross <- as.data.frame(matrix(ncol = 7, nrow = 50))
media_rmse4 <- as.data.frame(matrix(ncol = 0, nrow = 50))

# separando em teste e treino
temp <- createDataPartition(periodos_dados$Periodo_Ingresso, p = 0.95, list = F)

Análise

A mudança em relação ao código anterior é que o número de vizinhos ‘K’ não é mais uma constante, e sim um valor que muda a cada iteração (‘K’ = ‘k’), sendo guardados os valores obtidos para cada ‘k’.

##          1        2        3        4        5        6        7        8
## 1 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501
## 2 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877
## 3 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946
## 4 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520
## 5 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302
## 6 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501
##          9       10       11       12       13       14       15       16
## 1 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501
## 2 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877
## 3 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946
## 4 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520
## 5 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302
## 6 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501
##         17       18       19       20       21       22       23       24
## 1 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501
## 2 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877
## 3 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946
## 4 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520
## 5 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302
## 6 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501
##         25       26       27       28       29       30       31       32
## 1 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501
## 2 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877
## 3 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946
## 4 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520
## 5 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302
## 6 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501
##         33       34       35       36       37       38       39       40
## 1 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501
## 2 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877
## 3 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946
## 4 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520
## 5 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302
## 6 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501
##         41       42       43       44       45       46       47       48
## 1 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501 2.385501
## 2 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877 2.396877
## 3 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946 2.344946
## 4 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520 2.333520
## 5 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302 2.376302
## 6 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501 2.382501
##         49       50 media_geral
## 1 2.385501 2.385501    2.385501
## 2 2.396877 2.396877    2.396877
## 3 2.344946 2.344946    2.344946
## 4 2.333520 2.333520    2.333520
## 5 2.376302 2.376302    2.376302
## 6 2.382501 2.382501    2.382501
##   media_geral
## 1     2.33352

Por fim, foi feita a média de todas as observações por linha, ou seja, número de vizinhos e chegou-se ao valor ideal de 5 vizinhos.