Análisis del Caso Hipotético

Este estudio de caso analiza el conjunto de datos FIFA 20 Complete Player Dataset (Leone, 2019), disponible en Kaggle. El objetivo es explorar las relaciones entre variables de habilidad de los jugadores de fútbol, construir modelos de regresión lineal simple para modelar la relación entre tiro (shooting) y regate (dribbling), y ajustar un modelo de regresión logística para predecir el pie dominante (preferred_foot) de los jugadores.

Referencia: Leone, S. (2019). FIFA 20 complete player dataset. Kaggle.
https://www.kaggle.com/stefanoleone992/fifa-20-complete-player-dataset


Exploración de Datos

Carga del Conjunto de Datos

# Carga de librerías necesarias
library(tidyverse)
library(ggplot2)
library(corrplot)
library(car)
library(lmtest)
library(caret)
library(knitr)
library(kableExtra)
library(gridExtra)
library(ggfortify)

# Carga del dataset
futbol_raw <- read.csv("players_15.csv", stringsAsFactors = FALSE, sep=",")

# Selección de variables requeridas por la guía
vars_seleccionadas <- c("club", "preferred_foot", "team_position", "age",
                        "height_cm", "weight_kg", "overall", "potential",
                        "value_eur", "wage_eur",
                        "shooting", "passing", "dribbling",
                        "defending", "physic", "pace")

futbol_raw <- futbol_raw[, vars_seleccionadas]

# Vista general del dataset
cat("Dimensiones del dataset:", nrow(futbol_raw), "filas x", ncol(futbol_raw), "columnas\n")
#> Dimensiones del dataset: 15465 filas x 16 columnas

Descripción de Variables

A continuación se describe cada variable del conjunto de datos:

Variable Tipo Descripción
club Categórica Nombre del club al que pertenece el jugador
preferred_foot Binaria Pie dominante del jugador: Left (izquierdo) o Right (derecho)
team_position Categórica Posición táctica del jugador en su equipo (ej. CF, ST, GK)
age Numérica Edad del jugador en años cumplidos
height_cm Numérica Estatura del jugador en centímetros
weight_kg Numérica Peso del jugador en kilogramos
overall Numérica Valoración global del jugador (0–99), refleja su nivel actual
potential Numérica Potencial máximo que podría alcanzar el jugador (0–99)
value_eur Numérica Valor de mercado estimado del jugador en euros
wage_eur Numérica Salario semanal del jugador en euros
shooting Numérica Habilidad de tiro del jugador (0–99)
passing Numérica Habilidad de pase del jugador (0–99)
dribbling Numérica Habilidad de regate del jugador (0–99)
defending Numérica Habilidad defensiva del jugador (0–99)
physic Numérica Atributo físico del jugador (resistencia, fuerza) (0–99)
pace Numérica Velocidad del jugador (0–99)

Verificación de Datos Faltantes

# Contar NA por variable
# Contar NA por variable y mostrar tabla

cat("Dimensiones originales:", nrow(futbol_raw), "filas x", ncol(futbol_raw), "columnas\n")
#> Dimensiones originales: 15465 filas x 16 columnas
# Eliminar filas con NAs (elimina porteros que no tienen shooting/dribbling)
futbol_150_base <- futbol_raw %>% drop_na()

cat("Filas tras eliminar NAs:", nrow(futbol_150_base), "\n")
#> Filas tras eliminar NAs: 13762
# Tomar una muestra aleatoria reproducible de 150 jugadores para el análisis
set.seed(42)
futbol_150 <- futbol_150_base %>% sample_n(150)
cat("Muestra de trabajo:", nrow(futbol_150), "jugadores\n")
#> Muestra de trabajo: 150 jugadores

Nota: Se identificaron datos faltantes principalmente en variables de habilidad (shooting, dribbling, etc.) correspondientes a porteros. Las filas con valores NA fueron eliminadas para garantizar la integridad del análisis. Se trabaja con una muestra de 150 jugadores como indica la guía.

Análisis Exploratorio: Histograma y Boxplot

Variable shooting (Tiro)

