Projeto 1 - Aplicação de MLG

Universidade Estadual da Paraíba - UEPB

Professor: Pedro Monteiro de Almeida Junior

Aluno: José Wellington Cavalcanti

Aluno: Giullber Valentim da Silva

1 Introdução

     Neste trabalho foi realizado a modelagem dos dados com base nas distribuições Normal Inversa e a Gamma, que foram as escolhidas com base na aparente distribuição dos dados da variável resposta por meio de um histograma. Os dados utilizados foram retirados e filtrados da coleção de dados Dota 2 Matches disponivel no site kaggle.com, presentes na planilha players.csv, sendo escolhidos apenas as variáveis mais importantes para esse estudo.

     Dota 2 é um jogo de estilo moba (Multiplayer Online Battle Arena), o que em português significaria “Arena de Batalha Online Para Vários Jogadores”, disputado entre duas equipes composta de 5 jogadores cada:

  • Radiants (os iluminados);
  • Dires (Os temidos);

com cada uma tendo como objetivo principal a destruição do Ancient (Ancestral) dentro da base da equipe adversária, utilizando os três trilhas no mapa que podem ser classificados como:

  • bot: Lane (trilhas) inferior do mapa;
  • top: Lane superior do mapa;
  • mid: Lane no meio do mapa;

cada lane, para ambos lados, é defendida por três torres, com um ficando nas entradas da base das esquipes.

     Cada jogador poderá escolher apenas um herói (persogem do jogo) em uma partida dentre mais de 120 heróis disponiveis no jogo, nenhum herói pode ser escolhido por mais de um jogador durante a mesma partida. Durante a partida, cada equipe tentará superar a outra em gold (moeda utilizada dentro da partida para a compra de itens e possíveis buybacks) e nível através de:

  • Kills: Matando heróis adversários, o que garante uma boa vantagem de ouro e experiência;
  • farm: Matando criaturas espalhadas no mapa e nas lanes, permitindo que o herói ganhe e acumule mais gold;
  • Destruição de estruturas: Destruição de torres e barracas, garantido ouro e vantagem no mapa, ou seja, quanto menos estruturas no mapa uma equipe tiver, menos controle do mapa e menos espaço ela terá para evoluir;
  • Dentre outras maneiras;

1.1 Pacotes utilizados

library(tidyverse)
library(readxl)
library(echarts4r)
library(MASS)
library(pscl)
library(epiDisplay)
library(corrplot)
library(knitr)
library(car)

1.2 Banco de dados

## Importação do banco de dados 
dados_dota = read_xlsx("Dados//dota_data.xlsx")

     Com base nisso, o banco de dados utilizado nessa análise foi organizado de tal forma que possamos explicar a quantidade de ouro ganho por minuto por um determinadado herói com base em algumas outras variáveis, com isso, os dados foram organizados, a partir de uma média, da seguinte forma:

1.2.1 Seleção e resumo das variáveis de interesse

df = dados_dota %>% group_by(hero_id) %>% 
  summarise(gold_spent = mean(gold_spent),
            gold = mean(gold),
            gold_per_min = mean(gold_per_min),
            level = mean(level),
            xp_per_min = mean(xp_per_min),
            kills = mean(kills),
            deaths = mean(deaths),
            assists = mean(assists),
            denies = mean(denies),
            last_hits = mean(last_hits))
df_new = df[-1,]

kable(head(df_new,10), align = "l",
      caption = "tabela 1: Dados por herói")
tabela 1: Dados por herói
hero_id gold_spent gold gold_per_min level xp_per_min kills deaths assists denies last_hits
1 19535.907 2392.246 554.1927 20.57482 580.3928 7.340996 5.449979 6.722222 10.741699 298.67358
2 13129.112 1682.508 400.1091 18.03325 442.9383 8.525321 9.365138 10.498153 1.327755 136.26972
3 9834.172 1512.150 295.2934 15.56326 336.7203 4.766941 7.721112 11.811986 3.867607 32.76459
4 15626.152 1821.146 447.6417 19.41982 494.8359 9.657307 9.190122 9.746279 5.939445 165.67016
5 10367.260 1532.349 314.6689 15.78906 346.9434 4.483686 8.946215 14.027403 1.828830 48.83648
6 15209.486 2008.288 459.5548 18.64724 484.3773 6.869249 7.980061 7.801380 7.371932 174.06135
7 11156.634 1618.031 334.2949 16.61406 374.5496 4.931202 8.514616 15.178221 1.841031 71.51603
8 17697.906 2213.266 520.1265 19.88849 549.4204 9.552627 6.439100 8.394939 9.026169 220.60660
9 12856.619 1792.313 368.3325 17.03911 395.8036 6.374480 6.957143 12.395978 3.529820 94.17725
10 15537.172 2045.054 437.4199 18.90486 484.0157 7.646982 5.837927 9.759186 9.187664 164.61220

