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")
| 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." )
|
|
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")
| 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.")
| 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
| 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.