p1 <- ggplot(futbol_150, aes(x = shooting)) +
  geom_histogram(bins = 20, fill = "#1a5276", color = "white", alpha = 0.85) +
  geom_vline(aes(xintercept = mean(shooting)), color = "#e74c3c", 
             linetype = "dashed", linewidth = 1) +
  labs(title = "Histograma - Shooting",
       x = "Puntuación de Tiro", y = "Frecuencia") +
  theme_minimal(base_size = 11) +
  annotate("text", x = mean(futbol_150$shooting) + 5, 
           y = 18, label = paste0("Media = ", round(mean(futbol_150$shooting), 1)),
           color = "#e74c3c", size = 3.5)

p2 <- ggplot(futbol_150, aes(y = shooting)) +
  geom_boxplot(fill = "#1a5276", alpha = 0.7, outlier.color = "#e74c3c",
               outlier.shape = 16, outlier.size = 2) +
  labs(title = "Boxplot - Shooting", y = "Puntuación de Tiro") +
  theme_minimal(base_size = 11)

grid.arrange(p1, p2, ncol = 2)
Distribución de la variable shooting

Distribución de la variable shooting

Interpretación: La variable shooting presenta una distribución aproximadamente simétrica con media alrededor de 50.8. El boxplot revela la presencia de algunos valores atípicos en los extremos inferiores, correspondientes probablemente a porteros o jugadores defensivos con habilidades de tiro muy bajas.

Variable dribbling (Regate)

p3 <- ggplot(futbol_150, aes(x = dribbling)) +
  geom_histogram(bins = 20, fill = "#117a65", color = "white", alpha = 0.85) +
  geom_vline(aes(xintercept = mean(dribbling)), color = "#e74c3c",
             linetype = "dashed", linewidth = 1) +
  labs(title = "Histograma - Dribbling",
       x = "Puntuación de Regate", y = "Frecuencia") +
  theme_minimal(base_size = 11) +
  annotate("text", x = mean(futbol_150$dribbling) + 5,
           y = 18, label = paste0("Media = ", round(mean(futbol_150$dribbling), 1)),
           color = "#e74c3c", size = 3.5)

p4 <- ggplot(futbol_150, aes(y = dribbling)) +
  geom_boxplot(fill = "#117a65", alpha = 0.7, outlier.color = "#e74c3c",
               outlier.shape = 16, outlier.size = 2) +
  labs(title = "Boxplot - Dribbling", y = "Puntuación de Regate") +
  theme_minimal(base_size = 11)

grid.arrange(p3, p4, ncol = 2)
Distribución de la variable dribbling

Distribución de la variable dribbling

Interpretación: La variable dribbling presenta una media de r round(mean(futbol_150\(dribbling), 1) y una mediana de r round(median(futbol_150\)dribbling), 1). r ifelse(mean(futbol_150\(dribbling) > median(futbol_150\)dribbling), “La media es mayor que la mediana, lo que indica un ligero sesgo hacia la derecha.”, “La mediana es mayor que la media, lo que indica un ligero sesgo hacia la izquierda.”). El boxplot muestra valores atípicos en los extremos inferiores,correspondientes a jugadores defensivos con baja habilidad de regate.


Regresión Lineal Simple

Se modela la relación entre la habilidad de tiro (shooting, variable independiente \(X\)) y la habilidad de regate (dribbling, variable dependiente \(Y\)).

Partición Train / Test

# Semilla para reproducibilidad
set.seed(10)

# Índices de la muestra de entrenamiento (140 datos)
indices_train <- sample(1:nrow(futbol_150), 140)

# Conjunto de entrenamiento
train <- futbol_150[indices_train, ]

# Conjunto de prueba (10 datos restantes)
test  <- futbol_150[-indices_train, ]

cat("Tamaño conjunto train:", nrow(train), "\n")
#> Tamaño conjunto train: 140
cat("Tamaño conjunto test:", nrow(test), "\n")
#> Tamaño conjunto test: 10

a) Gráfico de Dispersión y Correlación