onde:

  • hero_id: Id de identificação do herói;
  • gold_spent: Média da quantidade de ouro gasto em uma partida;
  • gold: Média da quantidade de ouro restante no final de uma partida;
  • gold_per_min: Média da quantidade de ouro por minuto ganho em uma partida;
  • level: Média da quantidade nível ganho por um herói em uma partida;
  • xp_per_min: Média da quantidade de experiência por minuto obtida por um herói em uma partida;
  • Kills: Média da quantidade de heróis adversários mortos por um herói em uma partida;
  • deaths: Média da quantidade de vezes em que o herói morreu em uma partida;
  • assists: Média da quantidade de vezes que um herói ajudou heróis da sua equipe a matar algum herói adversário em uma partida;
  • denies: Média da quantidade de vezes em que o herói negou alguma critura para um herói adversário em uma partida;
  • last_hits: Média da quantidade de vezes em que o herói matou algum criatura no jogo em uma partida;

2 Análise descritiva

     Assim como toda análise estatística, é fundamental a anáçise descritiva dos dados. Nessa etapa podemos econtrar padrões ou até mesmo informações importantes para a modelagem dos dados, através de tabelas ou gráficos.

     Com base nisso, incialmente teremos a seguinte tabela:

descritiva_data = summ(df_new)

kable(descritiva_data, align = 'l',
      caption = "tabela 2: Estatísticas descritiva." )
tabela 2: Estatísticas descritiva.
x
No. of observations = 110
Var. name obs. mean median s.d. min. max.
gold_spent 110 13722.16 13767.86 2768.83 8509.1 24595.31
gold 110 1849.06 1808.08 265.23 1366.25 2769.52
gold_per_min 110 404.04 403.04 74.15 287.52 709.55
level 110 17.88 18.03 1.66 14.35 21.79
xp_per_min 110 441.1 443.77 76.24 307.35 675.13
kills 110 7.04 6.96 2.25 2.41 12.71
deaths 110 7.74 7.67 0.97 5.35 10.13
assists 110 11.65 11.76 2.55 5.8 18.24
denies 110 4.64 3.78 2.61 0.82 14.53
last_hits 110 126.34 122.22 62.82 29.55 298.67

2.1 Análise da variável resposta

Histograma

fun_hist <- function(data,col){
  name = names(data[col])
  histograma<-hist(data[[col]],  col="#27727b", border="white", xlab="Gold",
                   ylab="FREQUÊNCIA", main=paste0("Histograma de ",name), 
                   ylim = c(0,32), 
                   xlim = c(200,800))
  abline(v=mean(data[[col]]), col="red", lwd=2)
  abline(v=median(data[[col]]), col=7, lwd = 3, lty = 2)
  
  xfit<-seq(min(data[[col]]),max(data[[col]]))
  yfit<-dnorm(xfit,mean=mean(data[[col]]),sd=sd(data[[col]]))
  yfit <- yfit*diff(histograma$mids[1:2])*length(data[[col]])
  lines(xfit, yfit, col='#cc7e63', lwd=2)
  
  legend("topright", legend =c("Média","Mediana",'Curva Densidade'),
         col=c('red',7,'#cc7e63'),lty = c(1,2,1),lwd=c(2,3,2), cex = 1)
}


fun_hist(df_new,3)

     Com base neste histograma, analisando a sua curva de densidade, podemos verificar uma assimetria à direita com apenas valores contínuos e positivos, o que se encaixa na definição das distribuições Gamma e Normal inversa, logo, iremos avaliar qual distribuição se adequa melhor aos dados com base em algumas comparações que será feita loga a seguir.

2.2 Análise das variáveis explicativas

