Ram Maheshwari Logo Image
Sergio Cobos
A4 - Análisis estadístico avanzado

Introducción

El conjunto de datos fifa22.csv se encuentra disponible en la plataforma Kaggle: https://www.kaggle.com/datasets/stefanoleone992/fifa-22-complete-player-dataset. Este conjunto de datos contiene el estilo de juego del videojuego de consola Fifa 2022, así como estadísticas reales de los jugadores de fútbol. Las principales variables que usaremos en esta actividad son:

El resto de información se puede consultar en https://www.sofifa.com

En esta actividad se analizará si el salario y valor de mercado está influido por la liga y si juega con la selección nacional. Nos centraremos en los jugadores que son estrellas del fútbol. Para hacerlo, se aplican diferentes tipos de análisis, revisando el contraste de hipótesis de dos muestras, vistos en la actividad A2, y después realizando análisis más complejos como ANOVA.

Notas importantes a tener en cuenta para la entrega de la actividad: - Es necesario entregar el fichero Rmd y el fichero de salida (PDF o html). - El fichero de salida tiene que incluir el código y el resultado de su ejecución (paso a paso). - Se tiene que incluir un índice o tabla de contenidos. Y se tiene que respetar la numeración de los apartados del enunciado. - No realicéis listados de los conjuntos de datos, puesto que estos pueden ocupar varias páginas. Si queréis comprobar el efecto de una instrucción sobre un conjunto de datos podéis usar la función head y tail que muestran las primeras o últimas filas del conjunto de datos.

1 Preprocesado

1.1 Variables wage y age

Cargad el fichero de datos “fifa22.csv”. Consultad los tipos de datos de las variables y si es necesario, aplicad las transformaciones apropiadas. Solo hace falta que realicéis este proceso para las variables que usaremos en el análisis (variables indicadas más arriba). Averiguad posibles inconsistencias en los valores de wage y age. En caso de que existan inconsistencias, corregidlas. Nota: Si los valores de wage están en libras se tienen que pasar a euros. Considerad la siguiente tasa de cambio (£1 = 113EUR).

Verificamos la estructura del juego de datos principal. Vemos el número de columnas que tenemos y ejemplos de los contenidos de las filas.

# Cargar los datos
datos <- read.table("fifa22.csv", sep = ",", header = TRUE, quote = "\"", stringsAsFactors = FALSE, colClasses = "character", fileEncoding = "ISO-8859-1")

# Verificar las clases de columna
str(datos)
## 'data.frame':    19239 obs. of  34 variables:
##  $ X                        : chr  "1" "2" "3" "4" ...
##  $ overall                  : chr  "93" "92" "91" "91" ...
##  $ potential                : chr  "93" "92" "91" "91" ...
##  $ value_eur                : chr  "7.8e+07" "119500000" "4.5e+07" "1.29e+08" ...
##  $ wage                     : chr  "320000" "270000" "£270000" "270000" ...
##  $ age                      : chr  "34" "32" "36" "29" ...
##  $ dob                      : chr  "1987-06-24" "1988-08-21" "1985-02-05" "1992-02-05" ...
##  $ height_cm                : chr  "170" "185" "187" "175" ...
##  $ weight_kg                : chr  "72" "81" "83" "68" ...
##  $ club_team_id             : chr  "73" "21" "11" "73" ...
##  $ club_name                : chr  "Paris Saint-Germain" "FC Bayern München" "Manchester United" "Paris Saint-Germain" ...
##  $ league_name              : chr  "French Ligue 1" "German 1. Bundesliga" "English Premier League" "French Ligue 1" ...
##  $ league_level             : chr  "1" "1" "1" "1" ...
##  $ club_position            : chr  "RW" "ST" "ST" "LW" ...
##  $ club_jersey_number       : chr  "30" "9" "7" "10" ...
##  $ club_loaned_from         : chr  "" "" "" "" ...
##  $ club_joined              : chr  "2021-08-10" "2014-07-01" "2021-08-27" "2017-08-03" ...
##  $ club_contract_valid_until: chr  "2023" "2023" "2023" "2025" ...
##  $ nationality_id           : chr  "52" "37" "38" "54" ...
##  $ nationality_name         : chr  "Argentina" "Poland" "Portugal" "Brazil" ...
##  $ nation_team_id           : chr  "1369" "1353" "1354" NA ...
##  $ nation_position          : chr  "RW" "RS" "ST" "" ...
##  $ nation_jersey_number     : chr  "10" "9" "7" NA ...
##  $ preferred_foot           : chr  "Left" "Right" "Right" "Right" ...
##  $ weak_foot                : chr  "4" "4" "4" "5" ...
##  $ skill_moves              : chr  "4" "4" "5" "5" ...
##  $ international_reputation : chr  "5" "5" "5" "5" ...
##  $ work_rate                : chr  "Medium/Low" "High/Medium" "High/Low" "High/Medium" ...
##  $ body_type                : chr  "Unique" "Unique" "Unique" "Unique" ...
##  $ real_face                : chr  "Yes" "Yes" "Yes" "Yes" ...
##  $ release_clause_eur       : chr  "144300000" "197200000" "83300000" "238700000" ...
##  $ player_tags              : chr  "#Dribbler, #Distance Shooter, #FK Specialist, #Acrobat, #Clinical Finisher, #Complete Forward" "#Aerial Threat, #Distance Shooter, #Clinical Finisher, #Complete Forward" "#Aerial Threat, #Dribbler, #Distance Shooter, #Crosser, #Acrobat, #Clinical Finisher, #Complete Forward" "#Speedster, #Dribbler, #Playmaker, #FK Specialist, #Acrobat, #Complete Midfielder" ...
##  $ player_traits            : chr  "Finesse Shot, Long Shot Taker (AI), Playmaker (AI), Outside Foot Shot, One Club Player, Chip Shot (AI), Technic"| __truncated__ "Solid Player, Finesse Shot, Outside Foot Shot, Chip Shot (AI)" "Power Free-Kick, Flair, Long Shot Taker (AI), Speed Dribbler (AI), Outside Foot Shot" "Injury Prone, Flair, Speed Dribbler (AI), Playmaker (AI), Outside Foot Shot, Technical Dribbler (AI)" ...
##  $ pace                     : chr  "85" "78" "87" "91" ...

Vemos que tenemos 19 variables y 19.239 registros.

# Crear una función para multiplicar los valores con libra por 1.13
multiply_wage <- function(wage) {
  if (grepl("£", wage)) {
    wage <- as.numeric(gsub("£", "", wage)) * 1.13
  }
  return(wage)
}

# Aplicar la función a la variable wage
datos$wage <- sapply(datos$wage, multiply_wage)
str(datos$wage)
##  chr [1:19239] "320000" "270000" "305100" "270000" "395500" "130000" ...

Observamos que la transformación se ha realizado correctamente.

# Convertir variables numéricas a tipo entero
datos <- datos %>%
  mutate(wage = as.integer(wage),                  # Salario
         value_eur = as.integer(value_eur),        # Valor en euros
         overall = as.integer(overall),            # Valor general
         age = as.integer(age),                    # Edad
         league_level = as.integer(league_level),  # Nivel de la liga
         international_reputation = as.integer(international_reputation))  

# Mostrar la estructura actualizada de las variables específicas
str(datos[c("wage", "value_eur", "overall", "age", "league_level", "international_reputation")])
## 'data.frame':    19239 obs. of  6 variables:
##  $ wage                    : int  320000 270000 305100 270000 395500 130000 230000 86000 250000 271200 ...
##  $ value_eur               : int  78000000 119500000 45000000 129000000 125500000 112000000 194000000 13500000 99000000 129500000 ...
##  $ overall                 : int  93 92 91 91 91 91 91 90 90 90 ...
##  $ age                     : int  34 32 36 29 30 28 22 35 29 27 ...
##  $ league_level            : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ international_reputation: int  5 5 5 5 4 5 4 5 4 4 ...