# Correlación de Pearson
correlacion <- cor(train$shooting, train$dribbling)
cat("Correlación de Pearson (shooting vs dribbling):", round(correlacion, 4), "\n")
#> Correlación de Pearson (shooting vs dribbling): 0.71
# Gráfico de dispersión
ggplot(train, aes(x = shooting, y = dribbling)) +
  geom_point(color = "#1a5276", alpha = 0.6, size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "#e74c3c", fill = "#fadbd8") +
  labs(title = "Dispersión: Shooting vs Dribbling",
       subtitle = paste0("r de Pearson = ", round(correlacion, 4)),
       x = "Shooting (Tiro)",
       y = "Dribbling (Regate)") +
  theme_minimal(base_size = 11)
Gráfico de dispersión Shooting vs Dribbling

Gráfico de dispersión Shooting vs Dribbling

Interpretación: La correlación de Pearson es r = 0.71, lo que indica una relación lineal fuerte y positiva entre las habilidades de tiro y regate. El gráfico de dispersión confirma que, en general, los jugadores con mayor capacidad de tiro también tienden a tener mejor habilidad de regate.

b) Estimación de Coeficientes de Regresión

# Ajuste del modelo de regresión lineal simple
modelo_lineal <- lm(dribbling ~ shooting, data = train)

# Resumen del modelo
summary(modelo_lineal)
#> 
#> Call:
#> lm(formula = dribbling ~ shooting, data = train)
#> 
#> Residuals:
#>     Min      1Q  Median      3Q     Max 
#> -17.917  -4.831   0.755   4.508  15.887 
#> 
#> Coefficients:
#>             Estimate Std. Error t value Pr(>|t|)    
#> (Intercept) 31.07775    2.49519   12.46   <2e-16 ***
#> shooting     0.56323    0.04755   11.85   <2e-16 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 7.415 on 138 degrees of freedom
#> Multiple R-squared:  0.5041, Adjusted R-squared:  0.5005 
#> F-statistic: 140.3 on 1 and 138 DF,  p-value: < 2.2e-16

Interpretación de coeficientes:

Coeficientes del modelo de regresión lineal
Estimado Error Estándar t-valor p-valor
(Intercept) 31.0778 2.4952 12.4551 0
shooting 0.5632 0.0476 11.8449 0
  • Intercepto (\(\beta_0\) = 31.078): Cuando el valor de shooting es 0, se estima que dribbling sería 31.078. Este valor carece de interpretación práctica real, ya que un jugador con tiro igual a 0 es un escenario hipotético.

  • Pendiente (\(\beta_1\) = 0.563): Por cada punto adicional en la habilidad de tiro, la habilidad de regate aumenta en promedio 0.563 puntos, manteniendo todo lo demás constante.

La ecuación del modelo es:

\[\widehat{\text{dribbling}} = 31.078 + 0.563 \cdot \text{shooting}\]

c) Pruebas de Hipótesis sobre los Parámetros

summary_modelo <- summary(modelo_lineal)

# p-valores
p_intercepto <- summary_modelo$coefficients[1, 4]
p_shooting   <- summary_modelo$coefficients[2, 4]

cat("Prueba H0: β0 = 0  →  p-valor =", format(p_intercepto, scientific = TRUE), "\n")
#> Prueba H0: β0 = 0  →  p-valor = 2.462055e-24
cat("Prueba H0: β1 = 0  →  p-valor =", format(p_shooting,   scientific = TRUE), "\n")
#> Prueba H0: β1 = 0  →  p-valor = 9.058402e-23

Interpretación:

  • Para el intercepto: \(H_0: \beta_0 = 0\) vs \(H_1: \beta_0 \neq 0\). Con un p-valor de 2.462055e-24, se rechaza H₀, el intercepto es estadísticamente significativo..

  • Para la pendiente: \(H_0: \beta_1 = 0\) vs \(H_1: \beta_1 \neq 0\). Con un p-valor de 9.058402e-23, se rechaza H₀, lo que significa que shooting es un predictor estadísticamente significativo de dribbling. Este resultado confirma que existe una relación lineal real entre las dos variables.

