Lendo os dados

dados <- read.csv("dados/graduados.csv")

Conhecendo os dados

Os dados usados são referentes ao histórico de alunos do curso de computação da UFCG. A tarefa é, utilizando regressão linear, explicar o desempenho acadêmico.

O dataset inicial possui 15751 observações com 7 variáveis. No processo de leitura algumas alterações tiveram de ser feitas, encontramos muitos NaNs e tivemos que removelos para não influenciar nas análises que serão feitas. Depois calculamos os CRAs (Coeficiente de Rendimento Acadêmico) dos alunos.

#ordenando os dados pela matrícula
graduados <- dados %>%
  arrange(matricula)

#filtrando dados e removendo os NaNs
graduados.clean <- graduados %>%
  filter(!is.na(media))

#calculando CRA dos alunos e salvando numa coluna
graduados.cra <- graduados.clean %>%
  group_by(matricula) %>%
  mutate(cra.contrb = media*creditos) %>%
  summarise(cra = sum(cra.contrb)/sum(creditos))

#utilizando a função dcast para deixar o dataset na forma ideal para a análise
graduados.model.input <- graduados.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.cra)

Períodos Iniciais

A ideia principal dessa análise é explicar o desempenho acadêmico final dos alunos de computação, analisando como foi o seu desempenho no início do curso. Para isso vamos analisar seus rendimentos no primeiro e no segundo período do curso, levando em consideração suas notas nas disciplinas cursadas e, usando regressão linear, tentar explicar seu desempenho final. Nossa análise será dividida por partes, primeiro vamos nos aprofundar no primeiro período, ver quais disciplinas mais afetam o desempenho do aluno, depois vamos ver quais disciplinas não influenciam, nesse caso vamos identificar as cadeiras que não tem valor em significância para o modelo que queremos construi e assim removê-las. Depois de selecionar as variáveis mais importantes vamos montar nosso modelo.

#selecionando cra e disciplinas do primeiro e segundo período
p1.p2 <- graduados.model.input %>%
  select(Laboratório.de.Programação.I, Programação.I, Introdução.à.Computação, Cálculo.Diferencial.e.Integral.I, Álgebra.Vetorial.e.Geometria.Analítica, Leitura.e.Produção.de.Textos, 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, cra)

#renomeando colunas
colnames(p1.p2) <- c("C1", "Vetorial", "LPT", "P1", "IC", "LP1","C2", "Discreta", "P2", "Grafos", "Física", "LP2", "CRA")

#removendo NaNs
p1.p2 <- na.omit(p1.p2)

#calculando modelo linear
lm.p1p2 <-lm(CRA ~ ., p1.p2)

summary(lm.p1p2)
## 
## Call:
## lm(formula = CRA ~ ., data = p1.p2)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -1.8273 -0.2988  0.1069  0.2796  1.0032 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.33894    0.59783   2.240  0.02758 *  
## C1          -0.02472    0.07450  -0.332  0.74082    
## Vetorial    -0.02593    0.07684  -0.337  0.73660    
## LPT          0.10196    0.08639   1.180  0.24098    
## P1           0.02121    0.04907   0.432  0.66661    
## IC           0.04443    0.04762   0.933  0.35327    
## LP1          0.09172    0.05167   1.775  0.07925 .  
## C2          -0.00100    0.05302  -0.019  0.98499    
## Discreta     0.23935    0.05863   4.083 9.63e-05 ***
## P2           0.29214    0.09553   3.058  0.00293 ** 
## Grafos       0.09620    0.06302   1.526  0.13040    
## Física      -0.01024    0.06120  -0.167  0.86745    
## LP2         -0.02848    0.06666  -0.427  0.67024    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.5046 on 90 degrees of freedom
## Multiple R-squared:  0.6889, Adjusted R-squared:  0.6474 
## F-statistic: 16.61 on 12 and 90 DF,  p-value: < 2.2e-16