Observamos que los canvios se han realizado correctamente.

# Crear un data frame con las variables "wage" y "age"
df <- data.frame(wage = datos$wage, age = datos$age)

# Boxplot de la variable "wage" con ggplot y color "cornflowerblue"
p1 <- ggplot(df, aes(x = "", y = wage)) +
  geom_boxplot(fill = "cornflowerblue", color = "black") +
  labs(title = "Boxplot de Wage", x = "Wage", y = "Valores") +
  theme_minimal()

# Boxplot de la variable "age" con ggplot y color "cornflowerblue"
p2 <- ggplot(df, aes(x = "", y = age)) +
  geom_boxplot(fill = "cornflowerblue", color = "black") +
  labs(title = "Boxplot de Age", x = "Age", y = "Valores") +
  theme_minimal()

# Combinar los gráficos en un grid
grid.arrange(p1, p2, ncol = 2)

wage: Podemos observar que la caja del diagrama de caja y bigotes es relativamente estrecha, lo que indica que la mayoría de los salarios se concentran en un rango más estrecho. Sin embargo, también podemos notar la presencia de varios valores atípicos muy elevados que se extienden hacia arriba, lo que indica que hay algunos salarios excepcionalmente altos en el conjunto de datos.

Es importante tener en cuenta que estos valores atípicos no deben considerarse necesariamente como anomalías o errores en los datos, ya que es posible que existan salarios excepcionalmente altos en la realidad, como en el caso de jugadores de fútbol u otros profesionales con sueldos desorbitados.

age: Podemos observar que la caja azul en el diagrama de caja y bigotes se encuentra principalmente en un rango de aproximadamente 20 a 30 años, lo que indica que la mayoría de las edades se concentran en esa franja. Esto sugiere que hay una distribución relativamente uniforme de edades en ese rango.

Sin embargo, también podemos notar la presencia de un valor atípico que se aleja mucho de la media y se encuentra fuera de los límites del bigote. Este valor atípico se considerará anómalo, ya que se aleja significativamente de la mayoría de las edades observadas y podría ser un caso excepcional o un error en los datos.

# Resumen de la variable "wage"
summary(datos$wage)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##     500    1000    3000    9243    8000  395500      61
# Resumen de la variable "age"
summary(datos$age)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   16.00   21.00   25.00   25.21   29.00   54.00

wage: Podemos observar que el salario mínimo es de 500, mientras que el salario máximo alcanza los 395500. La mediana, que representa el valor medio de la distribución, es de 3000, lo que indica que la mitad de los salarios están por encima de este valor y la otra mitad está por debajo. La media, por otro lado, es de 9243, lo que implica que, en promedio, los salarios tienden a ser más altos que la mediana. Además, se reportan 61 valores faltantes (NA’s) en la variable “wage”.

age: Podemos observar que la edad mínima registrada es de 16 años, mientras que la edad máxima es de 54 años. La mediana, que representa el valor medio de la distribución, es de 25 años, lo que indica que la mitad de las edades están por encima de este valor y la otra mitad está por debajo. La media, por otro lado, es ligeramente mayor, con un valor de 25.21, lo que sugiere que hay algunas edades más altas que influyen en el promedio. En general, la distribución de las edades muestra una concentración en los grupos más jóvenes, ya que los valores del primer cuartil y el tercer cuartil se encuentran en torno a los 21 y 29 años, respectivamente.

# Eliminar filas con NA en la variable "wage" 
datos <- datos[complete.cases(datos$wage), ]

# Eliminar filas con valores mayores a 45 
datos <- datos[datos$age <= 45, ]

# Resumen de la variable "wage"
summary(datos$wage)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     500    1000    3000    9243    8000  395500
# Resumen de la variable "age"
summary(datos$age)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    16.0    21.0    25.0    25.2    29.0    43.0

Vemos que se han corregido correctamente las inconsistencias de las variables.

1.2 Valores ausentes

En este apartado, limpiaremos el conjunto de datos de los valores ausentes. Concretamente, adoptaremos una estrategia sencilla que es eliminar las observaciones del conjunto de datos que tengan valores ausentes (NA’s). Seguid los pasos que se indican a continuación: Eliminad los valores ausentes del conjunto de datos. Denominad al nuevo conjunto de datos fifaclean. Comprobad cuántas observaciones tienen valores ausentes y reflexionad brevemente sobre cómo de preocupante es el problema de valores ausentes en estos datos. Nota: En las variables nation_team_id, nation_position y nation_jersey_number se observan muchos casos sin valor. No eliminéis estas observaciones puesto que no son verdaderos missings, sino que simplemente indican que el jugador no ha jugado nunca con el equipo nacional.

# Calcular la suma de valores faltantes por columna
print('NA')
## [1] "NA"
colSums(is.na(datos))
##                         X                   overall                 potential 
##                         0                         0                         0 
##                 value_eur                      wage                       age 
##                        12                         0                         0 
##                       dob                 height_cm                 weight_kg 
##                         0                         0                         0 
##              club_team_id                 club_name               league_name 
##                         0                         0                         0 
##              league_level             club_position        club_jersey_number 
##                         0                         0                         0 
##          club_loaned_from               club_joined club_contract_valid_until 
##                         0                         0                         0 
##            nationality_id          nationality_name            nation_team_id 
##                         0                         0                     18479 
##           nation_position      nation_jersey_number            preferred_foot 
##                         0                     18479                         0 
##                 weak_foot               skill_moves  international_reputation 
##                         0                         0                         0 
##                 work_rate                 body_type                 real_face 
##                         0                         0                         0 
##        release_clause_eur               player_tags             player_traits 
##                      1114                         0                         0 
##                      pace 
##                      2124
# Eliminar filas con valores faltantes en todas las columnas, excepto nation_team_id, nation_position y nation_jersey_number
datos <- datos %>% drop_na(-c(nation_team_id, nation_position, nation_jersey_number))

# Calcular la suma de valores faltantes por columna después de eliminar filas con valores faltantes
print('NA')
## [1] "NA"
colSums(is.na(datos))
##                         X                   overall                 potential 
##                         0                         0                         0 
##                 value_eur                      wage                       age 
##                         0                         0                         0 
##                       dob                 height_cm                 weight_kg 
##                         0                         0                         0 
##              club_team_id                 club_name               league_name 
##                         0                         0                         0 
##              league_level             club_position        club_jersey_number 
##                         0                         0                         0 
##          club_loaned_from               club_joined club_contract_valid_until 
##                         0                         0                         0 
##            nationality_id          nationality_name            nation_team_id 
##                         0                         0                     15441 
##           nation_position      nation_jersey_number            preferred_foot 
##                         0                     15441                         0 
##                 weak_foot               skill_moves  international_reputation 
##                         0                         0                         0 
##                 work_rate                 body_type                 real_face 
##                         0                         0                         0 
##        release_clause_eur               player_tags             player_traits 
##                         0                         0                         0 
##                      pace 
##                         0

1.3 Creación de base datos star

Seleccionaremos aquellos jugadores que son los que más cobran semanalmente (estrellas). Realizad un box-plot. Identificad el número de valores atípicos y guardad las observaciones con valores atípicos en la nueva base de datos llamada star. En el resto de apartados trabajaremos con este juego de datos.

Nota: El criterio para determinar si es una estrella es que sea un valor atípico de la variable wage. La detección de valores atípicos se tiene que basar en el mismo criterio que la función boxplot.stats. Se puede usar esta función.

# Crear un data frame con la variable "wage"
df <- data.frame(wage = datos$wage)

# Crear el boxplot utilizando ggplot
ggplot(df, aes(y = wage)) +
  geom_boxplot(fill = "cornflowerblue", color = "black") +
  labs(title = "Boxplot de Wage", y = "Wage") +
  theme_minimal()

# Calcular los límites del boxplot para la variable "wage"
boxplot_stats <- boxplot.stats(datos$wage)