d) Coeficiente de Determinación R² y Tabla ANOVA

r2        <- summary_modelo$r.squared
r2_adj    <- summary_modelo$adj.r.squared

cat("R² =", round(r2, 4), "\n")
#> R² = 0.5041
cat("R² ajustado =", round(r2_adj, 4), "\n")
#> R² ajustado = 0.5005
# Tabla ANOVA
anova_tabla <- anova(modelo_lineal)
kable(round(anova_tabla, 4),
      caption = "Tabla ANOVA del modelo de regresión lineal",
      booktabs = TRUE) %>%
  kable_styling(latex_options = c("hold_position"), font_size = 10)
Tabla ANOVA del modelo de regresión lineal
Df Sum Sq Mean Sq F value Pr(>F)
shooting 1 7713.344 7713.344 140.3012 0
Residuals 138 7586.828 54.977 NA NA

Interpretación:

  • R² = 0.5041: El 50.41% de la variabilidad en dribbling es explicada por la variable shooting.

  • Tabla ANOVA: El estadístico F es significativo (p < 0.05), confirmando que el modelo en su conjunto es estadísticamente significativo, es decir, shooting contribuye de manera relevante a explicar dribbling.

e) ¿Es este un buen modelo?

#> R² = 0.5041 | R² ajustado = 0.5005
#> F-estadístico p-valor: 9.058402e-23

Conclusión sobre la calidad del modelo:

El modelo explica el 50.41% de la varianza de dribbling mediante shooting. Este es un valor moderado. Si bien la relación es estadísticamente significativa, el modelo simple deja una parte importante de la varianza sin explicar, lo que sugiere que existen otros factores (posición, overall, physic) que influyen en la habilidad de regate. En términos prácticos, el modelo es útil como primera aproximación pero se podría mejorar incorporando variables adicionales.

f) Análisis de Residuos

par(mfrow = c(2, 2))
plot(modelo_lineal, which = 1:4, col = "#1a5276", pch = 16, cex = 0.6)
Diagnóstico de residuos del modelo lineal

Diagnóstico de residuos del modelo lineal

par(mfrow = c(1, 1))
# Test de normalidad de Shapiro-Wilk
sw_test <- shapiro.test(residuals(modelo_lineal))
cat("Shapiro-Wilk: W =", round(sw_test$statistic, 4), 
    "| p-valor =", round(sw_test$p.value, 4), "\n")
#> Shapiro-Wilk: W = 0.9866 | p-valor = 0.1919
# Test de homocedasticidad (Breusch-Pagan)
bp_test <- bptest(modelo_lineal)
cat("Breusch-Pagan: BP =", round(bp_test$statistic, 4), 
    "| p-valor =", round(bp_test$p.value, 4), "\n")
#> Breusch-Pagan: BP = 7.0713 | p-valor = 0.0078
# Test de autocorrelación (Durbin-Watson)
dw_test <- dwtest(modelo_lineal)
cat("Durbin-Watson: DW =", round(dw_test$statistic, 4), 
    "| p-valor =", round(dw_test$p.value, 4), "\n")
#> Durbin-Watson: DW = 1.9997 | p-valor = 0.4968

Interpretación del análisis de residuos:

  • Linealidad (Residuals vs Fitted, gráfico superior izquierdo): Los residuos se distribuyen alrededor de cero sin un patrón sistemático, lo que indica que el supuesto de linealidad se cumple.

  • Normalidad (Shapiro-Wilk, p = 0.1919): No se rechaza la hipótesis de normalidad de los residuos (p > 0.05). El supuesto de normalidad se cumple.

  • Homocedasticidad (Breusch-Pagan, p = 0.0078): Se detecta heterocedasticidad (p < 0.05). La varianza de los residuos no es constante a lo largo de los valores ajustados.

  • Independencia (Durbin-Watson, DW = 1.9997, p = 0.4968): No hay evidencia de autocorrelación en los residuos (p > 0.05). El supuesto de independencia se cumple.

g) Valores Atípicos e Influyentes