df_var = df_new[,-3]
par(mfrow = c(2,2))
for(i in 1:2){
  
    name = names(df_var[i])
  hist(df_var[[i]],main = paste("Histograma de" , name),
       xlab = NULL, col = '#e098c7')
  boxplot(df_var[[i]], main = paste("Boxplot de" , name),
          col = "#27727b")
  
}

par(mfrow = c(2,2))
for(i in 3:4){
  
    name = names(df_var[i])
  hist(df_var[[i]],main = paste("Histograma de" , name),
       xlab = NULL, col = '#e098c7')
  boxplot(df_var[[i]], main = paste("Boxplot de" , name),
          col = "#27727b")
  
}

par(mfrow = c(2,2))
for(i in 5:6){
  
    name = names(df_var[i])
  hist(df_var[[i]],main = paste("Histograma de" , name),
       xlab = NULL, col = '#e098c7')
  boxplot(df_var[[i]], main = paste("Boxplot de" , name),
          col = "#27727b")
  
}

par(mfrow = c(2,2))
for(i in 7:8){
  
    name = names(df_var[i])
  hist(df_var[[i]],main = paste("Histograma de" , name),
       xlab = NULL, col = '#e098c7')
  boxplot(df_var[[i]], main = paste("Boxplot de" , name),
          col = "#27727b")
  
}

par(mfrow = c(1,2))
for(i in 9){
  
    name = names(df_var[i])
  hist(df_var[[i]],main = paste("Histograma de" , name),
       xlab = NULL, col = '#e098c7')
  boxplot(df_var[[i]], main = paste("Boxplot de" , name),
          col = "#27727b")
  
}

2.3 Correlação

cor_var = cor(df_new)
corrplot(cor_var, method = "number")

     Com base neste gráfico, podemos verificar alguns casos de possíveis variáveis multicolineares, são elas: gold_spent, level, xp_per_min e last_hits. Inicialmente não iremos retirar esta variáveis do banco de dados, mas logo a seguir, na aplicação do vif (Fator de Inflação da Variância) será discutida o método de aplicação e remoção das mesmas, se necessário.

3 Ajuste inicial dos modelos

3.1 Normal Inversa

     O primeiro modelo que iremos ajustar será com base na Normal Inversa usando a função de ligação identidade, que foi a que demonstrou os melhores resultados. Com base nisso, teremos:

modelo_invG = glm(gold_per_min~ gold+ gold_spent+level+xp_per_min+
               kills+deaths+assists+denies+last_hits, data = df_new,
             family = inverse.gaussian(link = "identity"))
summary(modelo_invG)
## 
## Call:
## glm(formula = gold_per_min ~ gold + gold_spent + level + xp_per_min + 
##     kills + deaths + assists + denies + last_hits, family = inverse.gaussian(link = "identity"), 
##     data = df_new)
## 
## Deviance Residuals: 
##        Min          1Q      Median          3Q         Max  
## -1.182e-03  -2.128e-04   2.760e-06   3.895e-04   1.229e-03  
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  2.467e+02  1.756e+01  14.048  < 2e-16 ***
## gold         2.201e-02  3.238e-03   6.796 7.90e-10 ***
## gold_spent   2.261e-02  7.755e-04  29.149  < 2e-16 ***
## level       -3.575e+01  1.842e+00 -19.409  < 2e-16 ***
## xp_per_min   9.023e-01  3.803e-02  23.728  < 2e-16 ***
## kills       -2.244e-01  4.015e-01  -0.559   0.5775    
## deaths       5.433e+00  5.831e-01   9.317 3.11e-15 ***
## assists      4.115e-01  1.909e-01   2.155   0.0336 *  
## denies      -5.849e-01  2.354e-01  -2.485   0.0146 *  
## last_hits    4.166e-02  2.547e-02   1.636   0.1051    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for inverse.gaussian family taken to be 2.746116e-07)
## 
##     Null deviance: 8.9634e-03  on 109  degrees of freedom
## Residual deviance: 2.7581e-05  on 100  degrees of freedom
## AIC: 637.42
## 
## Number of Fisher Scoring iterations: 3

3.2 Gamma

     O ajuste utilizando a distribuição Gamma também apresentou melhores resultados com a função de ligação identidade, sendo assim, teremos:

modelo_gm = glm(gold_per_min~ gold+ gold_spent+level+xp_per_min+
               kills+deaths+assists+denies+last_hits, data = df_new,
             family = Gamma(link = "identity"))
