Lo primero que tenemos que hacer para comenzar a analizar el dataset de datos 2015 de los equipos de futbol, es cargarlos.
# Carga de datos
datos_2015 <- read.csv2("datos_2015.csv", encoding = "latin1")
datos_2015$valor <- as.numeric(as.character(datos_2015$valor))
Al cargar la base de datos vemos que tiene una dimensión de 30 observaciones o filas y de 49 variables o columnas. Las columas tiene los siguientes nombres:
names(datos_2015)
## [1] "club" "Pts_2012_13" "Pts_2013_14"
## [4] "Pts_2014" "inversion_abs" "inversion_relativa"
## [7] "valor" "libertadores" "sudamericana"
## [10] "ascenso" "Pos" "Pts"
## [13] "PJ" "PG" "PE"
## [16] "PP" "GF" "GC"
## [19] "Dif" "Pos_Fecha_1" "Pos_Fecha_2"
## [22] "Pos_Fecha_3" "Pos_Fecha_4" "Pos_Fecha_5"
## [25] "Pos_Fecha_6" "Pos_Fecha_7" "Pos_Fecha_8"
## [28] "Pos_Fecha_9" "Pos_Fecha_10" "Pos_Fecha_11"
## [31] "Pos_Fecha_12" "Pos_Fecha_13" "Pos_Fecha_14"
## [34] "Pos_Fecha_15" "Pos_Fecha_16" "Pos_Fecha_17"
## [37] "Pos_Fecha_18" "Pos_Fecha_19" "Pos_Fecha_20"
## [40] "Pos_Fecha_21" "Pos_Fecha_22" "Pos_Fecha_23"
## [43] "Pos_Fecha_24" "Pos_Fecha_25" "Pos_Fecha_26"
## [46] "Pos_Fecha_27" "Pos_Fecha_28" "Pos_Fecha_29"
## [49] "Pos_Fecha_30"
Así vemos que la base de datos tiene el nombre del club de futbol correspondiente en la variable club, y luego los puntos que obtuvieron esos clubes en los torneos 2012/13, 2013/14 y 2014 (cuando no participó de ellos se indica 0 puntos), luego las variables relacionadas con la inversión del club, absoluta y relativa, y el valor del equipo. Luego la variable libertadores y sudamericana sobre si jugaron esas copas durante 2015, la variable ascenso sobre si esos equipos ascendieron en el 2014 (y el del 2015 fue su primer torneo en la primera); luego la Posición final en el torneo 2015 (Pos), con la cantidad de Puntos (Pts); Partidos Jugados (PJ), ganados (PG), empatados (PE), perdidos (PP), goles a favor (GF), goles en contra (GC), y diferencia de goles (Dif).
Luego, 30 columnas con las posiciones de cada equipo en las distintas fechas.
Podemos ver quienes cómo fueron los resultados, en la tabla de posiciones, ordenada por posición final:
datos_ordenados <- datos_2015 %>%
arrange(Pos) %>%
select(club, Pts, Pos, PG, PE, PP, GF, GC, Dif, libertadores, sudamericana)
knitr::kable(datos_ordenados) %>%
kable_styling(bootstrap_options = "striped", full_width = F)
| club | Pts | Pos | PG | PE | PP | GF | GC | Dif | libertadores | sudamericana |
|---|---|---|---|---|---|---|---|---|---|---|
| Boca Juniors | 64 | 1 | 20 | 4 | 6 | 49 | 26 | 23 | 1 | 0 |
| San Lorenzo | 61 | 2 | 18 | 7 | 5 | 44 | 20 | 24 | 1 | 0 |
| Rosario Central | 59 | 3 | 16 | 11 | 3 | 47 | 26 | 21 | 0 | 0 |
| Racing | 57 | 4 | 16 | 9 | 5 | 40 | 23 | 17 | 1 | 0 |
| Independiente | 54 | 5 | 14 | 12 | 4 | 44 | 22 | 22 | 0 | 1 |
| Belgrano | 51 | 6 | 14 | 9 | 7 | 33 | 23 | 10 | 0 | 1 |
| Estudiantes | 51 | 7 | 14 | 9 | 7 | 34 | 28 | 6 | 1 | 0 |
| Banfield | 50 | 8 | 14 | 8 | 8 | 38 | 32 | 6 | 0 | 0 |
| River Plate | 49 | 9 | 13 | 10 | 7 | 46 | 33 | 13 | 1 | 1 |
| Tigre | 46 | 10 | 12 | 10 | 8 | 32 | 25 | 7 | 0 | 1 |
| Quilmes | 45 | 11 | 13 | 6 | 11 | 38 | 37 | 1 | 0 | 0 |
| Gimnasia y Esgrima | 44 | 12 | 12 | 8 | 10 | 41 | 38 | 3 | 0 | 0 |
| Lanús | 42 | 13 | 10 | 12 | 8 | 33 | 29 | 4 | 0 | 1 |
| Unión | 41 | 14 | 9 | 14 | 7 | 38 | 37 | 1 | 0 | 0 |
| Aldosivi | 40 | 15 | 11 | 7 | 12 | 37 | 40 | -3 | 0 | 0 |
| Newell’s Old Boys | 40 | 16 | 10 | 10 | 10 | 27 | 30 | -3 | 0 | 0 |
| San Martín (SJ) | 37 | 17 | 8 | 13 | 9 | 32 | 34 | -2 | 0 | 0 |
| Olimpo | 36 | 18 | 8 | 12 | 10 | 23 | 26 | -3 | 0 | 0 |
| Colón | 34 | 19 | 7 | 13 | 10 | 26 | 31 | -5 | 0 | 0 |
| Argentinos Juniors | 33 | 20 | 8 | 9 | 13 | 30 | 38 | -8 | 0 | 0 |
| Defensa y Justicia | 32 | 21 | 8 | 8 | 14 | 27 | 31 | -4 | 0 | 0 |
| Godoy Cruz | 32 | 22 | 8 | 8 | 14 | 32 | 40 | -8 | 0 | 0 |
| Huracán | 30 | 23 | 6 | 12 | 12 | 29 | 37 | -8 | 1 | 1 |
| Sarmiento | 30 | 24 | 7 | 9 | 14 | 24 | 34 | -10 | 0 | 0 |
| Temperley | 30 | 25 | 6 | 12 | 12 | 19 | 29 | -10 | 0 | 0 |
| Nueva Chicago | 29 | 26 | 7 | 8 | 15 | 29 | 38 | -9 | 0 | 0 |
| Vélez | 29 | 27 | 7 | 8 | 15 | 27 | 37 | -10 | 0 | 0 |
| Arsenal | 27 | 28 | 7 | 6 | 17 | 25 | 44 | -19 | 0 | 1 |
| Atlético de Rafaela | 23 | 29 | 4 | 11 | 15 | 29 | 51 | -22 | 0 | 0 |
| Crucero del Norte | 14 | 30 | 3 | 5 | 22 | 21 | 55 | -34 | 0 | 0 |
De esta tabla se desprende que Boca Juniors quedó en el primer lugar, y Crucero del Norte en el último.
Podemos analizar las trayectorias de los primeros y de los últimos cinco a lo largo de las distintas fechas.
xfecha <- datos_2015 %>%
arrange(Pos) %>%
slice(1:5) %>%
select(club, Pos_Fecha_1:Pos_Fecha_30) %>%
gather(key = fecha, value = "Posicion", Pos_Fecha_1:Pos_Fecha_30)
xfecha <- xfecha %>%
mutate(fecha = as.numeric(str_replace(fecha, pattern = "Pos_Fecha_", replacement = "")))
ggplot(data = xfecha) +
geom_path(aes(y = Posicion, x = fecha, group = club, color = club), size = 1.2)+
labs(title = "Trayectoria de los primeros 5 equipos",
subtitle = "Torneo 2015", x = "Fecha", y = "Posición")+
scale_y_reverse()+
theme_bw()
Y la trayectoria de los cinco últimos
xfecha2 <- datos_2015 %>%
arrange(desc(Pos)) %>%
slice(1:5) %>%
select(club, Pos_Fecha_1:Pos_Fecha_30) %>%
gather(key = fecha, value = "Posicion", Pos_Fecha_1:Pos_Fecha_30)
xfecha2 <- xfecha2 %>%
mutate(fecha = as.numeric(str_replace(fecha, pattern = "Pos_Fecha_", replacement = "")))
ggplot(data = xfecha2) +
geom_path(aes(y = Posicion, x = fecha, group = club, color = club), size = 1.2)+
labs(title = "Trayectoria de los últimos 5 equipos",
subtitle = "Torneo 2015", x = "Fecha", y = "Posición")+
scale_y_reverse()+
theme_bw()
Con respecto a los puntos de los distintos equipos, podemos ver el siguiente análisis
summary(datos_2015$Pts)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 14.00 30.50 40.00 40.33 49.75 64.00
sd(datos_2015$Pts)
## [1] 12.14661
Así, el promedio de puntos en el torneo fue de 40.33 y el desvío estandar de 12.15. Y podemos hacer un gráfico. Parece una distribución normal, pero cuando ampliamos la cantidad de breaks no es tan acampanadada…
par(mfrow = c(1,2))
hist(datos_2015$Pts, breaks = 5, xlab = "Puntos", main = "Histograma breaks = 5",
col = "lightblue")
hist(datos_2015$Pts, breaks = 10, xlab = "Puntos", main = "Histograma breaks = 10",
col = "lightblue")
También podemos hacer un plot con la dispersión de puntos del promedio (marcamos también los dos desvíos estandar del promedio)
ggplot(data = datos_ordenados)+
geom_point (aes(x = Pts, y = reorder(club, Pts)))+
geom_vline(xintercept = mean(datos_2015$Pts), color = "red")+
geom_vline(xintercept = c(mean(datos_2015$Pts)+ 2*sd(datos_2015$Pts),
mean(datos_2015$Pts)- 2*sd(datos_2015$Pts)),
color = "red", linetype = 2)+
geom_vline(xintercept = c(mean(datos_2015$Pts)+ 1*sd(datos_2015$Pts),
mean(datos_2015$Pts)- 1*sd(datos_2015$Pts)),
color = "red", linetype = 3)+
labs(title = "Puntajes del torneo 2015",
subtitle = "Promedio y 1 y 2 desvío estándares", x = "Puntos", y = "Club")+
theme_bw()
Usar una reg. lineal para explicar la variable Pts (puntos) a partir de las variables Pts_2012_13, Pts_2013_14,Pts_2014, inversion_abs (inversión absoluta), inversion_relativa (inversión relativa), valor (valor en millones deeuros), libertadores (si participó en el 2015 en la Copa Libertadores), sudamericana (si participó en el 2015 en laCopa Sudamericana), ascenso (si ascendió).
Comenzaré por regresiones lineales simples. Primero voy a realizar tres regresiones para analizar si existe relación entre los puntos obtenidos en el torneo 2015, y los puntos obtenidos por el mismo equipo en los torneos 2012_13, 2013_14, y 2014. Para ello, deberé primero filtrar de la regresión los equipos que no jugaron esos torneos, por lo que figuran con 0 puntos (por ello los convierto a NA).
datos_regresiones <- datos_2015 %>%
select(club, Pts, Pts_2012_13, Pts_2013_14, Pts_2014) %>%
na_if(0)
regresion_2012 <- lm(Pts ~ Pts_2012_13, data = datos_regresiones)
regresion_2013 <- lm(Pts ~ Pts_2013_14, data = datos_regresiones)
regresion_2014 <- lm(Pts ~ Pts_2014, data = datos_regresiones)
par(mfrow = c(2,2))
plot(y = datos_regresiones$Pts, x = datos_regresiones$Pts_2012_13,
ylab = "Torneo 2015", xlab = "Torneo 2012/2013")
abline(regresion_2012, lwd = 3, col = "red")
plot(y = datos_regresiones$Pts, x = datos_regresiones$Pts_2013_14,
ylab = "Torneo 2015", xlab = "Torneo 2013/2014")
abline(regresion_2013, lwd = 3, col = "red")
plot(y = datos_regresiones$Pts, x = datos_regresiones$Pts_2014,
ylab = "Torneo 2015", xlab = "Torneo 2014")
abline(regresion_2014, lwd = 3, col = "red")
Luego de ver que estos gráficos señalen que probablemente no exista correlación, armo una regresión lineal múltiple, y para ver si el modelo es posible, grafico los residudos
regresion_multiple <- lm(Pts ~ Pts_2012_13 + Pts_2013_14 + Pts_2014,
data = datos_regresiones)
tab_model(regresion_multiple,
show.se = TRUE, show.df = TRUE, show.stat = TRUE, show.ci = FALSE, show.fstat = TRUE)
| Pts | ||||
|---|---|---|---|---|
| Predictors | Estimates | std. Error | Statistic | p |
| (Intercept) | 27.20 | 31.46 | 0.86 | 0.408 |
| Pts_2012_13 | -0.11 | 0.38 | -0.30 | 0.774 |
| Pts_2013_14 | 0.07 | 0.47 | 0.15 | 0.881 |
| Pts_2014 | 0.70 | 0.54 | 1.30 | 0.223 |
| Observations | 14 | |||
| R2 / adjusted R2 | 0.147 / -0.109 | |||
par(mfrow = c(2,2))
plot(regresion_multiple)
Lamentablemente, estos diagnosticos nos indican que este modelo lineal no es satisfactorio. Especialmente la distribución de los residuos en el plot 1, donde la distribución no es regular al rededor de la línea, indicándonos que probablemente no sea una regresióin lineal, o que este modelo no encaja. Lo mismo sucede con el estadístico \(R^2\), que al ser muy bajo (0.1468036) nos señala que el modelo tiene problemas.
Podemos pensar otra regresión con otras variables. Por ejemplo, ¿existe alguna relación en el valor del equipo y los puntos que obtiene? Es decir, ¿la inversión en jugadores de futbol repercute en cuántos puntos obtiene el club en el torneo? Analicemos eso.
regresion_valor <- lm(Pts ~ valor, data = datos_2015)
plot(y = datos_2015$Pts, x = datos_2015$valor,
ylab = "Puntos torneo 2015", xlab = "Valor del club")
abline(regresion_valor, lwd = 3, col = "red")
tab_model(regresion_valor,
show.se = TRUE, show.df = TRUE, show.stat = TRUE, show.ci = FALSE, show.fstat = TRUE)
| Pts | ||||
|---|---|---|---|---|
| Predictors | Estimates | std. Error | Statistic | p |
| (Intercept) | 29.66 | 3.12 | 9.49 | <0.001 |
| valor | 0.71 | 0.17 | 4.15 | <0.001 |
| Observations | 30 | |||
| R2 / adjusted R2 | 0.381 / 0.359 | |||
Y analizamos los residuos
par(mfrow = c(2,2))
plot(regresion_valor)
Si bien existe correlación significativa, los residuos nos señalan que el modelo no es perfecto. Podríamos intentar algunas tranformaciones a ver si mejora. El valor, que está en dinero podemos transformarlo con el logaritmo. Y los puntos los podemos transformar con raíz cuadrada.
datos_transf <- data.frame(datos_2015$Pts, datos_2015$valor,
"sqrt.Pts" = sqrt(datos_2015$Pts),
"log.valor" = log10(datos_2015$valor)) %>%
arrange(desc(datos_2015.Pts))
kable(datos_transf) %>%
kable_styling(bootstrap_options = "striped", full_width = F)
| datos_2015.Pts | datos_2015.valor | sqrt.Pts | log.valor |
|---|---|---|---|
| 64 | 38.83 | 8.000000 | 1.5891674 |
| 61 | 37.85 | 7.810250 | 1.5780659 |
| 59 | 16.33 | 7.681146 | 1.2129862 |
| 57 | 19.40 | 7.549834 | 1.2878017 |
| 54 | 16.90 | 7.348469 | 1.2278867 |
| 51 | 20.15 | 7.141428 | 1.3042751 |
| 51 | 8.78 | 7.141428 | 0.9434945 |
| 50 | 16.93 | 7.071068 | 1.2286570 |
| 49 | 43.40 | 7.000000 | 1.6374897 |
| 46 | 13.95 | 6.782330 | 1.1445742 |
| 45 | 13.23 | 6.708204 | 1.1215598 |
| 44 | 10.33 | 6.633250 | 1.0141003 |
| 42 | 18.32 | 6.480741 | 1.2629255 |
| 41 | 6.58 | 6.403124 | 0.8182259 |
| 40 | 6.73 | 6.324555 | 0.8280151 |
| 40 | 32.56 | 6.324555 | 1.5126844 |
| 37 | 6.83 | 6.082763 | 0.8344207 |
| 36 | 10.00 | 6.000000 | 1.0000000 |
| 34 | 8.55 | 5.830952 | 0.9319661 |
| 33 | 14.48 | 5.744563 | 1.1607686 |
| 32 | 13.08 | 5.656854 | 1.1166077 |
| 32 | 6.90 | 5.656854 | 0.8388491 |
| 30 | 9.63 | 5.477226 | 0.9836263 |
| 30 | 6.20 | 5.477226 | 0.7923917 |
| 30 | 3.38 | 5.477226 | 0.5289167 |
| 29 | 3.75 | 5.385165 | 0.5740313 |
| 29 | 20.00 | 5.385165 | 1.3010300 |
| 27 | 14.28 | 5.196152 | 1.1547282 |
| 23 | 8.58 | 4.795832 | 0.9334873 |
| 14 | 4.43 | 3.741657 | 0.6464037 |
Y hago un gráfico, a ver si mejoró y ploteo los graficos de diagnostico.
regresion_transf <- lm(sqrt.Pts ~ log.valor, data = datos_transf)
plot(y = datos_transf$sqrt.Pts, x = datos_transf$log.valor,
ylab = "Raíz cuadrada de Puntos", xlab = "Logaritmo de valor")
abline(regresion_transf, lwd = 3, col = "red")
tab_model(regresion_transf,
show.se = TRUE, show.df = TRUE, show.stat = TRUE, show.ci = FALSE, show.fstat = TRUE)
| sqrt.Pts | ||||
|---|---|---|---|---|
| Predictors | Estimates | std. Error | Statistic | p |
| (Intercept) | 3.89 | 0.55 | 7.10 | <0.001 |
| log.valor | 2.20 | 0.49 | 4.51 | <0.001 |
| Observations | 30 | |||
| R2 / adjusted R2 | 0.421 / 0.400 | |||
#residudos
par(mfrow = c(2,2))
plot(regresion_transf)
Este modelo encaja mucho mejor!
Luego de las transformaciones, vimos que nuestra regresión es de un modelo lineal, con la siguiente fórmula.
\(y = \beta{_0} + \beta{_1}x\)
\(\sqrt{(Pts)} = intercept + pendiente*\log({valor})\)
\(\sqrt{(Pts)} = 3.88 + 2.22* \log(valor)\)
Y en base a esto, para calcular el intervalo de confianza podemos utilizar la técnica de Boostrap no paramétrico. Para ello, haremos una tabla con 10.000 replicaciones de \(\beta{_0}\) y de \(\beta{_1}\).
#funcion que reordena y recalcula la regresion
set.seed(999)
regresiones <- function(X,Y){
boot <- sample.int(n = nrow(datos_transf), size = nrow(datos_transf), replace = TRUE)
boot_fit <- lm(sqrt.Pts ~ log.valor, data=datos_transf[boot,])
return(coef(boot_fit))
}
# matriz de 10000 replicaciones de los coeficientes de la regresion
boot <- t(replicate(10000,regresiones(X,Y)))
head(boot, 10) %>%
kable() %>%
kable_styling(bootstrap_options = "striped", full_width = F)
| (Intercept) | log.valor |
|---|---|
| 3.724547 | 2.469323 |
| 4.185238 | 1.989383 |
| 4.045299 | 2.048250 |
| 4.070316 | 2.117026 |
| 4.079419 | 1.906992 |
| 3.921058 | 2.149061 |
| 4.475351 | 1.748147 |
| 3.705875 | 2.406653 |
| 4.439895 | 1.756008 |
| 3.405725 | 2.703779 |
El promedio de la intercepción nos da 3.892, y de la pendiente 2.201. Esto es bastante similar de nuestros valores originales ( que eran 3.888, 2.204).
Y podemos graficarlo
par(mfrow=c(1,2))
MASS::truehist(boot[,1], main = "Boostrap del intercept", xlab = "intercept")
abline(v =median(boot[,1]), col = "red", lty = 2)
MASS::truehist(boot[,2], main = "Boostrap de la pendiente", xlab = "pendiente")
abline(v = median(boot[,2]), col = "red", lty = 2)
Luego, un gráfico de la regresión
plot(x = boot[,2], y = boot[,1], pch=19, cex=0.1,
ylab = "Intercept", xlab = "pendiente",
main = "Scaterplot del Boostrap de la regresión")
Y calcular el Intervalo de confianza para cada parámetro debemos analizar los quartiles de los parametros.
# Intervalos de Confianza para beta_0
beta0 <- quantile(boot[,1], p= c(.025,.25,.5,.75,.975))
beta1 <- quantile(boot[,2], p= c(.025,.25,.5,.75,.975))
kable(list(beta0, beta1)) %>%
kable_styling(bootstrap_options = "striped", full_width = F)
|
|
De este modo, el intervalo del 95% de confianza para la intercepción va de 2.7554875 a 4.864679; y el de la pendiente va de 1.3071572 a 3.1945521.
Para el modelo elegido, ¿se puede decir que existe algún coeficiente de las variables explicativas estadísticamente distinto de cero? Pruebe el test de hipótesis (Busque para contextualizar en Agresti, el test F, capítulo 11, en particular 11.4 -11.5)
???