# Obtener los índices de las filas con valores atípicos de "wage"
outlier_indices <- which(datos$wage %in% boxplot_stats$out)

# Crear la base de datos "star" con las filas que contienen valores atípicos en "wage"
star <- datos[outlier_indices, ]

str(star)
## 'data.frame':    2030 obs. of  34 variables:
##  $ X                        : chr  "1" "2" "3" "4" ...
##  $ overall                  : int  93 92 91 91 91 91 90 90 89 89 ...
##  $ potential                : chr  "93" "92" "91" "91" ...
##  $ value_eur                : int  78000000 119500000 45000000 129000000 125500000 194000000 129500000 100000000 66000000 104000000 ...
##  $ wage                     : int  320000 270000 305100 270000 395500 230000 271200 259900 350000 248600 ...
##  $ age                      : int  34 32 36 29 30 22 27 30 33 28 ...
##  $ dob                      : chr  "1987-06-24" "1988-08-21" "1985-02-05" "1992-02-05" ...
##  $ height_cm                : chr  "170" "185" "187" "175" ...
##  $ weight_kg                : chr  "72" "81" "83" "68" ...
##  $ club_team_id             : chr  "73" "21" "11" "73" ...
##  $ club_name                : chr  "Paris Saint-Germain" "FC Bayern München" "Manchester United" "Paris Saint-Germain" ...
##  $ league_name              : chr  "French Ligue 1" "German 1. Bundesliga" "English Premier League" "French Ligue 1" ...
##  $ league_level             : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ club_position            : chr  "RW" "ST" "ST" "LW" ...
##  $ club_jersey_number       : chr  "30" "9" "7" "10" ...
##  $ club_loaned_from         : chr  "" "" "" "" ...
##  $ club_joined              : chr  "2021-08-10" "2014-07-01" "2021-08-27" "2017-08-03" ...
##  $ club_contract_valid_until: chr  "2023" "2023" "2023" "2025" ...
##  $ nationality_id           : chr  "52" "37" "38" "54" ...
##  $ nationality_name         : chr  "Argentina" "Poland" "Portugal" "Brazil" ...
##  $ nation_team_id           : chr  "1369" "1353" "1354" NA ...
##  $ nation_position          : chr  "RW" "RS" "ST" "" ...
##  $ nation_jersey_number     : chr  "10" "9" "7" NA ...
##  $ preferred_foot           : chr  "Left" "Right" "Right" "Right" ...
##  $ weak_foot                : chr  "4" "4" "4" "5" ...
##  $ skill_moves              : chr  "4" "4" "5" "5" ...
##  $ international_reputation : int  5 5 5 5 4 4 4 4 4 4 ...
##  $ work_rate                : chr  "Medium/Low" "High/Medium" "High/Low" "High/Medium" ...
##  $ body_type                : chr  "Unique" "Unique" "Unique" "Unique" ...
##  $ real_face                : chr  "Yes" "Yes" "Yes" "Yes" ...
##  $ release_clause_eur       : chr  "144300000" "197200000" "83300000" "238700000" ...
##  $ player_tags              : chr  "#Dribbler, #Distance Shooter, #FK Specialist, #Acrobat, #Clinical Finisher, #Complete Forward" "#Aerial Threat, #Distance Shooter, #Clinical Finisher, #Complete Forward" "#Aerial Threat, #Dribbler, #Distance Shooter, #Crosser, #Acrobat, #Clinical Finisher, #Complete Forward" "#Speedster, #Dribbler, #Playmaker, #FK Specialist, #Acrobat, #Complete Midfielder" ...
##  $ player_traits            : chr  "Finesse Shot, Long Shot Taker (AI), Playmaker (AI), Outside Foot Shot, One Club Player, Chip Shot (AI), Technic"| __truncated__ "Solid Player, Finesse Shot, Outside Foot Shot, Chip Shot (AI)" "Power Free-Kick, Flair, Long Shot Taker (AI), Speed Dribbler (AI), Outside Foot Shot" "Injury Prone, Flair, Speed Dribbler (AI), Playmaker (AI), Outside Foot Shot, Technical Dribbler (AI)" ...
##  $ pace                     : chr  "85" "78" "87" "91" ...

Observamos que la base de datos “star” se ha creado correctamente.

2 Estadística descriptiva y visualización

2.1 Salario

Tomando los datos del conjunto star, realizad un análisis descriptivo de la variable wage. ¿Podemos asumir que la variable tiene una distribución normal? Tenéis que justificar la respuesta a partir de métodos visuales. En base a los resultados obtenidos, ¿pensáis que el salario medio de las estrellas de fútbol es un valor representativo del conjunto de observaciones? Justifica la respuesta.

# Crear histograma de la variable "wage" en "star"
ggplot(star, aes(x = wage)) +
  geom_histogram(fill = "cornflowerblue", color = "black") +
  labs(title = "Histograma de Wage", x = "Wage") +
  theme_minimal()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# Generar resumen de la variable "wage" en "star"
summary(star$wage)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   19000   24000   33000   47470   51000  395500

No presenta una distribución normal. La mayor parte de la distribución de la variable “wage” en la base de datos “star” se encuentra en el primer cuartil (Q1), es decir, el 25% inferior de los valores y se puede observar una clara asimetría. La presencia de valores atípicos en el extremo superior de la distribución puede estar “sesgando” hacia arriba el cálculo de la media, lo cual es más evidente si se compara con la mediana (Q2) que se encuentra en un valor más bajo.

Este sesgo se debe a que los salarios de las estrellas de fútbol más destacadas son significativamente más altos que los salarios de la mayoría de los jugadores. Los salarios extremadamente altos de algunos jugadores influyen en la media, pero no representan la situación típica de la mayoría de los jugadores. Por lo tanto, el salario medio puede no ser un valor representativo adecuado del conjunto de observaciones en este caso.

En lugar de utilizar el salario medio, sería más apropiado considerar la mediana como una medida de tendencia central, ya que esta no se ve tan afectada por los valores atípicos y representa el valor que divide al conjunto de datos en dos partes iguales.

2.2 Jugadores internacionales

Identificad si un jugador es internacional o no a partir del valor de la variable nation_team_id. En concreto, el jugador es internacional si la variable nation_team_id toma un valor. Si no es internacional, esta variable toma un valor ausente. Después mostrad un box plot del salario según si el jugador es o no internacional. ¿Que podemos decir?

Nota: Para calcular la media u otras medidas por cada tipo de jugador (internacional o no), podéis utilizar las funciones summarize y group_by de la librería dplyr. Para realizar la visualización de los datos, podéis utilizar la función ggplot de la librería ggplot2.

# Crear una nueva variable "es_internacional" basada en nation_team_id
star$international <- ifelse(is.na(star$nation_team_id), "0", "1")

# Crear boxplot del salario según si el jugador es o no internacional
ggplot(star, aes(x = international, y = wage, fill = international)) +
  geom_boxplot(color = "black") +
  labs(title = "Boxplot de Salario por Internacionalidad", x = "", y = "Salario") +
  theme_minimal()

Basándonos en los resultados observados en el boxplot del salario según la internacionalidad de los jugadores, podemos hacer las siguientes observaciones técnicas:

  1. Mediana más alta para jugadores internacionales: La línea central dentro de la caja del boxplot, que representa la mediana, es más alta para los jugadores internacionales en comparación con los no internacionales.

  2. Caja más ancha para jugadores internacionales: La caja del boxplot para los jugadores internacionales es más ancha en comparación con la de los no internacionales. Una caja más ancha indica una mayor dispersión o variabilidad en los salarios de los jugadores internacionales en comparación con los no internacionales.

  3. Valores atípicos: Se observa que hay algunos valores atípicos tanto para los jugadores internacionales como para los no internacionales. Sin embargo, los valores atípicos más destacados en términos de salarios más altos corresponden a los jugadores internacionales. Esto indica que, aunque existen algunos jugadores no internacionales con salarios excepcionalmente altos, los jugadores internacionales tienden a tener salarios más elevados en general.