summary(modelo_gm)
## 
## Call:
## glm(formula = gold_per_min ~ gold + gold_spent + level + xp_per_min + 
##     kills + deaths + assists + denies + last_hits, family = Gamma(link = "identity"), 
##     data = df_new)
## 
## Deviance Residuals: 
##        Min          1Q      Median          3Q         Max  
## -0.0231647  -0.0050093   0.0000451   0.0070011   0.0242132  
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  2.460e+02  1.883e+01  13.066  < 2e-16 ***
## gold         2.144e-02  3.314e-03   6.469 3.68e-09 ***
## gold_spent   2.293e-02  7.255e-04  31.602  < 2e-16 ***
## level       -3.590e+01  1.930e+00 -18.600  < 2e-16 ***
## xp_per_min   9.010e-01  3.914e-02  23.022  < 2e-16 ***
## kills       -2.778e-01  4.130e-01  -0.673   0.5026    
## deaths       5.717e+00  6.008e-01   9.516 1.14e-15 ***
## assists      3.756e-01  2.016e-01   1.863   0.0654 .  
## denies      -5.557e-01  2.339e-01  -2.376   0.0194 *  
## last_hits    3.273e-02  2.533e-02   1.292   0.1992    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for Gamma family taken to be 0.0001130904)
## 
##     Null deviance: 3.584980  on 109  degrees of freedom
## Residual deviance: 0.011339  on 100  degrees of freedom
## AIC: 641.12
## 
## Number of Fisher Scoring iterations: 3

     Se pode notar que uma grande maioria das variáveis deram como siginificativas, porém, as duas principais não se mostraram signficativas, são elas: kills e last_hits. Ambas, durante uma partida, são as que mais influênciam diretamente na quantidade ouro ganho por minuto por cada herói, como dito anteriormente, o farm é um dos principais meios de conseguir e acumular ouro durante a partida através dos last_hits em cada criatura no mapa, seguido pela quantida de kills que se pode obter na mesma.

     Sendo assim, podemos verificar que existe algum problema na modelagem dos dados ocasionando uma perda da informação na explicação da variável resposta.

3.3 Comparação Inicial

     Os critérios adotados para a comparação dos modelos foram o AIC e o pseudo_\(R^{2}\) de McFadden, com isso, teremos:

# AIC
invg_aic = modelo_invG$aic
gm_aic = modelo_gm$aic

# McFadden
invg_pR2 = pR2(modelo_invG)[[4]]
## fitting null model for pseudo-r2
gm_pR2 = pR2(modelo_gm)[[4]]
## fitting null model for pseudo-r2
normal_inv = c(invg_pR2,invg_aic)
gamma = c(gm_pR2,gm_aic)

tabela_comp = rbind(normal_inv,gamma)
colnames(tabela_comp) = c("McFadden","AIC")

kable(tabela_comp, align = 'l',
      caption = "tabela 3: Comparação inicial dos modelos")
tabela 3: Comparação inicial dos modelos
McFadden AIC
normal_inv 0.5083077 637.4175
gamma 0.5058554 641.1155

     De forma inicial, podemos verificar que o modelagem dos dados com base na Normal Inversa se mostrou um pouco mais ajustado em relação a Gamma.

4 Verificando a existência de Multicolinearidade

     Com base no que foi verificado anteriormente, problemas na significância de variáveis que explicam a variável resposta gold_per_min, iremos aplicar a metodologia do vif e verificar se após a remoção de algumas variáveis, que apresentem valores acima de 5, os modelos irão representar melhor os dados.

     Para esse estudo, como não foi verificado nenhuma diferença dos valores na aplicação do vif utilizando os dois modelos, iremos demonstrar e realizar o passo a passo apenas com o modelo da Normal Inversa. Portanto:

4.1 Passo 1 - Geral

modelo_teste = glm(gold_per_min~ gold+ gold_spent+level+xp_per_min+
               kills+deaths+assists+denies+last_hits, data = df_new,
             family = inverse.gaussian(link = "identity"))

vif_values <- vif(modelo_teste)

# Gráfico
barplot(vif_values, main = "VIF Values", horiz = TRUE, col = "steelblue")
abline(v = 5, lwd = 3, lty = 2)