# Leverage y distancia de Cook
leverage   <- hatvalues(modelo_lineal)
cook_dist  <- cooks.distance(modelo_lineal)
n          <- nrow(train)

# Umbrales
umbral_lev  <- 2 * 2 / n          # 2p/n
umbral_cook <- 4 / n              # 4/n

influyentes <- which(cook_dist > umbral_cook)
apalancados <- which(leverage > umbral_lev)

cat("Puntos con alto apalancamiento (>", round(umbral_lev, 4), "):", 
    length(apalancados), "\n")
#> Puntos con alto apalancamiento (> 0.0286 ): 8
cat("Puntos influyentes por Cook (>", round(umbral_cook, 4), "):", 
    length(influyentes), "\n")
#> Puntos influyentes por Cook (> 0.0286 ): 12
# Gráfico de Cook's Distance
plot(cook_dist, type = "h", col = "#e74c3c",
     main = "Distancia de Cook por Observación",
     xlab = "Observación", ylab = "Distancia de Cook")
abline(h = umbral_cook, col = "#1a5276", lty = 2, lwd = 2)
legend("topright", legend = paste0("Umbral = ", round(umbral_cook, 4)),
       col = "#1a5276", lty = 2, bty = "n")
Detección de valores atípicos e influyentes

Detección de valores atípicos e influyentes

# Outliers por método de Bonferroni
influenceIndexPlot(modelo_lineal, vars = "Bonf", las = 1)
Detección de valores atípicos e influyentes

Detección de valores atípicos e influyentes

# Puntos influyentes por distancia de Cook
influenceIndexPlot(modelo_lineal, vars = "Cook")
Detección de valores atípicos e influyentes

Detección de valores atípicos e influyentes

Interpretación: El gráfico de Bonferroni identifica las observaciones con residuos estudentizados más extremos, que son candidatos a valores atípicos. La distancia de Cook complementa este análisis mostrando cuáles de esas observaciones tienen además una influencia real sobre los coeficientes del modelo. Se identificaron 12 observaciones con distancia de Cook superior al umbral (4/n = 0.0286). Se recomienda revisar estos casos, pues podrían corresponder a jugadores con perfiles atípicos que afectan la pendiente de la recta de regresión.

h) Intervalos de Confianza y Predicción

# Crear secuencia de valores para la gráfica
x_seq <- data.frame(shooting = seq(min(train$shooting), max(train$shooting), length.out = 200))

# Intervalos de confianza (IC) y predicción (IP)
ic <- predict(modelo_lineal, newdata = x_seq, interval = "confidence", level = 0.95)
ip <- predict(modelo_lineal, newdata = x_seq, interval = "prediction",  level = 0.95)

# Construir dataframe para graficar
grafica_df <- data.frame(
  shooting  = x_seq$shooting,
  fit       = ic[, "fit"],
  ic_lower  = ic[, "lwr"],
  ic_upper  = ic[, "upr"],
  ip_lower  = ip[, "lwr"],
  ip_upper  = ip[, "upr"]
)

ggplot(train, aes(x = shooting, y = dribbling)) +
  geom_point(color = "#1a5276", alpha = 0.5, size = 1.8) +
  geom_ribbon(data = grafica_df, aes(x = shooting, ymin = ip_lower, ymax = ip_upper),
              inherit.aes = FALSE, fill = "#abebc6", alpha = 0.35) +
  geom_ribbon(data = grafica_df, aes(x = shooting, ymin = ic_lower, ymax = ic_upper),
              inherit.aes = FALSE, fill = "#2ecc71", alpha = 0.45) +
  geom_line(data = grafica_df, aes(x = shooting, y = fit),
            color = "#e74c3c", linewidth = 1) +
  labs(title = "Regresión Lineal con Intervalos de Confianza y Predicción",
       subtitle = "Verde oscuro: IC 95% | Verde claro: IP 95% | Línea roja: recta de regresión",
       x = "Shooting (Tiro)", y = "Dribbling (Regate)") +
  theme_minimal(base_size = 11)
Intervalos de confianza y predicción del modelo