En resumen, los jugadores internacionales tienden a tener una mediana más alta, una caja más ancha y valores atípicos más destacados en términos de salarios más altos. Sin embargo, también se observa cierta variabilidad en los salarios de los jugadores no internacionales, incluyendo algunos valores atípicos que cobran más que algunos jugadores internacionales.

2.3 Liga

En el siguiente apartado, analizaremos si hay diferencias según las principales ligas. Cread una nueva variable que indique si el jugador juega en la Premier League, Primera división española, a la Serie A italiana, a la primera división de la Bundesliga o a otra liga diferente a éstas (hay que agrupar el resto de ligas bajo la categoría “Other”). Denominad la variable league. Mostrad una tabla con el número de observaciones de cada categoría.

# Crear la variable league
star <- star %>%
  mutate(league = case_when(
    league_name == "English Premier League" ~ "Premier League",
    league_name == "Spain Primera Division" ~ "Primera Division",
    league_name == "Italian Serie A" ~ "Serie A",
    league_name == "German 1. Bundesliga" ~ "Bundesliga",
    TRUE ~ "Other"
  ))
# Mostrar tabla con el número de observaciones para cada categoría de liga
tabla_ligas <- table(star$league)
kable(tabla_ligas)
Var1 Freq
Bundesliga 241
Other 829
Premier League 397
Primera Division 310
Serie A 253
  1. Premier League: Tiene la mayor cantidad de jugadores considerados “stars” con 397 observaciones. Esto indica que la liga inglesa cuenta con un mayor número de jugadores reconocidos como talentos destacados.

  2. Primera División: La liga española sigue de cerca a la Premier League con 310 observaciones de jugadores considerados “stars”. Esto muestra que la Primera División también cuenta con una cantidad significativa de jugadores reconocidos como talentosos.

  3. Serie A: La liga italiana tiene 253 observaciones de jugadores considerados “stars”. Aunque es menor en comparación con la Premier League y la Primera División, aún muestra que la Serie A tiene su cuota de jugadores de alto nivel.

  4. Bundesliga: La liga italiana tiene 241 observaciones de jugadores considerados “stars”. Si bien tiene menos jugadores identificados como “stars” en comparación con las otras ligas mencionadas, aún cuenta con una cantidad considerable de talento destacado.

  5. Other: Las otras ligas tienen entre todas 829 observaciones, lo que nos indica que hay mas estrellas concentradas en las cuatro ligas anteriores que en las restantes.

3 Estadística inferencial

Suponemos que los jugadores en star son una muestra representativa de las estrellas de fútbol de los últimos años.

3.1 Intervalo de confianza de la media poblacional

Calculad manualmente el intervalo de confianza al 95 % de la media poblacional de la variable wage de los jugadores (no se pueden utilizar funciones como t.test o z.test para el cálculo). A partir del resultado obtenido, explicad cómo se interpreta el intervalo de confianza.

# Cálculo del intervalo de confianza
wage_data <- star$wage  

# Tamaño de la muestra
n <- length(wage_data)

# Media muestral
x_bar <- mean(wage_data)

# Desviación estándar muestral
s <- sd(wage_data)

# Valor crítico de t
t_critical <- qt(0.975, df = n - 1)

# Error estándar de la media
SE <- s / sqrt(n)

# Margen de error
margin_error <- t_critical * SE

# Intervalo de confianza
confidence_interval <- c(x_bar - margin_error, x_bar + margin_error)

# Imprimir el resultado
print(confidence_interval)
## [1] 45637.71 49302.19

El intervalo de confianza obtenido para la media de la variable “wage” en la base de datos “star” es de 45637.71 a 49302.19, con un nivel de confianza del 95%. Esto significa que podemos estar 95% seguros de que el verdadero valor de la media poblacional de los salarios de los jugadores se encuentra dentro de ese rango.

3.2 Contraste de hipótesis para la diferencia de medias

¿Podemos aceptar que las estrellas que juegan a primera de la liga española cobran en promedio lo mismo que el resto de jugadores estrellas? Responded a la pregunta utilizando un nivel de confianza del 95 %.

Nota: se tienen que realizar los cálculos manualmente. No se pueden usar funciones de R que calculen directamente el contraste como t.test o similar. Si que se pueden usar funciones como mean, sd, qnorm, pnorm, qt y pt.

Seguid los pasos que se detallan a continuación.

3.2.1 Escribid la hipótesis nula y la alternativa

  • Hipótesis nula (H0): La media de los salarios de las estrellas que juegan en la Primera División de la liga española es igual a la media de los salarios del resto de jugadores estrellas.

  • Hipótesis alternativa (H1): La media de los salarios de las estrellas que juegan en la Primera División de la liga española es diferente a la media de los salarios del resto de jugadores estrellas.

3.2.2 Justificación del test a aplicar

El t-test utilizado es apropiado en este caso porque estamos comparando las medias de dos grupos independientes (la Primera División de la liga española y el resto de jugadores estrellas). Queremos determinar si hay una diferencia significativa en los salarios promedio entre estos dos grupos.

El t-test asume que las muestras son independientes y que las distribuciones de las variables son aproximadamente normales. En este caso, asumimos que los salarios en ambos grupos siguen una distribución normal.

Al realizar el t-test manualmente, calculamos el valor t observado utilizando las medias, desviaciones estándar y tamaños de muestra de cada grupo. Luego, comparamos este valor t observado con el valor crítico de t correspondiente al nivel de confianza deseado. También calculamos el p-valor para determinar la significancia estadística de la diferencia observada.

Al aplicar este t-test y evaluar el valor p, podemos determinar si hay evidencia suficiente para rechazar la hipótesis nula y concluir que existe una diferencia significativa en los salarios promedio entre la Primera División y el resto de jugadores estrellas.

3.2.3 Cálculos

Realizad los cálculos del estadístico de contraste, valor crítico y p valor a un nivel de confianza del 95 %.

# Obtener los salarios de los jugadores de la Primera División
group1 <- star$wage[star$league == "Primera Division"]

# Obtener los salarios del resto de jugadores estrellas
group2 <- star$wage[star$league != "Primera Division"]

# Calcular el número de observaciones en cada grupo
n_group1 <- length(group1)
n_group2 <- length(group2)

# Calcular las medias de cada grupo
media_group1 <- mean(group1)
media_group2 <- mean(group2)

# Calcular las desviaciones estándar de cada grupo
sd_group1 <- sd(group1)
sd_group2 <- sd(group2)

# Calcular el error estándar de la diferencia de las medias
se <- sqrt((sd_group1^2 / n_group1) + (sd_group2^2 / n_group2))

# Calcular el valor t observado
t_obs <- (media_group1 - media_group2) / se

# Calcular los grados de libertad
df <- n_group1 + n_group2 - 2

# Calcular el valor crítico de t para el nivel de confianza deseado (95%)
alpha <- 0.05
t_critico <- qt(1 - alpha/2, df)

# Calcular el p-valor de manera bilateral
p_valor <- 2 * pt(-abs(t_obs), df)

# Imprimir los resultados
cat("Valor t observado:", t_obs, "\n")
## Valor t observado: 0.1597548
cat("Valor crítico de t:", t_critico, "\n")
## Valor crítico de t: 1.961134
cat("P-valor:", p_valor, "\n")
## P-valor: 0.8730902

3.2.4 Interpretación del test

Dado que el valor p (p-valor) obtenido (0.8730902) es mayor que el nivel de significancia comúnmente utilizado de 0.05, no se puede rechazar la hipótesis nula (H0). Esto implica que no hay evidencia suficiente para afirmar que la media de los salarios de las estrellas que juegan en la Primera División de la liga española difiere de la media de los salarios del resto de jugadores estrellas.