Temos agora nosso primeiro modelo com todas as variáveis (disciplinas do primeiro e do segundo período). Esse modelo consegue explicar ~64% (R2 ajustado) da variável alvo CRA. Mesmo com um bom percentual de explicação vamos refinar nosso modelo, primeiro vamos ver quais variáveis podem não estar influenciando nosso resultado e assim removê-las. Para iniciar nosso refinamento analisaremos a correlação entre as variáveis.

#calculando matriz de correlação
correlationMatrix <- cor(p1.p2)

#utlizamos a bibliota corrplot para montar o gráfico com as correlações
corrplot(correlationMatrix, method="circle", type="lower", order="hclust", addCoef.col = "black")

Analisando a matriz de correlação das variáveis, observamos que grande parte possue uma correlaçao até 0.5 ou inferior, baseado nisso assumimos um treshold de 0.65, ou seja, acima desse valor a correlação entre as variaveis e considerada alta. Com base na literatura, sabemos que variáveis com correlação alta e/ou p-valores altos influenciam negativamente na construção do modelo, por isso, para termos um modelo consistente vamos remover as variáveis que se comportam dessa forma.

Analisando nosso modelo com todas as variáveis, vemos que a disciplina de LPT possui uma significancia que é considerada, porém, por experiência própria, sabemos que o desempenho nessa disciplina não possui um peso significativo no rendimento do aluno, por isso vamos remover essa variável e rodarmos novamente o modelo.

lm.p1p2.melhorado <-lm(CRA ~ . -LPT, p1.p2)
summary(lm.p1p2.melhorado)
## 
## Call:
## lm(formula = CRA ~ . - LPT, data = p1.p2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.77208 -0.31773  0.08834  0.29697  0.96394 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.503626   0.582580   2.581  0.01145 *  
## C1          -0.017638   0.074416  -0.237  0.81317    
## Vetorial    -0.019346   0.076803  -0.252  0.80169    
## P1           0.027658   0.048870   0.566  0.57281    
## IC           0.058269   0.046254   1.260  0.21098    
## LP1          0.091203   0.051777   1.761  0.08152 .  
## C2           0.003867   0.052972   0.073  0.94196    
## Discreta     0.251851   0.057789   4.358 3.44e-05 ***
## P2           0.290248   0.095727   3.032  0.00316 ** 
## Grafos       0.105598   0.062650   1.686  0.09531 .  
## Física       0.012176   0.058303   0.209  0.83503    
## LP2         -0.016867   0.066074  -0.255  0.79909    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.5057 on 91 degrees of freedom
## Multiple R-squared:  0.6841, Adjusted R-squared:  0.6459 
## F-statistic: 17.92 on 11 and 91 DF,  p-value: < 2.2e-16

Analisando o modelo, agora sem LPT, concluímos que nosso feeling sobre essa disciplina estava correto, vemos que o R² e o R² ajustado permanecem praticamente constantes e o RSE diminui. Percebemos também que ao retirarmos LPT as variáveis LP1 e Grafos se mostraram significantes, o que nos diz que essa disciplina estava se mostrando significante devido sua relação com essas outras.

As variáveis que se apresentaram mais significantes foram Discreta, P2, Grafos e LP1 vamos agora rodar o nosso modelo apenas com essas variáveis.

lm.p1p2.melhorado2 <-lm(CRA ~ Discreta + P2 + Grafos + LP1, p1.p2)
summary(lm.p1p2.melhorado2)
## 
## Call:
## lm(formula = CRA ~ Discreta + P2 + Grafos + LP1, data = p1.p2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.75120 -0.30507  0.09335  0.29669  0.98625 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.64287    0.49036   3.350 0.001147 ** 
## Discreta     0.27251    0.05067   5.379 5.11e-07 ***
## P2           0.28364    0.07773   3.649 0.000424 ***
## Grafos       0.10967    0.05244   2.091 0.039070 *  
## LP1          0.09809    0.04432   2.213 0.029199 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4962 on 98 degrees of freedom
## Multiple R-squared:  0.6724, Adjusted R-squared:  0.659 
## F-statistic: 50.29 on 4 and 98 DF,  p-value: < 2.2e-16