Intervalos de confianza y predicción del modelo

Interpretación:

  • Intervalo de Confianza (IC 95% - verde oscuro): Representa la incertidumbre sobre la media de dribbling para un valor dado de shooting. Es más estrecho en el centro de los datos.

  • Intervalo de Predicción (IP 95% - verde claro): Representa la incertidumbre sobre un valor individual de dribbling. Es más amplio que el IC porque incluye la variabilidad individual alrededor de la media.

Cuanto más alejado del centro de los datos se encuentra un valor de shooting, mayor es la incertidumbre en la predicción, lo que se refleja en el ensanchamiento de ambas bandas.

i) Validación con el Conjunto Test

# Predicciones sobre el conjunto test
predicciones_test <- predict(modelo_lineal, newdata = test)

# Tabla comparativa
tabla_validacion <- data.frame(
  Shooting_test     = test$shooting,
  Dribbling_real    = test$dribbling,
  Dribbling_pred    = round(predicciones_test, 2),
  Diferencia        = round(test$dribbling - predicciones_test, 2)
)

kable(tabla_validacion,
      caption = "Comparación de valores reales vs predichos en el conjunto test",
      col.names = c("Shooting X_test", "Dribbling Y_test", "Dribbling Ŷ (modelo)", "Diferencia Y - Ŷ"),
      booktabs = TRUE,
      digits = 2) %>%
  kable_styling(latex_options = c("hold_position", "scale_down"), font_size = 10)
Comparación de valores reales vs predichos en el conjunto test
Shooting X_test Dribbling Y_test Dribbling Ŷ (modelo) Diferencia Y - Ŷ
2 53 56 60.93 -4.93
37 52 61 60.37 0.63
40 47 58 57.55 0.45
41 55 57 62.06 -5.06
44 61 58 65.43 -7.43
69 56 66 62.62 3.38
71 39 68 53.04 14.96
115 63 69 66.56 2.44
124 55 59 62.06 -3.06
126 27 33 46.28 -13.28
# Métricas de validación
mse_test  <- mean((test$dribbling - predicciones_test)^2)
rmse_test <- sqrt(mse_test)
mae_test  <- mean(abs(test$dribbling - predicciones_test))

cat("\nMetricas de error en test:\n")
#> 
#> Metricas de error en test:
cat("  MSE  =", round(mse_test, 4), "\n")
#>   MSE  = 53.2628
cat("  RMSE =", round(rmse_test, 4), "\n")
#>   RMSE = 7.2981
cat("  MAE  =", round(mae_test, 4), "\n")
#>   MAE  = 5.5621

Interpretación: El RMSE de 7.3 puntos indica que, en promedio, el modelo se equivoca en aproximadamente 7.3 puntos al predecir la habilidad de regate a partir del tiro. Dado que la escala de dribbling va de 0 a 99, este error es relativamente bajo, lo que sugiere una capacidad predictiva aceptable del modelo. Las diferencias entre valores reales y predichos muestran que el modelo no sobreajusta ni subajusta sistemáticamente en el conjunto de prueba.


Regresión Logística

Preparación de la Variable Respuesta

# Convertir preferred_foot a variable binaria (0 = Left, 1 = Right)
futbol_logit <- futbol_150 %>%
  filter(preferred_foot %in% c("Left", "Right")) %>%
  mutate(foot_bin = ifelse(preferred_foot == "Right", 1, 0))

cat("Distribución de preferred_foot:\n")
#> Distribución de preferred_foot:
print(table(futbol_logit$preferred_foot))
#> 
#>  Left Right 
#>    35   115
cat("\nProporción pie derecho:", round(mean(futbol_logit$foot_bin), 3), "\n")
#> 
#> Proporción pie derecho: 0.767

Construcción del Modelo de Regresión Logística

Dado que preferred_foot es una variable binaria (Left = 0, Right = 1), no es apropiado usar regresión lineal, ya que la recta no garantiza predicciones entre 0 y 1. La regresión logística resuelve esto mediante la función sigmoide:

\[P(Y=1|X) = \frac{e^{\beta_0 + \beta_1 X_1 + \cdots + \beta_k X_k}} {1 + e^{\beta_0 + \beta_1 X_1 + \cdots + \beta_k X_k}}\]

que siempre produce valores entre 0 y 1, interpretables como probabilidades de pertenecer a una categoría. En este caso, el modelo estima la probabilidad de que un jugador sea diestro (preferred_foot = Right) en función de su edad, peso, habilidad de tiro, pase y regate.

# Modelo de regresión logística
# Y = preferred_foot (binaria: 1 = Right, 0 = Left)
# X = age, weight_kg, shooting, passing, dribbling
modelo_logit <- glm(
  foot_bin ~ age + weight_kg + shooting + passing + dribbling,
  data   = futbol_logit,
  family = binomial(link = "logit")
)

summary(modelo_logit)
#> 
#> Call:
#> glm(formula = foot_bin ~ age + weight_kg + shooting + passing + 
#>     dribbling, family = binomial(link = "logit"), data = futbol_logit)
#> 
#> Coefficients:
#>             Estimate Std. Error z value Pr(>|z|)
#> (Intercept)  0.59202    3.34744   0.177    0.860
#> age          0.02429    0.04887   0.497    0.619
#> weight_kg    0.02769    0.03537   0.783    0.434
#> shooting     0.02382    0.02251   1.058    0.290
#> passing     -0.01250    0.03251  -0.385    0.701
#> dribbling   -0.04230    0.04010  -1.055    0.291
#> 
#> (Dispersion parameter for binomial family taken to be 1)
#> 
#>     Null deviance: 162.98  on 149  degrees of freedom
#> Residual deviance: 157.01  on 144  degrees of freedom
#> AIC: 169.01
#> 
#> Number of Fisher Scoring iterations: 4
# Validación del modelo logístico
anova(modelo_logit, test = "Chisq")

Interpretación del ANOVA logístico: El test chi-cuadrado compara el modelo con predictores contra el modelo nulo (sin variables). Si el p-valor acumulado es < 0.05, se rechaza H₀ y se concluye que al menos una variable predictora aporta significativamente al modelo. Este resultado complementa los p-valores individuales de cada coeficiente mostrados en el resumen anterior.

Coeficientes del modelo de regresión logística
Estimado Error Estándar z-valor p-valor
(Intercept) 0.5920 3.3474 0.1769 0.8596
age 0.0243 0.0489 0.4971 0.6191
weight_kg 0.0277 0.0354 0.7830 0.4337
shooting 0.0238 0.0225 1.0581 0.2900
passing -0.0125 0.0325 -0.3846 0.7005
dribbling -0.0423 0.0401 -1.0550 0.2914

Interpretación de los coeficientes (en términos de odds ratio):

odds_ratios <- exp(coef(modelo_logit))
or_df <- data.frame(
  Variable    = names(odds_ratios),
  "Odds Ratio" = round(odds_ratios, 4)
)
kable(or_df, caption = "Odds Ratios del modelo logístico",
      booktabs = TRUE, row.names = FALSE) %>%
  kable_styling(latex_options = c("hold_position"), font_size = 10)
Odds Ratios del modelo logístico
Variable Odds.Ratio
(Intercept) 1.8076
age 1.0246
weight_kg 1.0281
shooting 1.0241
passing 0.9876
dribbling 0.9586

Los coeficientes del modelo logístico se interpretan en términos de odds ratios (OR). Un OR > 1 indica que la variable aumenta la probabilidad de que el jugador sea diestro; un OR < 1 indica que la reduce. Las variables con p-valor < 0.05 son estadísticamente significativas para predecir el pie dominante.

Matriz de Confusión y Métricas de Evaluación

# Probabilidades predichas
probabilidades <- predict(modelo_logit, type = "response")

# Clasificación con umbral 0.5
predicciones_clase <- ifelse(probabilidades >= 0.5, 1, 0)

# Matriz de confusión
conf_matrix <- confusionMatrix(
  factor(predicciones_clase, levels = c(0, 1)),
  factor(futbol_logit$foot_bin, levels = c(0, 1)),
  positive = "1"
)