4 Modelo de regresión lineal

Queremos investigar qué variables explican el valor de mercado del jugador. Estimad un modelo de regresión lineal múltiple que tenga como variables explicativas: international, wage, overall, age y league, y como variable dependiente value_eur expresado en millones de euros. Interpretad el modelo lineal ajustado. ¿Como es la calidad del ajuste? Explicad la contribución de las variables explicativas en el modelo

# Dividir la variable value_eur del dataframe star por un millón
star$value_eur <- star$value_eur / 1000000

# Convertir las variables en factores
star$international <- as.factor(star$international)
star$league <- as.factor(star$league)

# Especificar las categorías de referencia
star$international <- relevel(star$international, ref = "0")
star$league <- relevel(star$league, ref = "Other")

# Ajustar el modelo de regresión lineal múltiple
modelo <- lm(value_eur ~ international + wage + overall + age + league, data = star)
summary(modelo)
## 
## Call:
## lm(formula = value_eur ~ international + wage + overall + age + 
##     league, data = star)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -36.379  -3.700  -0.667   2.672 102.215 
## 
## Coefficients:
##                          Estimate Std. Error t value Pr(>|t|)    
## (Intercept)            -1.562e+02  4.588e+00 -34.039  < 2e-16 ***
## international1          2.190e+00  4.587e-01   4.775 1.93e-06 ***
## wage                    1.645e-04  6.211e-06  26.478  < 2e-16 ***
## overall                 2.594e+00  6.308e-02  41.121  < 2e-16 ***
## age                    -1.278e+00  4.546e-02 -28.104  < 2e-16 ***
## leagueBundesliga       -3.085e-01  5.519e-01  -0.559  0.57617    
## leaguePremier League   -4.869e+00  5.082e-01  -9.580  < 2e-16 ***
## leaguePrimera Division -4.387e-01  5.144e-01  -0.853  0.39386    
## leagueSerie A          -1.654e+00  5.417e-01  -3.053  0.00229 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 7.407 on 2021 degrees of freedom
## Multiple R-squared:  0.8267, Adjusted R-squared:  0.826 
## F-statistic:  1205 on 8 and 2021 DF,  p-value: < 2.2e-16

Al ajustar el modelo de regresión lineal múltiple, utilizando “No” como categoría de referencia para la variable “international” y “Other” como categoría de referencia para la variable “league”, podemos interpretar los siguientes resultados:

El modelo muestra un buen ajuste, ya que el coeficiente de determinación (R-cuadrado) es 0.8267, lo que indica que aproximadamente el 82.67% de la variabilidad en el valor de mercado del jugador puede ser explicada por las variables incluidas en el modelo.

El estadístico F es significativo con un valor de p muy bajo (< 2.2e-16), lo que indica que el modelo en su conjunto es estadísticamente significativo y que al menos una de las variables explicativas tiene un efecto significativo en el valor de mercado del jugador.

5 Regresión logística

5.1 Modelo predictivo

Ajustad un modelo predictivo basado en la regresión logística para predecir la probabilidad de ser internacional (es decir, de jugar en la selección nacional) en función de las variables explicativas utilizadas anteriormente en el modelo de regresión lineal. Incluid también la variable value_eur como variable explicativa. Mostrad el resultado del modelo e interpretad el modelo en términos de: cuáles son las variables significativas y como es la calidad del modelo.

# Ajustar el modelo de regresión logística
modelo_logistico <- glm(international ~ wage + overall + age + league + value_eur, data = star, family = binomial)

# Obtener un resumen del modelo
summary(modelo_logistico)
## 
## Call:
## glm(formula = international ~ wage + overall + age + league + 
##     value_eur, family = binomial, data = star)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -2.2579  -0.6029  -0.4592  -0.3372   2.6337  
## 
## Coefficients:
##                          Estimate Std. Error z value Pr(>|z|)    
## (Intercept)            -1.218e+01  2.421e+00  -5.032 4.86e-07 ***
## wage                    7.812e-07  2.377e-06   0.329 0.742378    
## overall                 1.612e-01  3.632e-02   4.439 9.04e-06 ***
## age                    -7.288e-02  2.238e-02  -3.257 0.001126 ** 
## leagueBundesliga       -2.706e-03  2.038e-01  -0.013 0.989407    
## leaguePremier League    1.774e-01  1.888e-01   0.939 0.347587    
## leaguePrimera Division -8.108e-01  2.158e-01  -3.757 0.000172 ***
## leagueSerie A          -1.915e-01  2.061e-01  -0.929 0.352696    
## value_eur               1.459e-02  8.543e-03   1.708 0.087632 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1939.7  on 2029  degrees of freedom
## Residual deviance: 1660.9  on 2021  degrees of freedom
## AIC: 1678.9
## 
## Number of Fisher Scoring iterations: 5

Las variables significativas en el modelo, de acuerdo con los valores p, son:

  • overall (Estimate: 0.1612, p-valor: 9.04e-06): Esta variable tiene un coeficiente positivo, lo que sugiere que a medida que el puntaje general de un jugador aumenta, es más probable que sea internacional.

  • age (Estimate: -0.07288, p-valor: 0.001126): Esta variable tiene un coeficiente negativo, lo que indica que a medida que la edad de un jugador aumenta, es menos probable que sea internacional.

  • leaguePrimera Division (Estimate: -0.8108, p-valor: 0.000172): Esta variable representa la liga en la que juega el jugador. En este caso, pertenecer a la liga “Primera Division” (probablemente la liga española) disminuye las probabilidades de ser internacional en comparación con otras ligas.

En cuanto a la calidad del modelo, podemos evaluarlo a través de la devianza. La devianza es una medida de ajuste del modelo, y una menor devianza indica un mejor ajuste. En este caso, la devianza nula (Null deviance) es de 1939.7 y la devianza residual (Residual deviance) es de 1660.9. Esto sugiere que el modelo ha logrado reducir la devianza en comparación con el modelo nulo. Sin embargo, para una evaluación más completa de la calidad del modelo, sería necesario compararlo con otros modelos y realizar pruebas adicionales, como validación cruzada o análisis de residuos.

5.2 Matriz de confusión

A continuación analizad la precisión del modelo, comparando la predicción del modelo sobre los mismos datos del conjunto de datos. Asumiremos que la predicción del modelo es 1 (internacional) si la probabilidad del modelo de regresión logística es superior o igual a 0.5 y 0 en caso contrario. Calculad manualmente la matriz de confusión. Interpretad los resultados. Indicad los valores de sensibilidad y especificidad e interpretadlos.

# Obtención de los valores reales
valores_reales <- as.factor(star$international)

# Obtención de las predicciones del modelo
probabilidades <- predict(modelo, type = "response")
predicciones <- ifelse(probabilidades >= 0.5, 1, 0)

# Creación de la matriz de confusión
matriz_confusion <- table(valores_reales, predicciones)
cat("Matriz de confusión:\n")
## Matriz de confusión:
print(matriz_confusion)
##               predicciones
## valores_reales    0    1
##              0  321 1335
##              1   19  355
  • Verdaderos positivos (TP): Hay 355 casos en los que el modelo predijo correctamente que la variable objetivo era “Si” (internacional) y efectivamente lo era en la realidad.

  • Verdaderos negativos (TN): Hay 321 casos en los que el modelo predijo correctamente que la variable objetivo era “No” (no internacional) y efectivamente no lo era en la realidad.

  • Falsos positivos (FP): Hay 1335 casos en los que el modelo predijo incorrectamente que la variable objetivo era “Si” (internacional), pero en realidad no lo era.

  • Falsos negativos (FN): Hay 19 casos en los que el modelo predijo incorrectamente que la variable objetivo era “No” (no internacional), pero en realidad sí lo era.