Com o nosso modelo melhorado, vemos que o R² ajustado aumentou, temos agora que nosso modelo consegue explicar ~65% da variação dos dados, o RSE diminui de 0.5057 para 0.4962.

Vamos analisar mais profundamente o nosso modelo.

predicoes = predict.lm(lm.p1p2.melhorado ,p1.p2)

#plot modelo
plot(p1.p2$CRA ,predicoes , xlab="CRA", ylab="Disciplinas do 1ºP e 2ºP")
abline(0,1,col="red",lty=2,lwd=2)

#plot do modelo
prediction <- predict(lm.p1p2.melhorado)

lm_prediction <- data.frame(pred = prediction, obs = p1.p2$CRA)

ggplot(lm_prediction, aes(pred, obs)) +  geom_point(alpha = 0.1, position = position_jitter(width = 0.3)) + 
  labs(title="Previsão do modelo", x= "Predição", y="CRA") +  
  geom_line(aes(y = predict(lm.p1p2.melhorado, p1.p2)), colour = "red")

Gráficos de diagnósticos referentes aos resíduos. Plotando previsões versus resíduos

residuos = p1.p2$CRA - predicoes

#plot residuos
plot(predicoes,residuos)
abline(h=0,col="blue",lty=2,lwd=2)

Verificando se os resíduos seguem uma distribuição normal com média 0:

qqnorm(residuos)
qqline(residuos, col = 2,lwd=2,lty=2)

Verificando frequência dos resíduos

ggplot(lm.p1p2.melhorado, aes(.resid)) + labs(title="Frequência de resíduos", x= "Resíduo", y="Frequência") + 
  geom_freqpoly(binwidth = 0.5) 

Analisando os três gráficos mostrados acima, conseguimos ver que os resíduos possuem uma distribuição simétrica em relação ao eixo zero, não temos nenhum padrão que possa ser considerado o que significa que nosso modelo está bem elaborado. No segundo gráfico, temos que os resíduos seguem uma distribuição normal com média zero, a sobreposição dos pontos sobre a linha vermelha nos mostra isso. No terceiro gŕafico observamos a a frequência dos nossos resíduos e vemos que ela tem um coportamento bem similiar a de uma normal.

1 - Primeiro Período

Vamos filtrar nosso dataset original para utilizarmos apenas as disciplinas referentes ao primeiro período.

#filtrando disciplinas
primeiro.periodo <- p1.p2 %>%
  select(C1, Vetorial, LPT, P1, IC, LP1, CRA)

#removendo NaNs
primeiro.periodo <- na.omit(primeiro.periodo)

#plotando relacionamento entra as disciplinas
ggpairs(primeiro.periodo)

#utilizamos a função melt para transformar os dados e podermos ter o plot dos histogramas de todas as disciplinas
df1 <- melt(primeiro.periodo)

#plotando histogramas
ggplot(df1,aes(x = value)) + 
    facet_wrap(~variable, scales = "free_x") + 
    geom_histogram(aes(fill=..count..))

No primeiro gráfico temos várias informações sobre nossas variáveis, a curva de sua distribuição, o plot de seus pontos e sua correlação. No segundo podemos ver o histograma de cada uma das disciplinas. A informação necessária que queremos tirar desses gráficos é observar o comportamento e distribuição de nossas variáveis. Como as curvas de suas distribuições se assemelham muito com a de uma distribuição normal concluimos que não será preciso aplicarmos nenhum procedimento de transformação nos dados.

1.1 - Relacionamento entre variáveis.

Nos gráficos acima podemos ver o relacionamento entre as variáveis. LPT é a disciplina que possui maior correlação com a variável resposta CRA.