print(conf_matrix)
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0   0   0
#>          1  35 115
#>                                           
#>                Accuracy : 0.7667          
#>                  95% CI : (0.6907, 0.8318)
#>     No Information Rate : 0.7667          
#>     P-Value [Acc > NIR] : 0.5452          
#>                                           
#>                   Kappa : 0               
#>                                           
#>  Mcnemar's Test P-Value : 9.081e-09       
#>                                           
#>             Sensitivity : 1.0000          
#>             Specificity : 0.0000          
#>          Pos Pred Value : 0.7667          
#>          Neg Pred Value :    NaN          
#>              Prevalence : 0.7667          
#>          Detection Rate : 0.7667          
#>    Detection Prevalence : 1.0000          
#>       Balanced Accuracy : 0.5000          
#>                                           
#>        'Positive' Class : 1               
#> 
Métricas de evaluación del modelo logístico
Metrica Valor
Accuracy 0.7667
Recall (Sensibilidad) 1.0000
Precisión 0.7667
F1-Score 0.8679

Interpretación de las métricas:

  • Accuracy = 0.7667: El modelo clasifica correctamente el 76.7% de los jugadores en cuanto a su pie dominante. Este valor es relativamente alto y refleja un buen desempeño general del modelo.

  • Recall = 1: El modelo detecta correctamente el 100% de los jugadores diestros reales. Este es el porcentaje de verdaderos positivos sobre el total de positivos reales.

  • ¿Qué tan efectivo es este modelo para predecir el pie dominante?
    El modelo logístico con las variables age, weight_kg, shooting, passing y dribbling logra una accuracy de 76.7% y un recall de 100%. Estos resultados indican que el modelo es efectivo para predecir el pie dominante y que las variables seleccionadas capturan información relevante sobre esta característica. Cabe destacar que el dataset de FIFA está naturalmente desbalanceado hacia jugadores diestros (aproximadamente 75-80% de jugadores), lo que puede inflar el accuracy y subestimar el recall de la clase minoritaria (pie izquierdo).


Conclusiones Generales

  1. Exploración de datos: El conjunto de datos FIFA contiene información rica sobre las habilidades de los jugadores. Tras eliminar valores faltantes (principalmente de porteros), se trabajó con 13762 registros completos, de los cuales se extrajo una muestra de 150. Las distribuciones de shooting y dribbling son aproximadamente simétricas con presencia de valores atípicos en los extremos inferiores.

  2. Regresión lineal simple: Se encontró una correlación fuerte (r = 0.71) entre tiro y regate. El modelo es estadísticamente significativo (p < 0.05), aunque el R² de 0.504 sugiere que shooting explica solo una parte de la variabilidad en dribbling. Los supuestos del modelo fueron verificados mediante análisis de residuos.

  3. Regresión logística: El modelo para predecir el pie dominante alcanzó una accuracy de 76.7% y un recall de 100%. La prueba ANOVA chi-cuadrado confirmó la significancia global del modelo. Dado el desbalance natural del dataset hacia jugadores diestros, el accuracy puede estar inflado, por lo que el recall es la métrica más informativa en este contexto. Se recomienda explorar variables adicionales para mejorar el desempeño predictivo.

  4. Recomendaciones: Para futuros análisis se sugiere: (a) explorar regresión múltiple incorporando variables como pace, physic y overall; (b) aplicar técnicas de manejo de desbalance de clases en la regresión logística; (c) evaluar modelos más complejos como Random Forest o Gradient Boosting para mejorar la predicción.


Referencias

Leone, S. (2019). FIFA 20 complete player dataset. Kaggle.
https://www.kaggle.com/stefanoleone992/fifa-20-complete-player-dataset

James, G., Witten, D., Hastie, T., & Tibshirani, R. (2021). An Introduction to Statistical Learning (2nd ed.). Springer.

R Core Team (2024). R: A language and environment for statistical computing. R Foundation for Statistical Computing. https://www.R-project.org/