# Cálculo de las métricas de evaluación
verdaderos_positivos <- matriz_confusion[2, 2]
falsos_positivos <- matriz_confusion[1, 2]
verdaderos_negativos <- matriz_confusion[1, 1]
falsos_negativos <- matriz_confusion[2, 1]

precision <- verdaderos_positivos / (verdaderos_positivos + falsos_positivos)
sensibilidad <- verdaderos_positivos / (verdaderos_positivos + falsos_negativos)
especificidad <- verdaderos_negativos / (verdaderos_negativos + falsos_positivos)
exactitud <- (verdaderos_positivos + verdaderos_negativos) / sum(matriz_confusion)

# Imprimir las métricas de evaluación

cat("\nPrecision:", precision)
## 
## Precision: 0.2100592
cat("\nSensibilidad:", sensibilidad)
## 
## Sensibilidad: 0.9491979
cat("\nEspecificidad:", especificidad)
## 
## Especificidad: 0.1938406
cat("\nExactitud:", exactitud)
## 
## Exactitud: 0.3330049
  • Precisión: La precisión es del 21.01%. Indica la proporción de predicciones positivas que fueron correctas en relación con todas las predicciones positivas. En este caso, indica la proporción de jugadores que fueron clasificados correctamente como internacionales en relación con todos los jugadores clasificados como internacionales por el modelo.

  • Sensibilidad: La sensibilidad es del 94.92%. También conocida como recall o tasa de verdaderos positivos, indica la proporción de casos positivos reales que fueron correctamente identificados por el modelo. En este caso, indica la proporción de jugadores internacionales que fueron clasificados correctamente como internacionales por el modelo.

  • Especificidad: La especificidad es del 19.38%. Representa la proporción de casos negativos reales que fueron correctamente identificados por el modelo. En este caso, indica la proporción de jugadores no internacionales que fueron clasificados correctamente como no internacionales por el modelo.

  • Exactitud: La exactitud es del 33.30%. Es la proporción de todas las predicciones (tanto positivas como negativas) que fueron correctas. En este caso, indica la proporción de jugadores (tanto internacionales como no internacionales) que fueron clasificados correctamente por el modelo.

En resumen, el modelo presenta un desempeño deficiente en términos de precisión, especificidad y exactitud, mientras que muestra una buena sensibilidad. Esto indica que el modelo tiene dificultades para clasificar correctamente los casos negativos (jugadores no internacionales), lo que resulta en un alto número de falsos positivos y una baja precisión general.

5.3 Predicción

Aplicad el modelo de regresión logística para predecir la probabilidad que sea internacional un jugador valorado en 100 millones, 30.000EUR de salario, puntuación de 90, edad 30 años y juega a la premier. Haced los cálculos sin usar función predict.

intercepto <- -12.18
coef_wage <- 7.81e-07
coef_overall <- 0.1612
coef_age <- -0.07288
coef_leaguePremierLeague <- 0.1774
coef_value_eur <- 0.01459

# Cálculo del logit
logit <- intercepto + coef_wage * 30000 + coef_overall * 90 + coef_age * 30 + coef_leaguePremierLeague * 1 + coef_value_eur * 100

# Cálculo de la probabilidad utilizando la función logística inversa
probabilidad <- 1 / (1 + exp(-logit))
resultado <- probabilidad*100
cat(resultado, "%")
## 85.83229 %

6 ANOVA unifactorial

A continuación se realizará un análisis de varianza, donde se desea comparar el salario entre las principales ligas. El análisis de varianza consiste a evaluar si la variabilidad de una variable dependiente puede explicarse a partir de una o varias variables independientes, denominadas factores. En el supuesto que nos ocupa, nos interesa evaluar si la variabilidad de la variable wage puede explicarse por el tipo de liga. Hay dos preguntas básicas a responder: ¿Existen diferencias en el salario (wage) entre las diferentes ligas? Si existen diferencias, ¿entre qué ligas se dan estas diferencias?

6.1 Visualización gráfica

Mostrad gráficamente la distribución de wage según league. Realizad un box-plot.

# Crear el gráfico de boxplot con color personalizado
ggplot(data = star, aes(x = league, y = wage)) +
  geom_boxplot(fill = "cornflowerblue") +
  xlab("Liga") +
  ylab("Salario") +
  ggtitle("Distribución de wage según la liga")

6.2 Hipótesis nula y alternativa

Escribid la hipótesis nula y la alternativa.

  • Hipótesis nula (H0): No existen diferencias significativas en el salario entre las diferentes ligas.

  • Hipótesis alternativa (H1): Existen diferencias significativas en el salario entre al menos dos de las diferentes ligas.

6.3 Modelo

Calculad el análisis de varianza, usando la función aov o lm. Interpretad el resultado del análisis.

modelo_anova <- aov(wage ~ league, data = star)
summary(modelo_anova)
##               Df    Sum Sq   Mean Sq F value Pr(>F)    
## league         4 6.627e+11 1.657e+11   114.4 <2e-16 ***
## Residuals   2025 2.933e+12 1.448e+09                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

El análisis de varianza (ANOVA) realizado muestra los siguientes resultados:

  • Df: Los grados de libertad correspondientes al factor “league” y al error residual. En este caso, el factor “league” tiene 4 grados de libertad, lo que significa que hay 4 niveles diferentes de la variable categórica “league” (por ejemplo, Bundesliga, Premier League, Primera División y Serie A). Los residuales tienen 2025 grados de libertad, que corresponden a la cantidad de observaciones menos el número de niveles del factor.

  • Sum Sq: La suma de cuadrados asociada al factor “league” y al error residual. En este caso, la suma de cuadrados del factor “league” es de 6.627e+11, lo que indica la variabilidad explicada por las diferencias entre las ligas. La suma de cuadrados del error residual es de 2.933e+12, que representa la variabilidad no explicada por el modelo.

  • Mean Sq: El cuadrado medio, calculado dividiendo la suma de cuadrados por los grados de libertad correspondientes. En este caso, el cuadrado medio del factor “league” es de 1.657e+11, y el cuadrado medio del error residual es de 1.448e+09.

  • F value: La estadística F, que compara la variabilidad explicada por el factor con la variabilidad no explicada por el modelo. En este caso, el valor F es de 114.4.

  • Pr(>F): El valor p asociado al factor “league”, que indica la significancia estadística de las diferencias entre las ligas. En este caso, el valor p es menor que 2e-16, lo que indica que existen diferencias significativas en el salario entre las diferentes ligas.

En resumen, el análisis de varianza muestra que el factor “league” tiene un efecto significativo en el salario, lo que indica que existen diferencias significativas en el salario entre las ligas consideradas.

6.4 Profundizando en ANOVA

A partir de los resultados del modelo devuelto por aov, identificad las variables SST (Total Sum of Squares), SSW (Within Sum of Squares), SSB (Between Sum of Squares) y los grados de libertad. A partir de estos valores, calculad manualmente el valor F, el valor crítico (a un nivel de confianza del 95 %), y el p valor. Interpretad los resultados y explicad el significado de las variables SST, SSW y SSB.

# Ajustar el modelo ANOVA
modelo_anova <- aov(wage ~ league, data = star)

# Obtener los residuos del modelo
residuos <- residuals(modelo_anova)

# Calcular SST
SST <- sum((star$wage - mean(star$wage))^2)

# Calcular SSW
SSW <- sum(residuos^2)

# Calcular SSB
SSB <- SST - SSW

# Imprimir los resultados
print(paste("SST (Total Sum of Squares):", SST))
## [1] "SST (Total Sum of Squares): 3595249992995.07"
print(paste("SSW (Within Sum of Squares):", SSW))
## [1] "SSW (Within Sum of Squares): 2932559602323.69"
print(paste("SSB (Between Sum of Squares):", SSB))
## [1] "SSB (Between Sum of Squares): 662690390671.388"
# Grados de libertad para la variable "league"
df_league <- 4

# Grados de libertad para los residuos
df_residuals <- 2025