1.2 - Analisando Matriz de correlação

#calculando matriz de correlação
correlationMatrix1 <- cor(primeiro.periodo)

#utlizamos a bibliota corrplot para montar o gráfico com as correlações
corrplot(correlationMatrix1, method="circle", type="lower", order="hclust", addCoef.col = "black")

No gráfico acima podemos observar a correlação entre as variáveis.

lm.p1.completo <- lm(primeiro.periodo$CRA ~ ., primeiro.periodo)
summary(lm.p1.completo)
## 
## Call:
## lm(formula = primeiro.periodo$CRA ~ ., data = primeiro.periodo)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.50445 -0.33043  0.08777  0.39468  1.14827 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.29099    0.67005   1.927 0.056973 .  
## C1           0.09525    0.08695   1.095 0.276071    
## Vetorial     0.06176    0.08391   0.736 0.463529    
## LPT          0.33606    0.08905   3.774 0.000278 ***
## P1           0.08196    0.05666   1.446 0.151311    
## IC           0.09873    0.05745   1.718 0.088957 .  
## LP1          0.10564    0.05872   1.799 0.075142 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.6204 on 96 degrees of freedom
## Multiple R-squared:  0.4984, Adjusted R-squared:  0.4671 
## F-statistic:  15.9 on 6 and 96 DF,  p-value: 1.311e-12

Para o modelo referente ao primeiro período o RSE vale 0.62 e o R² ajustado ~0.46. Utilizando a função summary temos um resumo do nosso modelo e de quais variáveis são importantes. Analisando a matriz de correlação vimos que as variáveis C1 e Vetorial possuem uma alta correlação e isso pode contribuir negativamente para o modelo, acontecendo uma colinearidade entre as variáveis, decidimos então remover a variável C1.

lm.p1 <- lm(primeiro.periodo$CRA ~ . -C1, primeiro.periodo)
summary(lm.p1)
## 
## Call:
## lm(formula = primeiro.periodo$CRA ~ . - C1, data = primeiro.periodo)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.44692 -0.34757  0.07878  0.40980  1.24096 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.47673    0.64891   2.276 0.025063 *  
## Vetorial     0.12905    0.05723   2.255 0.026374 *  
## LPT          0.35323    0.08775   4.026 0.000113 ***
## P1           0.08907    0.05635   1.581 0.117180    
## IC           0.09847    0.05751   1.712 0.090073 .  
## LP1          0.08889    0.05675   1.566 0.120513    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.621 on 97 degrees of freedom
## Multiple R-squared:  0.4921, Adjusted R-squared:  0.466 
## F-statistic:  18.8 on 5 and 97 DF,  p-value: 5.029e-13

Após remover a variável C1, concluímos que ela não influencia o nosso modelo, pois o R² ajustado permaneceu constante ~0.46. Concluímos nosso modelo refente ao primeiro período explicando aproximadamente 46% da dispersão dos dados.

2 - Segundo Período

Vamos filtrar nosso dataset original para utilizarmos apenas as disciplinas referentes ao segundo período.

#filtrando disciplinas
segundo.periodo <- p1.p2 %>%
  select(C2, Discreta, P2, Grafos, Física, LP2, CRA)

#plotando relacionamento entra as disciplinas
ggpairs(segundo.periodo)

#utilizamos a função melt para transformar os dados e podermos ter o plot dos histogramas de todas as disciplinas
df1 <- melt(segundo.periodo)

#plotando histogramas
ggplot(df1,aes(x = value)) + 
    facet_wrap(~variable, scales = "free_x") + 
    geom_histogram(aes(fill=..count..))

Da mesma forma que observamos o primeiro período, temos os plots para o segundo. Nossas variáveis continuam com um bom comportamento para aplicarmos um modelo de regressão linear.

2.1 - Relacionamento entre variáveis.