vif_values
##       gold gold_spent      level xp_per_min      kills     deaths    assists 
##   3.812807  26.058074  63.707802  52.732061   5.745330   2.185401   1.606084 
##     denies  last_hits 
##   1.827827  14.395207

4.2 Passo 2 - Elimando a variável “level”

modelo_teste = glm(gold_per_min~ gold+ gold_spent+xp_per_min+
               kills+deaths+assists+denies+last_hits, data = df_new,
             family = inverse.gaussian(link = "identity"))
vif_values <- vif(modelo_teste)

# Gráfico
barplot(vif_values, main = "VIF Values", horiz = TRUE, col = "steelblue")
abline(v = 5, lwd = 3, lty = 2)

vif_values
##       gold gold_spent xp_per_min      kills     deaths    assists     denies 
##   3.819012  24.165347  10.005384   5.383218   2.123729   1.325083   1.808116 
##  last_hits 
##  14.027769

4.3 Passo 3 - Elimando a variável “gold_spent”

modelo_teste = glm(gold_per_min~ gold+xp_per_min+
               kills+deaths+assists+denies+last_hits, data = df_new,
             family = inverse.gaussian(link = "identity"))
vif_values <- vif(modelo_teste)

# Gráfico
barplot(vif_values, main = "VIF Values", horiz = TRUE, col = "steelblue")
abline(v = 5, lwd = 3, lty = 2)

vif_values
##       gold xp_per_min      kills     deaths    assists     denies  last_hits 
##   3.478835  10.141891   3.873991   2.038699   1.275237   1.803701   5.491863

4.4 Passo 4 - Elimando a variável “xp_per_min”

modelo_teste = glm(gold_per_min~ gold+
               kills+deaths+assists+denies+last_hits, data = df_new,
             family = inverse.gaussian(link = "identity"))
vif_values <- vif(modelo_teste)

# Gráfico
barplot(vif_values, main = "VIF Values", horiz = TRUE, col = "steelblue")
abline(v = 5, lwd = 3, lty = 2)

vif_values
##      gold     kills    deaths   assists    denies last_hits 
##  3.367723  2.060466  1.864974  1.196995  1.802079  2.840848

     Neste caso, o modelo ideal seria o encontrado no passo 4, onde as variáveis apresentaram valores abaixo de 5. Porém, em relação ao AIC o mesmo aumentou após estre processo e o pseudo \(R^{2}\) de McFadden diminui bastante.

5 Aplicação do StepAIC e comparação

     Agora, com a remoção das variáveis que possuiam algum nível de multicolinearidade, iremos aplicar o algoritimo de Stepwise, onde o mesmo irá tentar encontrar o modelo mais parcimonioso possível.

5.1 StepAIC para a Normal Inversa

     Verificando o novo modelo ajustado:

modelo_invG_2 = glm(gold_per_min~ gold+
               kills+deaths+assists+denies+last_hits, data = df_new,
             family = inverse.gaussian(link = "identity"))
summary(modelo_invG_2)
## 
## Call:
## glm(formula = gold_per_min ~ gold + kills + deaths + assists + 
##     denies + last_hits, family = inverse.gaussian(link = "identity"), 
##     data = df_new)
## 
## Deviance Residuals: 
##        Min          1Q      Median          3Q         Max  
## -0.0094036  -0.0009933   0.0000673   0.0008593   0.0089593  
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 109.63523   29.82459   3.676 0.000378 ***
## gold          0.07993    0.01219   6.558 2.22e-09 ***
## kills         7.62907    0.97828   7.798 5.31e-12 ***
## deaths        0.89421    2.20212   0.406 0.685534    
## assists       0.14328    0.67818   0.211 0.833096    
## denies       -0.90686    0.94979  -0.955 0.341914    
## last_hits     0.69941    0.04549  15.374  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for inverse.gaussian family taken to be 4.472611e-06)
## 
##     Null deviance: 0.00896339  on 109  degrees of freedom
## Residual deviance: 0.00044995  on 103  degrees of freedom
## AIC: 938.54
## 
## Number of Fisher Scoring iterations: 5

     Note que as variáveis citadas anteriormente que não constavam como significativas no modelo inicial, após a aplicação do vif e da remoção de algumas variáveis, chegamos a um modelo que melhor explica a quantida de ouro gasto por minuto, por mais que o AIC tenha aumentado.

     Aplicando o algoritmo de Stepwise:

stepAIC(modelo_invG_2)
## Start:  AIC=938.54
## gold_per_min ~ gold + kills + deaths + assists + denies + last_hits
## 
##             Df   Deviance     AIC
## - assists    1 0.00045014  936.58
## - deaths     1 0.00045070  936.70
## - denies     1 0.00045405  937.45
## <none>         0.00044995  938.54
## - gold       1 0.00066661  984.98
## - kills      1 0.00072533  998.11
## - last_hits  1 0.00154123 1180.53
## 
## Step:  AIC=936.58
## gold_per_min ~ gold + kills + deaths + denies + last_hits
## 
##             Df   Deviance     AIC
## - deaths     1 0.00045112  934.80
## - denies     1 0.00045443  935.55
## <none>         0.00045014  936.58
## - gold       1 0.00067023  984.35
## - kills      1 0.00072672  997.12
## - last_hits  1 0.00157823 1189.67
## 
## Step:  AIC=934.82
## gold_per_min ~ gold + kills + denies + last_hits
## 
##             Df   Deviance     AIC
## - denies     1 0.00045643  934.03
## <none>         0.00045112  934.82
## - gold       1 0.00071055  991.66
## - kills      1 0.00078266 1008.02
## - last_hits  1 0.00158731 1190.51
## 
## Step:  AIC=934.11
## gold_per_min ~ gold + kills + last_hits
## 
##             Df   Deviance     AIC
## <none>         0.00045643  934.11
## - gold       1 0.00071210  989.18
## - kills      1 0.00079005 1006.58
## - last_hits  1 0.00159997 1187.38
## 
## Call:  glm(formula = gold_per_min ~ gold + kills + last_hits, family = inverse.gaussian(link = "identity"), 
##     data = df_new)
## 
## Coefficients:
## (Intercept)         gold        kills    last_hits  
##    123.0099       0.0767       7.4843       0.6839  
## 
## Degrees of Freedom: 109 Total (i.e. Null);  106 Residual
## Null Deviance:       0.008963 
## Residual Deviance: 0.0004564     AIC: 934.1

     O modelo final, proposto por esse algoritmo, corresponde justamente as variáveis que deram significativas e que realmente possuem um impacto direto na explicação da variável resposta.

5.2 StepAIC para a Gamma

     Fazendo o mesmo processo para a distribuição Gamma, teremos:

modelo_gm2 = glm(gold_per_min~ gold+
               kills+deaths+assists+denies+last_hits, data = df_new,
             family = Gamma(link = "identity"))
summary(modelo_gm2)
## 
## Call:
## glm(formula = gold_per_min ~ gold + kills + deaths + assists + 
##     denies + last_hits, family = Gamma(link = "identity"), data = df_new)
## 
## Deviance Residuals: 
##       Min         1Q     Median         3Q        Max  
## -0.179887  -0.018979   0.002743   0.018119   0.214915  
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 104.38107   31.19229   3.346  0.00114 ** 
## gold          0.08377    0.01250   6.699 1.14e-09 ***
## kills         7.47284    1.02339   7.302 6.16e-11 ***
## deaths        1.22853    2.33405   0.526  0.59978    
## assists      -0.04155    0.72346  -0.057  0.95431    
## denies       -1.12256    0.96202  -1.167  0.24596    
## last_hits     0.69874    0.04766  14.660  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for Gamma family taken to be 0.001927693)
## 
##     Null deviance: 3.58498  on 109  degrees of freedom
## Residual deviance: 0.19446  on 103  degrees of freedom
## AIC: 947.77
## 
## Number of Fisher Scoring iterations: 5

     Aqui também verificamos as mesmas variáveis explicativas significantes, seguindo para a aplicação do algortimo de Stepwise:

stepAIC(modelo_gm2)
## Start:  AIC=947.77
## gold_per_min ~ gold + kills + deaths + assists + denies + last_hits
## 
##             Df Deviance     AIC
## - assists    1  0.19446  945.77
## - deaths     1  0.19499  946.04
## - denies     1  0.19710  947.14
## <none>          0.19446  947.77
## - gold       1  0.28859  994.60
## - kills      1  0.29799  999.47
## - last_hits  1  0.61504 1163.95
## 
## Step:  AIC=945.77
## gold_per_min ~ gold + kills + deaths + denies + last_hits
## 
##             Df Deviance     AIC
## - deaths     1  0.19500  944.05
## - denies     1  0.19710  945.15
## <none>          0.19446  945.77
## - gold       1  0.28952  993.54
## - kills      1  0.29941  998.72
## - last_hits  1  0.63370 1173.76
## 
## Step:  AIC=944.07
## gold_per_min ~ gold + kills + denies + last_hits
## 
##             Df Deviance     AIC
## - denies     1  0.19828  943.80
## <none>          0.19500  944.07
## - gold       1  0.30388  999.28
## - kills      1  0.32074 1008.13
## - last_hits  1  0.63670 1174.14
## 
## Step:  AIC=943.91
## gold_per_min ~ gold + kills + last_hits
## 
##             Df Deviance     AIC
## <none>          0.19828  943.91
## - gold       1  0.30472  996.82
## - kills      1  0.32314 1006.32
## - last_hits  1  0.64222 1170.94
## 
## Call:  glm(formula = gold_per_min ~ gold + kills + last_hits, family = Gamma(link = "identity"), 
##     data = df_new)
## 
## Coefficients:
## (Intercept)         gold        kills    last_hits  
##   119.62781      0.07947      7.28254      0.68190  
## 
## Degrees of Freedom: 109 Total (i.e. Null);  106 Residual
## Null Deviance:       3.585 
## Residual Deviance: 0.1983    AIC: 943.9

     Chegamos as mesmas variáveis, o modelo mais parcimonioso encontrado pela metodologia acima será composto pelas variáveis: gold, kills e o last_hits.

5.3 Comparação

# AIC
invg_aic_2 = modelo_invG_3$aic
gm_aic_2 = modelo_gm3$aic

# McFadden
invg_pR2_2 = pR2(modelo_invG_3)[[4]]
## fitting null model for pseudo-r2
gm_pR2_2 = pR2(modelo_gm3)[[4]]
## fitting null model for pseudo-r2
normal_inv_2 = c(invg_pR2_2,invg_aic_2)
gamma_2 = c(gm_pR2_2,gm_aic_2)

tabela_comp_2 = rbind(normal_inv_2,gamma_2)
colnames(tabela_comp_2) = c("McFadden","AIC")

kable(tabela_comp_2, align = 'l',
      caption = "tabela 3: Comparação pós análise de multicolinearidade e da aplicação do Stepwise.")
tabela 3: Comparação pós análise de multicolinearidade e da aplicação do Stepwise.
McFadden AIC
normal_inv_2 0.2616762 934.1091
gamma_2 0.2546036 943.9097

     Aqui vemos que o melhor modelo continua sendo o realizado com base na Normal Inversa, possuindo um AIC mais baixo e um pseudo-\(R^{2}\) maior que o da distribuiçã Gamma.

6 Análise de Resíduos

6.1 Normal Inversa

qr <- statmod::qresiduals(modelo_invG_3) 

par(mfrow = c(2,2))
hist( qr , main = 'Histograma')
qqnorm(qr) 
qqline( qr, col = 'red' )
plot(qr, main = 'Resíduos quantílico')
abline(h = 2)
abline(h = -2)
plot( modelo_invG_2$fitted.values, qr,  xlab = 'Valores preditos', ylab = 'resíduos' )

Distância de cook’s: Verificando possíveis pontos influentes:

cooksD = cooks.distance(modelo_invG_2)
n <- nrow(df_new)
plot(cooksD, main = "Cooks Distance for Influential Obs")
abline(h = 4/n, lty = 2, col = "steelblue") # add cutoff line

Retirando valores influentes

influential_obs <- as.numeric(names(cooksD)[(cooksD > (4/n))])
df_new2_inv <- df_new[-influential_obs, ]


modelo_invG_4 = glm(gold_per_min~ gold+
               kills + last_hits, data = df_new2_inv,
             family = inverse.gaussian(link = "identity"))