# Cálculo del valor F
F_value <- (SSB / df_league) / (SSW / df_residuals)

# Valor crítico para un nivel de significancia del 0.05
valor_critico <- qf(0.95, df_league, df_residuals, lower.tail = FALSE)

# Valor p (p-value)
p_valor <- 1 - pf(F_value, df_league, df_residuals)

# Imprimir los resultados con texto
cat("Valor F:", F_value, "\n")
## Valor F: 114.4007
cat("Valor crítico:", valor_critico, "\n")
## Valor crítico: 0.1776242
cat("P-valor:", p_valor, "\n")
## P-valor: 0

El valor F obtenido es 114.4007. Esto indica que existe una diferencia significativa entre las ligas en términos del salario (wage). La diferencia observada es mayor de lo que se esperaría por azar.

El valor crítico para un nivel de confianza del 95% es 0.1776242. Si el valor F calculado es mayor que el valor crítico, se rechaza la hipótesis nula de igualdad de medias.

El p-valor obtenido es 0, lo que significa que la probabilidad de obtener una diferencia tan grande o más grande que la observada debido al azar es extremadamente baja. Por lo tanto, se rechaza la hipótesis nula y se concluye que hay una diferencia significativa en el salario entre las diferentes ligas.

En resumen, el análisis de varianza indica que hay diferencias significativas en el salario entre las diferentes ligas y se puede concluir que al menos una liga tiene un salario promedio diferente de las demás.

6.5 Efectos de los niveles del factor y fuerza de relación

Proporcionad la estimación del efecto de los niveles del factor league. Interpretad los resultados.

# Ajustar el modelo de regresión lineal
modelo_lm <- lm(wage ~ league, data = star)

# Obtener las estimaciones de los efectos de los niveles del factor league
estimaciones <- emmeans(modelo_lm, "league")

# Mostrar las estimaciones de los efectos
print(estimaciones)
##  league           emmean   SE   df lower.CL upper.CL
##  Other             32460 1322 2025    29868    35052
##  Bundesliga        40855 2451 2025    36047    45662
##  Premier League    81690 1910 2025    77945    85436
##  Primera Division  47890 2161 2025    43652    52129
##  Serie A           48743 2392 2025    44051    53435
## 
## Confidence level used: 0.95

Las estimaciones de los efectos de los niveles del factor league en el modelo de regresión lineal son las siguientes:

  • El nivel “Other” tiene una estimación de salario (wage) promedio de aproximadamente 32,460. El intervalo de confianza del 95% para esta estimación se encuentra entre 29,868 y 35,052.

  • El nivel “Bundesliga” tiene una estimación de salario promedio de aproximadamente 40,855, con un intervalo de confianza del 95% entre 36,047 y 45,662.

  • El nivel “Premier League” tiene una estimación de salario promedio de aproximadamente 81,690, con un intervalo de confianza del 95% entre 77,945 y 85,436.

  • El nivel “Primera Division” tiene una estimación de salario promedio de aproximadamente 47,890, con un intervalo de confianza del 95% entre 43,652 y 52,129.

  • El nivel “Serie A” tiene una estimación de salario promedio de aproximadamente 48,743, con un intervalo de confianza del 95% entre 44,051 y 53,435.

Estas estimaciones representan las diferencias promedio en los salarios entre los diferentes niveles de la variable league.

Calculad la parte de la variabilidad de salario explicada por el efecto de los niveles (fuerza de relación). Es decir, calculad η2 = SSB/SST del modelo. Interpretad los resultados.

n2 <- SSB/SST
n2
## [1] 0.1843239

El valor 0.1843239 representa la proporción de variabilidad explicada por el efecto de los niveles del factor league sobre el salario. Esta proporción indica que aproximadamente el 18.43% de la variabilidad total en el salario se puede atribuir a las diferencias entre los niveles del factor league. En otras palabras, el factor league tiene cierto grado de influencia en la variabilidad observada en el salario de los jugadores de fútbol.

6.6 Normalidad dels residuos

Usad el gráfico Normal Q-Q y el test Shapiro-Wilk para evaluar la normalidad de los residuos. Podéis usar las funciones de R correspondientes para hacer el gráfico y el test.

# Gráfico Q-Q de los residuos
qqnorm(modelo_anova$residuals, main = "Gráfico Q-Q de los residuos",
       xlab = "Cuantiles teóricos", ylab = "Cuantiles observados",
       col = "steelblue", pch = 20)
qqline(modelo_anova$residuals, col = "darkred", lwd = 2, lty = 2)

Los valores en el gráfico Q-Q están en una línea recta hasta el punto de 1 y luego se alejan en forma de curva, esto puede indicar una desviación de la distribución normal de los residuos. La línea recta inicial indica una buena aproximación a la normalidad, pero la curva posterior sugiere desviaciones en los extremos.

En este caso, si los valores se alejan en forma de curva a partir de 1 en el gráfico Q-Q, puede ser un indicio de que los residuos tienen colas más pesadas (mayor dispersión) o una distribución que difiere de una distribución normal en los valores más altos o extremos. Estas desviaciones pueden sugerir asimetría o curtosis en los datos.

Por lo tanto, es importante considerar estas desviaciones al evaluar la normalidad de los residuos. Un resultado que muestre una curva a partir de 1 en el gráfico Q-Q podría indicar que los residuos no siguen estrictamente una distribución normal en los valores más altos o extremos.