Nos gráficos acima podemos ver o relacionamento entre as variáveis. Podemos ver a curva de suas respectivas distribuições, com isso podemos dizer que a maioria se comporta como uma distribuição normal, isso significa que os dados estão bem distribuído e vemos também que não temos algum enviesamento que deve ser levado em consideração. Chegamos a conlusão que não será necessário aplicar alguma transformação nas variáveis. Podemos seguir adiante com nossa análise.

2.2 - Analisando Matriz de correlação

#calculando matriz de correlação
correlationMatrix2 <- cor(segundo.periodo)

#utlizamos a bibliota corrplot para montar o gráfico com as correlações
corrplot(correlationMatrix2, method="circle", type="lower", order="hclust", addCoef.col = "black")

Observe com atenção o gráfico acima e veja a correlação entre as disciplinas. A disciplina que possui maior correlação com a variável resposta é Matemática Discreta.

lm.p2.completo <- lm(segundo.periodo$CRA ~ ., segundo.periodo)
summary(lm.p2.completo)
## 
## Call:
## lm(formula = segundo.periodo$CRA ~ ., data = segundo.periodo)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.61719 -0.37021  0.06793  0.35182  1.00669 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 1.953591   0.519452   3.761 0.000291 ***
## C2          0.004532   0.050847   0.089 0.929172    
## Discreta    0.258405   0.057117   4.524 1.74e-05 ***
## P2          0.269866   0.089799   3.005 0.003386 ** 
## Grafos      0.133839   0.056205   2.381 0.019227 *  
## Física      0.040092   0.056358   0.711 0.478571    
## LP2         0.022584   0.058640   0.385 0.700996    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.5117 on 96 degrees of freedom
## Multiple R-squared:  0.6588, Adjusted R-squared:  0.6374 
## F-statistic: 30.89 on 6 and 96 DF,  p-value: < 2.2e-16

Montamos um modelo que leva em consideração todas as disciplinas do segundo período. Temos um R² 0.50 e um R² ajustado 0.64, ou seja, nosso modelo consegue explicar ~63% da dispersão dos dados. Porém, vamos tentar refiná-lo e utilizar apenas as variáveis que tiveram uma real significância.

lm.p2 <- lm(segundo.periodo$CRA ~ Discreta + P2 + Grafos, segundo.periodo)
summary(lm.p2)
## 
## Call:
## lm(formula = segundo.periodo$CRA ~ Discreta + P2 + Grafos, data = segundo.periodo)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.59195 -0.36647  0.07553  0.35313  0.95263 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  2.18886    0.43205   5.066 1.89e-06 ***
## Discreta     0.27684    0.05162   5.364 5.36e-07 ***
## P2           0.29400    0.07910   3.717 0.000334 ***
## Grafos       0.12704    0.05286   2.404 0.018095 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.5059 on 99 degrees of freedom
## Multiple R-squared:  0.656,  Adjusted R-squared:  0.6456 
## F-statistic: 62.94 on 3 and 99 DF,  p-value: < 2.2e-16

Após rodar novamente o modelo, percebemos que ao considerar apenas as variáveis mais significativas tivemos um aumento na porcentagem de explicação dos dados, nosso R² ajustado foi para 64% e o RSE sofreu uma redução de 0.51 para 0.50. Concluímos então, que nosso modelo fica mais consistente utilizando apenas essas variáveis.

3 - Conlusões

Uma das perguntas a serem respondidas com nossa análise, é ver qual dos períodos consegue explicar o desempenho do cra do aluno. Após analisar detalhadamente o nosso conjunto de dados, todas as variáveis juntas, depois deparadas por períodos, vamos levar em consideração o valor dos R² ajustado para definir qual período explica melhor o cra do aluno.

  • 1º Período: R² ajustado 0.466, RSE 0.621
  • 2º Período: R² ajustado 0.645, RSE 0.505

O segundo período explica melhor a dispersão dos dados, então concluimos que o 2ºP é melhor.