summary(modelo_invG_4)
## 
## Call:
## glm(formula = gold_per_min ~ gold + kills + last_hits, family = inverse.gaussian(link = "identity"), 
##     data = df_new2_inv)
## 
## Deviance Residuals: 
##        Min          1Q      Median          3Q         Max  
## -0.0027114  -0.0007227  -0.0001992   0.0009150   0.0060196  
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 1.622e+02  9.931e+00  16.332  < 2e-16 ***
## gold        4.670e-02  6.997e-03   6.675 1.35e-09 ***
## kills       8.375e+00  5.407e-01  15.489  < 2e-16 ***
## last_hits   7.544e-01  2.789e-02  27.051  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for inverse.gaussian family taken to be 1.616532e-06)
## 
##     Null deviance: 0.00788389  on 104  degrees of freedom
## Residual deviance: 0.00015931  on 101  degrees of freedom
## AIC: 785.58
## 
## Number of Fisher Scoring iterations: 3

6.2 Gamma

qr <- statmod::qresiduals(modelo_gm3) 

par(mfrow = c(2,2))
hist( qr , main = 'Histograma')
qqnorm(qr) 
qqline( qr, col = 'red' )
plot(qr, main = 'Resíduos quantílico')
abline(h = 2)
abline(h = -2)
plot( modelo_gm3$fitted.values, qr,  xlab = 'Valores preditos', ylab = 'resíduos' )

Distância de cook’s: Verificando possíveis pontos influentes:

cooksD = cooks.distance(modelo_gm3)
n <- nrow(df_new)
plot(cooksD, main = "Cooks Distance for Influential Obs")
abline(h = 4/n, lty = 2, col = "steelblue") # add cutoff line

Retirando valores influentes

influential_obs <- as.numeric(names(cooksD)[(cooksD > (4/n))])
df_new2_gm <- df_new[-influential_obs, ]


modelo_gm4 = glm(gold_per_min~ gold+
               kills + last_hits, data = df_new2_gm,
             family = Gamma(link = "identity"))
summary(modelo_gm4)
## 
## Call:
## glm(formula = gold_per_min ~ gold + kills + last_hits, family = Gamma(link = "identity"), 
##     data = df_new2_gm)
## 
## Deviance Residuals: 
##       Min         1Q     Median         3Q        Max  
## -0.059805  -0.013476  -0.002493   0.019393   0.046972  
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 1.691e+02  8.737e+00  19.358  < 2e-16 ***
## gold        4.210e-02  6.219e-03   6.769 8.96e-10 ***
## kills       8.339e+00  4.904e-01  17.003  < 2e-16 ***
## last_hits   7.664e-01  2.422e-02  31.643  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for Gamma family taken to be 0.0004918886)
## 
##     Null deviance: 3.047157  on 103  degrees of freedom
## Residual deviance: 0.049262  on 100  degrees of freedom
## AIC: 752.24
## 
## Number of Fisher Scoring iterations: 3

6.3 Comparação

## fitting null model for pseudo-r2
## fitting null model for pseudo-r2
tabela 4: Comparação pós análise resíduos e retirados de dados influentes.
McFadden AIC
normal_inv_3 0.3456451 785.5814
gamma_3 0.3665368 752.2424

     Portanto, nesta comparação final, notamos que o modelo com a distribuição Gamma, após a retirada dos pontos influentes, mostrou-se com o melhor ajuste em comparação com a Normal Inversa.

     Com base nisso, ambas os dois modelos se mostraram bem ajustados com uma diferença bem pequena entre eles,

6.4 Gamma pós retirada dados influentes

qr <- statmod::qresiduals(modelo_gm4) 

par(mfrow = c(2,2))
hist( qr , main = 'Histograma')
qqnorm(qr) 
qqline( qr, col = 'red' )
plot(qr, main = 'Resíduos quantílico')
abline(h = 2)
abline(h = -2)
plot( modelo_gm4$fitted.values, qr,  xlab = 'Valores preditos', ylab = 'resíduos' )

Teste de normalidade dos resíduos      Para a aplicação do teste de normalidade via Shapiro-Wilk, onde iremos testar as hipóteses:

  • \(H_{0}\): Os resíduos seguem uma distribuição normal;
  • \(H_{1}\): Os resíduos não seguem uma distribuição normal;

onde iremos rejeitar \(H_{0}\) quando o valor do p-value do teste for menor que 5% de significância, portanto:

shapiro.test(modelo_gm4$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  modelo_gm4$residuals
## W = 0.98567, p-value = 0.3277

     Como o valor do p-value do teste é maior que 5% de significância, assumimos que existem evidências suficientes que mostram que os resíduos seguem uma distribuição normal.