# Test Shapiro-Wilk de normalidad de los residuos
shapiro.test(modelo_anova$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  modelo_anova$residuals
## W = 0.70679, p-value < 2.2e-16

El resultado del test Shapiro-Wilk para evaluar la normalidad de los residuos del modelo de ANOVA es el siguiente:

  • Estadístico de prueba (W): 0.70679

  • Valor p: < 2.2e-16

Con un valor p tan bajo, menor que el nivel de significancia estándar de 0.05, rechazamos la hipótesis nula de normalidad de los residuos. Esto indica que los residuos no siguen una distribución normal.

Por lo tanto, podemos concluir que los residuos del modelo de ANOVA no se ajustan a una distribución normal. Esto puede tener implicaciones en la validez de los resultados y las inferencias realizadas a partir del modelo. Es importante considerar esta falta de normalidad al interpretar los efectos de las variables y las diferencias entre los grupos en el modelo de ANOVA.

Homocedasticidad de los residuos

El gráfico “Residuals vs Fitted” proporciona información sobre la homocedasticidad de los residuos. Mostrad e interpretad este gráfico.

# Gráfico Residuales vs. Ajustados
ggplot(data = star, aes(x = fitted(modelo_anova), y = residuals(modelo_anova))) +
  geom_point(size = 3, color = "steelblue") +
  geom_hline(yintercept = 0, color = "darkred", linetype = "dashed") +
  xlab("Valores ajustados") +
  ylab("Residuales") +
  ggtitle("Gráfico Residuales vs. Ajustados") +
  theme_bw()

En el gráfico “Residuales vs. Ajustados” se observan cinco líneas verticales distintas, donde cada línea representa un grupo correspondiente a una liga específica. Esto puede indicar la presencia de heterocedasticidad en los residuos. La heterocedasticidad implica que la varianza de los residuos no es constante a lo largo de los valores ajustados o de los grupos.

Que las líneas verticales muestran diferencias en la dispersión de los residuos entre los grupos, eso puede indicar una violación de la suposición de homocedasticidad.

En resumen, si en el gráfico “Residuales vs. Ajustados” se observan líneas verticales distintas para cada liga, eso puede indicar la presencia de heterocedasticidad en los residuos y una posible violación de la suposición de homocedasticidad en el modelo de ANOVA.

7 Comparaciones múltiples

Independientemente del resultado obtenido en el apartado anterior, realizad un test de comparación múltiple entre los grupos con corrección de Bonferroni. Este test se aplica cuando el test ANOVA devuelve rechazar la hipótesis nula de igualdad de medias. Por lo tanto, procederemos como si el test ANOVA hubiera dado como resultado el rechazo de la hipótesis nula. Calculad las comparaciones entre grupos con la corrección Bonferroni. Podéis utilizar la función pairwise.t.test. Interpretad los resultados.

# Ejemplo de análisis de varianza (ANOVA)
modelo_anova <- aov(wage ~ league, data = star)

# Pruebas post hoc con corrección de Bonferroni
comparaciones <- pairwise.t.test(star$wage, star$league, p.adjust.method = "bonferroni")

# Mostrar los resultados de las comparaciones
print(comparaciones)
## 
##  Pairwise comparisons using t tests with pooled SD 
## 
## data:  star$wage and star$league 
## 
##                  Other   Bundesliga Premier League Primera Division
## Bundesliga       0.026   -          -              -               
## Premier League   < 2e-16 < 2e-16    -              -               
## Primera Division 1.3e-08 0.315      < 2e-16        -               
## Serie A          3.0e-08 0.214      < 2e-16        1.000           
## 
## P value adjustment method: bonferroni

Los resultados de las pruebas post hoc con corrección de Bonferroni para comparar los grupos en términos de salario (wage) son los siguientes:

Estos resultados indican las diferencias significativas en los salarios entre los diferentes niveles de la liga, después de aplicar la corrección de Bonferroni. Es importante tener en cuenta que los valores p corregidos son más conservadores y requieren una evidencia más sólida para considerar las diferencias como significativas.

8 ANOVA multifactorial

A continuación, se desea evaluar el efecto sobre wage de la liga combinado con si el jugador es internacional. Seguid los pasos que se indican a continuación.

8.1 Análisis visual de los efectos principales y posibles interacciones

Dibujad en un gráfico la variable wage en función de league y en función de international. El gráfico tiene que permitir evaluar si hay interacción entre los dos factores. Por eso, se recomienda seguir estos pasos:

  1. Agrupad el conjunto de datos por league y por international. Calculad la media de salario para cada grupo. Mostrad el conjunto de datos en forma de tabla (data frame), donde se muestre la media de cada grupo según league y international.
star$international <- ifelse(star$international == 0, "No", "Si")


media_salario <- star %>%
  group_by(league, international) %>%
  summarise(media_wage = mean(wage))
## `summarise()` has grouped output by 'league'. You can override using the
## `.groups` argument.
kable(media_salario)
league international media_wage
Other No 30886.08
Other Si 41940.68
Bundesliga No 34619.05
Bundesliga Si 63519.23
Premier League No 69668.69
Premier League Si 111532.98
Primera Division No 41078.36
Primera Division Si 91357.14
Serie A No 44039.02
Serie A Si 68833.33
  1. Mostrad en un gráfico el valor medio de la variable wage para cada factor. Interpretad el resultado sobre si solo hay efectos principales o hay interacción entre los factores. Si hay interacción, explicad cómo se observa esta interacción en el gráfico.
ggplot(media_salario, aes(x = league, y = media_wage, fill = international)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(x = "League", y = "Average Wage", fill = "International") +
  theme_minimal()

Podemos observar que hay distintos valores de salario medio para cada combinación de liga e internacionalidad. Esto indica que hay efectos principales tanto de la variable “league” como de la variable “international” en el salario medio.

Además, si examinamos los valores de salario medio para cada combinación de liga e internacionalidad, podemos notar que los valores para jugadores internacionales (Si) tienden a ser más altos que los valores para jugadores no internacionales (No) en cada liga. Esto sugiere que la variable “international” tiene un efecto principal en el salario medio.

En cuanto a la interacción entre los factores, podemos observar que la relación entre la variable “league” y la variable “international” puede variar. Por ejemplo, en la liga “Primera División”, los jugadores internacionales tienen un salario medio mucho más alto en comparación con los jugadores no internacionales, mientras que en la liga “Bundesliga” la diferencia en el salario medio entre internacionales y no internacionales es menor.

Esto indica que existe una posible interacción entre la variable “league” y la variable “international” en relación con el salario medio. La influencia de ser internacional en el salario medio puede depender de la liga en la que juega el jugador.

En resumen, los datos sugieren que tanto la variable “league” como la variable “international” tienen efectos principales en el salario medio. Además, existe una posible interacción entre los factores, lo que implica que la influencia de la internacionalidad en el salario medio puede depender de la liga en la que juega el jugador.

8.2 Cálculo del modelo ANOVA con interacción

Con el análisis ANOVA multifactorial se comprobará si esta posible interacción es significativa. Podéis usar la función aov.

modelo_anova_interaccion <- aov(wage ~ league * international, data = star)
summary(modelo_anova_interaccion)
##                        Df    Sum Sq   Mean Sq F value   Pr(>F)    
## league                  4 6.627e+11 1.657e+11  127.34  < 2e-16 ***
## international           1 2.415e+11 2.415e+11  185.61  < 2e-16 ***
## league:international    4 6.308e+10 1.577e+10   12.12 9.74e-10 ***
## Residuals            2020 2.628e+12 1.301e+09                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

8.3 Interpretación de los resultados

Explicad si los factores son significativos, así como la interacción.

El modelo ANOVA muestra los resultados para los factores “league”, “international” y la interacción “league:international”. Podemos interpretar los resultados de la siguiente manera:

  • Factor “league”: Tiene un valor de F de 127.34 y un p-valor extremadamente pequeño (< 2e-16), lo que indica que el factor “league” es altamente significativo en el modelo. Hay diferencias significativas entre las diferentes ligas en términos de salario.

  • Factor “international”: Tiene un valor de F de 185.61 y un p-valor extremadamente pequeño (< 2e-16), lo que indica que el factor “international” es altamente significativo en el modelo. Hay diferencias significativas entre los jugadores internacionales y no internacionales en términos de salario.

  • Interacción “league:international”: Tiene un valor de F de 12.12 y un p-valor muy pequeño (9.74e-10), lo que indica que la interacción es significativa en el modelo. Esto implica que la relación entre el tipo de liga y la condición de internacional tiene un efecto adicional en el salario.

9 Resumen ejecutivo

Escribid un resumen ejecutivo como si tuvierais que comunicar a una audiencia no técnica. Por ejemplo, podría ser un equipo de managers de futbolistas, a los cuales se los tiene que informar sobre las diferencias en el salario y valor de mercado de los jugadores de jugar en una liga determinada y ser o no internacional.

Descubrimos que los jugadores internacionales tienden a ganar más que los jugadores no internacionales. Encontramos que la Premier League es la liga que tiene mas estrellas, la segunda liga con mas estrellas seria la Primera División, seguida de la Serie A y la Bundesliga por orden.

Observamos que la internacionalidad de un jugador, su calificación general (overall) y la edad son factores que afectan el valor de mercado. Ser internacional y tener una calificación general más alta aumentan el valor de un jugador, mientras que la edad tiende a disminuirlo.

Además, la liga en la que juegan también influye en sus salarios. Encontramos que la Premier League es la liga que paga mejores salarios en promedio, seguida por la Serie A y la Primera División. Estas dos ligas no presentan diferencias significativas en los salarios. Por otro lado, la Bundesliga paga salarios ligeramente más bajos en comparación. La liga con mayor diferencia de salarios entre jugadores internacionales y no internacionales es la Primera División, y la que menos diferencia presenta es la Serie A.

Concluimos que la liga en la que se juega y la condición de ser internacional tienen un impacto significativo en el salario de un jugador. Además, la relación entre estos factores también influye en el salario. En promedio, la Premier League se destaca como la liga que paga más a las estrellas. En las demás ligas se paga significativamente menos.

Estos hallazgos son importantes para los managers de futbolistas, ya que les proporcionan información valiosa sobre cómo la liga y la internacionalidad influyen en los salarios de los jugadores. Esto les permite tomar decisiones estratégicas al negociar contratos y buscar oportunidades en el mercado de fichajes.