---
title: "Análisis de Componentes Principales por ligas"
format:
html:
self-contained: true
code-tools: true
---
## Contexto
```{r, include=FALSE}
###################### PRIMERO CARGA LOS PAQUETES
#install.packages("GGally")
library(pheatmap)
library(readxl)
library(DT)
###################### PRIMERO CARGA LOS PAQUETES
if (!require("pacman")) install.packages("pacman")
library(FactoMineR)
library(gplots)
library(RColorBrewer)
library(corrplot)
library(dplyr)
library(forcats) # Para manejar factores
# cargar paquetes necesarios
pacman::p_load(
FactoMineR, tidyverse, factoextra, haven, naniar, corrplot, readr, gridExtra,
incidence, easypackages, readxl, dplyr, gplots, kableExtra, apyramid,
janitor, flextable, lubridate, stringr, rio, bench, sf, cleaner, DT,
leaflet, leaflet.extras, esquisse, tseries, forecast, skimr, tsibble,
epicontacts, distcrete, epitrix, EpiEstim, projections, magrittr, binom,
ape, outbreaker2, knitr, broom, ggridges, scales
)
library(writexl)
library(GGally)
library(ggforce) # Para agregar elipses y círculos
library(htmltools)
library(pheatmap)
library(qgraph)
#install.packages("kableExtra")
#Instalar los paquetes
#if (!require("pacman")) install.packages("pacman"); pacman::p_load(effsize, gplots, naniar, corrplot, readr, gridExtra, rcompanion, flextable, incidence, easypackages, FactoMineR, tidyverse, factoextra, haven, janitor, readxl, dplyr, kableExtra, apyramid, ggplot2, tidyr, lubridate, stringr, rio, bench, sf, cleaner, DT, leaflet, leaflet.extras, esquisse, tseries, forecast, skimr, tsibble, epicontacts, distcrete, epitrix, EpiEstim, projections, magrittr, binom, ape, outbreaker2, knitr, broom, ggridges, scales, psych, plotly, DescTools, effectsize)
#if (!require("pacman")) install.packages("pacman"); pacman::p_load(caret,qgraph,webshot)
library(effsize)
#install.packages("effsize")
#install.packages("gplots")
#install.packages(c( "naniar", "corrplot"))
#install.packages("readr")
library(readr)
library(gridExtra)
# Instalar el paquete rcompanion si no está instalado
if (!requireNamespace("rcompanion", quietly = TRUE)) {
install.packages("rcompanion")
}
# Cargar el paquete
library(rcompanion)
# Mostrar la tabla con flextable
library(flextable)
library(incidence) #core functions
library(easypackages)#recargar varias librerias en una sola linea
paquetes <- c("FactoMineR", "tidyverse", "factoextra", "haven", "naniar", "corrplot")
libraries(paquetes)
#Sys.setlocale("LC_ALL", "en_US.UTF-8")
#Sys.setenv(LANG = "spa")
library(janitor)#para los comandos tably
library(readxl)
library(dplyr)
library(gplots)
library(FactoMineR)#GRAFICAR ACM
library(factoextra)
library(kableExtra)#PARA DECORAR LAS TABLAS
library(apyramid)#PARA REALIZAR PIRAMIDE
library(ggplot2)#PARA DIBUJAR
library(readxl)#PARA LEER EXCEL
library(dplyr) # manipulacion de dato
library(janitor)#para los comandos tably
library(factoextra)
library(gplots)#graficos
#if (!require("pacman")) install.packages("pacman")
# cargar paquetes necesarios
pacman::p_load(
tidyr,
dplyr,
lubridate,
stringr,
rio,
bench,
janitor,
# reclin2,
sf,
readr,
cleaner,
#plotly,
DT,
leaflet,
leaflet.extras,
esquisse.,
tseries,
tidyverse,
janitor,
forecast,
skimr,
tsibble)
#install.packages("epicontacts")
library(epicontacts)
#install.packages("distcrete")
library(distcrete)
#install.packages("epitrix")
library(epitrix)
#install.packages("EpiEstim")
library(EpiEstim)
library(projections)
library(magrittr)
library(binom)
library(ape)
library(outbreaker2)
library(knitr)
library(broom)
library(ggridges)
library(scales)
#install.packages("ggridges")
library(dplyr)
library(tidyr)
library(psych)
library(PerformanceAnalytics)
library(corrplot)
library(plotly)
library(flextable)
library(dplyr)
#install.packages(c("dplyr", "tidyverse", "readxl", "DescTools", "effectsize"))
library(dplyr)
library(readxl)
library(DescTools)
library(effectsize)
library(readxl)
library(dplyr)
```
Tenemos los siguientes datos:
```{r, include=FALSE, message=FALSE, warning=FALSE}
Player_performance_5_ligas <- read_excel("D:/nocturno/temporales/estadistica del deporte/Analisis_de_componentes_principales_Rugbi/nueva_version/Analisis_de_componentes_principales_Rugbi_op2/Analisis_de_componentes_principales_Rugbi/Player performance 5 ligas.xlsx")
#View(Player_performance_5_ligas)
#colnames(Player_performance_5_ligas)
#head(Player_performance_5_ligas[1])
#Factorizamos cada variable
Player_performance_5_ligas_ <- Player_performance_5_ligas %>%
mutate(
# Conversión de tiNation de datos
across(1:6, as.factor),across(7, as.numeric),across(8, as.factor),
across(9:124, as.numeric))
Player_performance_5_ligas_ <- Player_performance_5_ligas_ %>%
mutate(Nation = if_else(Nation == "ESP", "SPAIN", Nation))
```
```{r, echo=FALSE, message=FALSE, warning=FALSE}
datatable(
Player_performance_5_ligas_,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 1.</b> data provided .")
)
)
)
```
"[3. Confusión de variables: El artículo no distingue adecuadamente entre los efectos de la liga frente a los efectos de la nacionalidad. Los jugadores brasileños en la Ligue 1 pueden exhibir patrones ofensivos no por su nacionalidad, sino porque la Ligue 1 atrae a delanteros brasileños. Análisis de regresión con términos de interacción habrían aclarado este punto.]{.underline}" (se modifico el enfoque a ligas)
Para las ligas tenemos la siguiente distribución:
```{r, echo=FALSE, message=FALSE, warning=FALSE}
calc_ci <- function(count, total, conf.level = 0.95) {
prop <- count / total
z <- qnorm(1 - (1 - conf.level) / 2)
se <- sqrt(prop * (1 - prop) / total)
lower <- prop - z * se
upper <- prop + z * se
return(c(percent(lower, accuracy = 0.01), percent(upper, accuracy = 0.01)))
}
# Crear la tabla de frecuencias y formatear los porcentajes
table <- Player_performance_5_ligas_ %>% tabyl(Comp)%>%adorn_pct_formatting()
# Asignar nombres uniformes a las columnas
colnames(table) <- c("League", "Frecuencia", "Porcentaje")
# Calcular intervalos de confianza para las proporciones
total <- sum(table$Frecuencia)
ci <- t(apply(table[, 2, drop = FALSE], 1, function(x) calc_ci(x, total)))
colnames(ci) <- c("CI_Lower", "CI_Upper")
table <- cbind(table, ci)
datatable(
table,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel")
),
caption = htmltools::HTML(
"<span style='font-weight: bold;'>Table 2.</span> Distribution of nations."
)
)
table <- table[order(-table$Frecuencia), ]
naciones<-5
tablefrec<-table[1:naciones,1:2]
ggplot(tablefrec, aes(x = League, y = Frecuencia, fill = League)) +
geom_bar(stat = "identity") + # Mostrar eje y como porcentajes
labs(title = "Distribution of the top 10 leagues",
x = "League",
y = "Frecuency") +
theme_minimal() +
theme(legend.Nationition = "none",
axis.text.x = element_text(angle = 45, hjust = 1))
tablechi <- table(Player_performance_5_ligas_[, 4])
# Prueba chi cuadrado
chi <- chisq.test(tablechi)
chi
```
Se realizó la prueba chi-cuadrado para verificar diferencias significativas en las frecuencias de las ligas, con un valor p menor que 0,05, lo que indica que existen diferencias.
"[2. Sesgo de selección no abordado: Los jugadores con tiempo de juego reducido pueden tener métricas distorsionadas si no se ajustan por los minutos jugados. Este ajuste fortalecería el análisis.]{.underline}
4. Usar solo observaciones entre jugadores que jugaron el partido completo ("Cada observación correspondió a una aparición de partido completo por un jugador...") puede distorsionar seriamente las características de las ligas."
Para evitar el sesgo de selección no abordado, observamos el comportamiento de los partidos jugados
```{r, echo=FALSE}
summary(Player_performance_5_ligas_$MP)
```
Dado que el Q1 está en 5 partidos, se establece un umbral mínimo absoluto, por lo que se eliminan del análisis los jugadores con menos de 5 partidos.
```{r, echo=FALSE}
# ==================================================
# SOLUCIÓN 1: FILTRO DE MÍNIMOS (Cortafuegos inicial)
# ==================================================
# 1. Definir el umbral mínimo (en minutos y en 90s)
# - Recomendación: 200 minutos (aprox. 2.2 partidos completos).
# - Si tu muestra tiene muchos jugadores, usa 250 min para mayor robustez.
umbral_partidos <- 5
#umbral_90s <- umbral_minutos / 90 # Aprox 2.22
# 2. Ver cuántos jugadores tienes antes del filtro
cat("Jugadores totales en la muestra:", nrow(Player_performance_5_ligas), "\n")
# 3. Aplicar el filtro (elige UNA de las dos opciones, ambas son equivalentes)
# --- Opción A: Filtrar directamente por la columna 'Min' ---
Player_performance_5_ligas_ <- Player_performance_5_ligas_[Player_performance_5_ligas_$MP >= umbral_partidos, ]
# --- Opción B: Filtrar por la columna '90s' (si prefieres) ---
# datos_filtrados <- Player_performance_5_ligas_[Player_performance_5_ligas_$`90s` >= umbral_90s, ]
# 4. Ver cuántos jugadores quedan después del filtro
cat("Jugadores después del filtro (>= ", umbral_partidos, " partidos):", nrow(Player_performance_5_ligas_), "\n")
# 5. Calcular el porcentaje de datos descartados
porcentaje_descarte <- (1 - (nrow(Player_performance_5_ligas_) / nrow(Player_performance_5_ligas))) * 100
cat("Porcentaje de jugadores descartados por bajo numero de partidos:",
round(porcentaje_descarte, 2), "% \n")
# 6. (Opcional) Visualiza el resumen de minutos ANTES y DESPUÉS para ver el efecto
cat("\n--- Resumen de Partidos ANTES del filtro ---\n")
print(summary(Player_performance_5_ligas$MP))
cat("\n--- Resumen de Partidos DESPUÉS del filtro ---\n")
print(summary(Player_performance_5_ligas_$MP))
# 7. (Opcional) Si quieres ver qué jugadores se fueron, puedes crear un filtro inverso
# jugadores_descartados <- Player_performance_5_ligas_[Player_performance_5_ligas_$Min < umbral_minutos, ]
# View(jugadores_descartados) # Para inspeccionarlos visualmente
```
## Tratamiento de datos
" [1. Falta de claridad en la limpieza de datos: Aunque se menciona, no hay detalles sobre los criterios de exclusión, el tratamiento de valores atípicos (outliers) o la imputación de datos faltantes. Esto debe ser explícito.]{.underline}"
```{r, include=FALSE, message=FALSE}
resultados_variables_list<-list()
tabla_final_lista <-list()
Estadisticas_partidos <- c( "MP","Starts", "Min","90s","Comp" , "Age")
Estadisticas_disparo<- c( "Goals","Shots", "SoT%","G/SH","G/SoT" , "ShoDist", "ShoFK", "ShoPK", "PKatt")
# Pases Completados Totales
Estadisticas_pases <- c(
"PassTotCmp", "PassTotAtt", "PassTotCmp%", "PassTotDist", "PassTotPrgDist",
"PassShoCmp", "PassShoAtt", "PassShoCmp%",
"PassMedCmp", "PassMedAtt", "PassMedCmp%",
"PassLonCmp", "PassLonAtt", "PassLonCmp%",
"Assists", "PassAss", "Pass3rd", "PPA", "CrsPA", "PassProg",
"PassLive", "PassDead", "TB", "Sw", "PassCrs", "TI", "CK"
)
Estadisticas_acciones_creacion <- c(
"SCA", "SCAPassLive", "SCAPassDead", "SCADrib", "SCASh", "SCAFld", "SCADef", "GCA"
)
Estadisticas_acciones_creacion <- c(
"SCA", "SCAPassLive", "SCAPassDead", "SCADrib", "SCASh", "SCAFld", "SCADef", "GCA"
)
Estadisticas_defensa <- c(
"Tkl", "TklWon", "TklDef3rd", "TklMid3rd", "TklAtt3rd", "TklDri", "TklDriAtt",
"TklDri%", "TklDriPast", "Blocks", "BlkSh", "Int", "Tkl+Int", "Clr", "Err"
)
# Control del Balón y Conducciones
Estadisticas_control_balon <- c(
"Touches", "TouDefPen", "TouDef3rd", "TouMid3rd", "TouAtt3rd", "TouAttPen",
"TouLive", "ToAtt", "ToSuc", "ToSuc%", "ToTkl", "ToTkl%"
)
# Conducciones y Recepciones
Estadisticas_conducciones_recepciones <- c(
"Carries", "CarTotDist", "CarPrgDist", "CarProg", "Car3rd", "CPA",
"CarMis", "CarDis", "Rec", "RecProg"
)
# Faltas y Disciplina
Estadisticas_faltas_disciplina <- c(
"CrdY", "CrdR", "2CrdY", "Fls", "Fld", "Off"
)
# Centros
Estadisticas_centros <- c(
"AerWon", "AerLost", "AerWon%"
)
# Crear una lista con las dos categorías
lista_categorias <- list(
disparo = Estadisticas_disparo,
pases = Estadisticas_pases,
acciones_creacion = Estadisticas_acciones_creacion,
defensa = Estadisticas_defensa,
control_balon = Estadisticas_control_balon,
conducciones_recepciones = Estadisticas_conducciones_recepciones,
faltas_disciplina = Estadisticas_faltas_disciplina,
centros = Estadisticas_centros,partidos = Estadisticas_partidos
)
guardar_datos_baja_cor_diferenciados<-list()
num_categoria<-1
for (num_categoria in 1:9) {
sublista_partidos <- lista_categorias[[num_categoria]] # Usamos [[1]] para extraer el elemento, no [1] que devuelve una lista
sublista_partidos
# Seleccionar elementos según los números
#columnas_deseadas <- c(lista_categorias[1][num_categoria:length(Estadisticas_partidos)],lista_categorias$disparo[num_categoria+1:(length(Estadisticas_disparo)-1)])
columnas_deseadas <- c(sublista_partidos)
#lista_categorias[1]
columnas_deseadas#colnames(Player_performance_5_ligas)
#indices_columnas
# Obtener los índices de las columnas
indices_columnas <- which(colnames(Player_performance_5_ligas_) %in% columnas_deseadas)
# Extraer las columnas usando los índices
#analisis_pca1<-Player_performance_5_ligas_[, indices_columnas]
#anexo_mas################################################################
analisis_pca1_2<-cbind.data.frame(Player_performance_5_ligas_$Comp,Player_performance_5_ligas_[7],Player_performance_5_ligas_[9:124])
analisis_pca1_2<-Player_performance_5_ligas_[indices_columnas]
# Cargar librerías necesarias
library(dplyr)
# Asumimos que analisis_pca es tu base de datos
# Seleccionamos solo las columnas numéricas (excluimos Nation si es categórica)
numeric_vars <- analisis_pca1_2 %>%
select_if(is.numeric)
# Realizamos la prueba de Shapiro-Wilk para cada variable numérica
normality_tests <- sapply(numeric_vars, function(x) {
if (sum(!is.na(x)) > 3) { # Shapiro-Wilk requiere al menos 4 observaciones no NA
shapiro.test(x)$p.value
} else {
NA # Si hay menos de 4 observaciones, devolvemos NA
}
})
# Creamos un dataframe con los resultados de normalidad
normality_results <- data.frame(
Variable = names(numeric_vars),
P_Valor = normality_tests,
Cumple_Normalidad = ifelse(normality_tests > 0.05, "Cumple", "No Cumple"),
stringsAsFactors = FALSE
)
# Mostramos los resultados de normalidad con la interpretación
print(normality_results)
# Separamos las variables en dos subbases
# Variables que cumplen el supuesto de normalidad
vars_cumplen <- normality_results %>%
filter(Cumple_Normalidad == "Cumple") %>%
pull(Variable)
#vars_cumplen
# Variables que NO cumplen el supuesto de normalidad
vars_no_cumplen <- normality_results %>%
filter(Cumple_Normalidad == "No Cumple") %>%
pull(Variable)
# Creamos las subbases
# Subbase con variables que cumplen el supuesto (incluye la columna Nation si existe)
if (length(vars_cumplen) > 0) {
analisis_pca_cumple <- analisis_pca1_2 %>%
select(any_of(c("Comp", vars_cumplen)))
} else {
analisis_pca_cumple <- data.frame(Comp = analisis_pca1_2$Comp) # Si no hay variables, solo mantenemos Nation
}
# Subbase con variables que NO cumplen el supuesto (incluye la columna Nation si existe)
if (length(vars_no_cumplen) > 0) {
analisis_pca_no_cumple <- analisis_pca1_2 %>%
select(any_of(c("Comp", vars_no_cumplen)))
} else {
analisis_pca_no_cumple <- data.frame(Comp = analisis_pca$Comp) # Si no hay variables, solo mantenemos Nation
}
# Mostramos las subbases
print("Subbase con variables que cumplen el supuesto de normalidad:")
print(head(analisis_pca_cumple))
print("Subbase con variables que NO cumplen el supuesto de normalidad:")
print(head(analisis_pca_no_cumple))
data_corr<-analisis_pca1_2[,2:length(colnames(analisis_pca1_2))]
matriz_cor <- cor(data_corr, method = "kendall")
# Crear datos simulados
set.seed(123)
# Aplicar el código anterior
umbral <- 0.9
library(tidyverse)
cor_df <- as.data.frame(as.table(matriz_cor)) %>%
filter(Var1 != Var2) %>%
mutate(abs_cor = abs(Freq)) %>%
filter(abs_cor > umbral) %>%
select(Var1, Var2, abs_cor)
vars_alta_cor <- unique(c(as.character(cor_df$Var1), as.character(cor_df$Var2)))
vars_alta_cor
datos_baja_cor1 <- analisis_pca1_2[, !colnames(analisis_pca1_2) %in% vars_alta_cor] # Grupo de baja
guardar_datos_baja_cor_diferenciados[[num_categoria]]<-datos_baja_cor1
tabla_final_lista <- guardar_datos_baja_cor_diferenciados[[num_categoria]]
}
combined_table <- do.call(cbind, guardar_datos_baja_cor_diferenciados)
data_corr_f<-combined_table[,2:length(colnames(combined_table))]
data_corr_f <- data_corr_f %>%
select_if(is.numeric)
matriz_cor_f <- cor(data_corr_f, method = "kendall")
# Crear datos simulados
set.seed(123)
# Aplicar el código anterior
umbral <- 0.9
library(tidyverse)
cor_df_f <- as.data.frame(as.table(matriz_cor_f)) %>%
filter(Var1 != Var2) %>%
mutate(abs_cor = abs(Freq)) %>%
filter(abs_cor > umbral) %>%
select(Var1, Var2, abs_cor)
vars_alta_cor_f <- unique(c(as.character(cor_df_f$Var1), as.character(cor_df_f$Var2)))
vars_alta_cor_f
datos_baja_cor1 <- combined_table[, !colnames(combined_table) %in% vars_alta_cor] # Grupo de baja
variables_categorias_df <- data.frame(Variable = character(), Categoria = character(), stringsAsFactors = FALSE)
# Iterar sobre las variables que quedaron en datos_baja_cor1
for (var in colnames(datos_baja_cor1)) {
# Iterar sobre las categorías en lista_categorias
for (categoria in names(lista_categorias)) {
# Verificar si la variable pertenece a la categoría actual
if (var %in% lista_categorias[[categoria]]) {
# Agregar la variable y su categoría al dataframe
variables_categorias_df <- rbind(variables_categorias_df,
data.frame(Variable = var, Categoria = categoria, stringsAsFactors = FALSE))
break # Salir del bucle una vez que se encuentra la categoría
}
}
}
defensivas<-variables_categorias_df%>%filter(Categoria=="defensa"|Categoria=="disparo" |Categoria=="pases"|Categoria=="acciones_creacion" | ( (Variable=="ToTkl"|Variable=="ToTkl%"|Variable=="CrdY"|Variable=="CrdR"|Variable=="2CrdY"|Variable=="Fls")))
ofensivas<-variables_categorias_df%>%filter(Categoria=="conducciones_recepciones" | Categoria=="control_balon" & (Variable!="ToTkl"|Variable!="ToTkl%"|Variable!="Fld"|Variable!="Off"))
mixtas<-variables_categorias_df%>%filter( Categoria=="centros"|Categoria=="partidos")
# Calcular la suma de correlaciones absolutas para cada variable en matriz_cor_f
cor_sums <- rowSums(abs(matriz_cor_f), na.rm = TRUE)
# Crear un dataframe con las variables y su puntaje de correlación
cor_importance <- data.frame(
Variable = names(cor_sums),
Cor_Sum = cor_sums,
stringsAsFactors = FALSE
)
# Unir con las categorías defensivas y ofensivas
# Para Defensivas
defensivas_importance <- cor_importance %>%
filter(Variable %in% defensivas$Variable) %>%
arrange(desc(Cor_Sum)) %>% # Ordenar por puntaje de correlación descendente
slice_head(n = 10) # Seleccionar las 10 principales
# Para Ofensivas
ofensivas_importance <- cor_importance %>%
filter(Variable %in% ofensivas$Variable) %>%
arrange(desc(Cor_Sum)) %>% # Ordenar por puntaje de correlación descendente
slice_head(n = 10) # Seleccionar las 10 principales
# Para Ofensivas
mixtas_importance <- cor_importance %>%
filter(Variable %in% mixtas$Variable) %>%
arrange(desc(Cor_Sum)) %>% # Ordenar por puntaje de correlación descendente
slice_head(n = 3) # Seleccionar las 10 principales
# Mostrar el dataframe resultante
```
Tenemos las siguientes categorias de variables
```{r,echo=FALSE, warning=FALSE,message=FALSE}
variables_cat<-do.call(rbind, lista_categorias)
variables_cat1<-rbind.data.frame("Grupos"=row.names(variables_cat),variables_cat)
colnames(variables_cat1)<-c("Groups",paste(rep("Variable",26),seq(1:26)))
tagList(
datatable(
variables_cat1,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">Variable groups</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 3.</b> Variable groups.")
)
)
```
**Analizamos las variables según su grupo. Como ejemplo, tenemos** PartidosPartidos con las variables indicadas en la tabla 3.
Realizamos la prueba de normalidad. Aquellas que cumplen el supuesto se analizan por medio de la correlación de Spearman, y las que no, mediante la correlación de Kendall. Las variables con alta correlación son excluidas, ya que en la gráfica mostrarían superposiciones al generar vectores linealmente dependientes.
```{r, echo=FALSE}
print(normality_results)
pheatmap(
matriz_cor,
cluster_rows = FALSE, # Desactiva clustering/dendrograma en filas
cluster_cols = FALSE,
fontsize_row = 4, # Tamaño etiquetas filas
fontsize_col = 4, # Tamaño etiquetas columnas
display_numbers = FALSE,
fontsize_number = 2, # Mostrar valores de correlación
number_format = "%.2f", # Formato de 2 decimales
number_color = "black",
na_col = "white", # Color para celdas NA (triángulo superior)
main = "Partidos Group correlation matrix"
)
```
El umbral de correlacion 0.9 o mayores, se elige a partir del criterio del investigador y de distintas pruebas con varios valores que generaron distinto tipos de graficas no aptas para interpretacion a causa de superposiciones. Para este caso, las variables de alta correlacion son "Min", "90s" y "Starts", por tanto tomamos las variables restantes como representantes de ese grupo, el proceso se repite para todos los grupos, generando asi una depuracion 118 variables a 66.
Luego a estas 66 variables se volvio a practicar pruebas de normalidad, ninguna cumplio, se realizo entonces correlacion de kendall
```{r, echo=FALSE}
pheatmap(
matriz_cor_f,
cluster_rows = FALSE, # Desactiva clustering/dendrograma en filas
cluster_cols = FALSE,
fontsize_row = 4, # Tamaño etiquetas filas
fontsize_col = 4, # Tamaño etiquetas columnas
display_numbers = FALSE,
fontsize_number = 2, # Mostrar valores de correlación
number_format = "%.2f", # Formato de 2 decimales
number_color = "black",
na_col = "white", # Color para celdas NA (triángulo superior)
main = "Group representatives correlation matrix"
)
```
"
8.2. No está del todo claro qué métricas se consideran defensivas y cuáles ofensivas en el estudio. Claramente hay algo mal con la Tabla 1.
La métrica "Cor_Sum" presentada en la Tabla 1 necesita aclararse: qué significa y cómo se calculó. ¿Suma las correlaciones de una variable dada con las demás (para evaluar redundancia), o mide la relación con la afiliación a la liga? Esta información debe ser inequívoca.
[3.Además, ¿por qué se eligieron exactamente 10 métricas? ¿Cambiaría el resultado del estudio si se eligiera un número diferente de métricas (15 o 20, por ejemplo)?]{.underline}
7.Hay una columna etiquetada como "Cor_Sum". Por favor, especifique qué significa este término en la descripción de la tabla. "
**Evaluacion de redundancia(Cor_num)**
Se calculo a partir de la la suma de los valores absolutos de los coeficientes de correlación de Kendall de una variable \*i\* con el resto de las variables \*j\* incluidas en la matriz de correlación
```{r}
cor_sums <- rowSums(abs(matriz_cor_f), na.rm = TRUE)
```
Los grupos de variables, a su vez, pertenecen a tres grandes categorías, definidas a criterio del investigador: las que miden acciones de defensa, las que miden acciones de ataque y las mixtas. Separamos entonces las obtenidas en estas tres categorías y luego tomamos las 10 con las redundancias más bajas de cada categoría. Tomar un número diferente de variables agregaría más vectores a las gráficas, que podrían generar ruido al momento de las interpretaciones.
```{r, echo=FALSE,include=TRUE}
analisis_pca1_gen<-cbind.data.frame(Player_performance_5_ligas_[4],Player_performance_5_ligas_[7],Player_performance_5_ligas_[9:124])
data_corr_gen<-analisis_pca1_gen[,2:length(colnames(analisis_pca1_gen))]
#matriz_cor_gen <- cor(data_corr_gen, method = "kendall")
tagList(
datatable(
mixtas,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">Mixed Variables</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 4.</b> Mixed Variables.")
)
)
tagList(
datatable(
defensivas_importance,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">Defensive Variables</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 5.</b> Defensive Variables.")
)
)
tagList(
datatable(
ofensivas_importance,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">Attack Variables</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 6.</b> Attack Variables.")
)
)
```
## Análisis de Componentes principales Defensa
"4. Interpretación superficial del ACP: La asociación entre la Ligue 1 y la orientación ofensiva es descriptiva, no causal. Se necesitarían análisis de varianza (ANOVA) o modelos multinivel para probar la significancia estadística."
Realizamos entonces un análisis para las variables de defensivas por liga, primero correlacion entre sus cruces y luego por ligas:
```{r, echo=FALSE}
analisis_pca0<-cbind.data.frame(Player_performance_5_ligas_[4],Player_performance_5_ligas_[7],Player_performance_5_ligas_[9:22])
#colnames(analisis_pca0)
columnas_deseadas <- c( "MP","Comp" , "Age")
#colnames(Player_performance_5_ligas)
# Obtener los índices de las columnas
indices_columnas <- which(colnames(Player_performance_5_ligas_) %in% columnas_deseadas)
#
#indices_columnas
# Extraer las columnas usando los índices
#c(mixtas$Variable)
analisis_pca<-cbind(datos_baja_cor1[c(mixtas$Variable[4],mixtas$Variabl[1:2],mixtas$Variable[5:6])],datos_baja_cor1[, c(defensivas_importance$Variable)])
analisis_pca<-analisis_pca[,-which(colnames(analisis_pca) %in%c("SCA","Shots","PPA"))
]
#analisis_pca<-cbind(datos_baja_cor1[,c("Comp")],datos_baja_cor1[, c(mixtas$Variable[1:3])],datos_baja_cor1[, c(defensivas_importance$Variable)])
analisis_pca$Age<-analisis_pca$Age/10
analisis_pca$MP<-analisis_pca$MP/10
####################################3
result <- PCA(analisis_pca[,2:length(colnames(analisis_pca))],graph=FALSE,scale.unit = FALSE)
#result$var
#plot(result,choix="var")
analisis_pca_M<-as.matrix(analisis_pca[2:length(colnames(analisis_pca))])
brand.sc <- analisis_pca
brand.sc [ , 2:length(colnames(analisis_pca))] <- data.frame(scale(analisis_pca [ , 2:length(colnames(analisis_pca))]))
#summary(brand.sc)
corrplot::corrplot(cor(brand.sc [ , 2:length(colnames(analisis_pca))], method = "kendall") , order="hclust")
brand.mean <- aggregate (. ~ Comp , data=brand.sc , mean)
#brand.mean
rownames(brand.mean) <- brand.mean [ , 1] # la marca como nombre de filas
brand.mean <- brand.mean [ , -1] # eliminamos la columna de marca
#brand.mean
par(mar=c(1,1,1,1))
pheatmap(
as.matrix(brand.mean),
cluster_rows = FALSE, # Desactiva clustering/dendrograma en filas
cluster_cols = FALSE,
fontsize_row = 4, # Tamaño etiquetas filas
fontsize_col = 4, # Tamaño etiquetas columnas
display_numbers = TRUE,
fontsize_number = 4, # Mostrar valores de correlación
number_format = "%.2f", # Formato de 2 decimales
number_color = "black",
na_col = "white", # Color para celdas NA (triángulo superior)
main = "correlación Matrix Leagues vs Defensive variables"
)
```
Realizamos el análisis de componentes principales
```{r, echo=FALSE, include=FALSE}
brand.pc <- prcomp(brand.sc [ , 2:length(colnames(analisis_pca))])
summary(brand.pc)
par(mar=c(1,1,1,1))
plot(brand.pc , type="l")
numero_variables<-10
filas_deseadas <- c(levels(analisis_pca$Comp))
#cambiar las filas deseadas para agregar mas ligas
ligas<-as.data.frame(rownames(brand.mean))
# Obtener los índices de las columnas
indices_filas <- which(ligas$`rownames(brand.mean)` %in% filas_deseadas)
indices_filas
brand.mean<-brand.mean[indices_filas,1:numero_variables]
brand.mu.pc <- prcomp(brand.mean , scale=TRUE)
summary(brand.mu.pc)
#brand.mu.pc$center
biplot(brand.mu.pc , main="Lagues vs defensive variables" , cex=c(0.55 , 0.55))
summary(brand.mu.pc)
# Normalizar las variables numéricas
data_pca_scaled <- scale(select(analisis_pca, -Comp))
# Aplicar PCA
pca_result <- prcomp(data_pca_scaled, center = TRUE, scale. = TRUE)
# Convertir los resultados del PCA en un dataframe para graficar
pca_df <- as.data.frame(pca_result$x)
pca_df
pca_df$Comp <- analisis_pca$Comp # Agregar la Nationición del jugador
# Obtener valores únicos de League en tablefrec
unique_leagues <- unique(tablefrec$League)
unique_leagues
# Filtrar pca_df con los valores únicos de League
pca_df_filtered <- pca_df %>% filter(Comp %in% unique_leagues)
# Graficar PCA con ggplot2
library(ggplot2)
pca_Nation<-ggplot(pca_df_filtered, aes(x = PC1, y = PC2, color = Comp)) +
geom_point(alpha = 0.7) +
theme_minimal() +
labs(title = "PCA for players leagues", x = "Principal Component 1", y = "Principal Component 2")
pca_Nation
#Los porteros tienden a estar más dispersos hacia PC1 Nationitivo (valores entre 5 y 10). Esto indica que los porteros tienen características que los diferencian notablemente de otras Nationiciones en las variables que contribuyen a PC1.
#Delanteros (FW, verde): Los delanteros también están más dispersos hacia PC1 Nationitivo, pero menos que los porteros. Esto sugiere que comparten algunas características con los porteros en PC1, pero son menos extremos
# Graficar un Biplot para ver la contribución de cada variable
par(mar=c(1,1,1,1))
biplot(pca_result, scale = 0)
fviz_pca_var(pca_result, col.var = "cos2",
geom.var = "arrow",
labelsize = 2,
repel = FALSE)
par(mar=c(1,1,1,1))
biplot(pca_result, scale = 0, cex = 0.5, col = c("dodgerblue3", "deeppink3"))
```
**Rotacional**
Se muestra a continuación la matriz de rotación, que indica cuánto contribuye cada variable original a cada componente principal. Los valores (cargas) oscilan entre -1 y 1; cuanto mayor sea su valor absoluto, mayor será la contribución de la variable al componente.
En el caso de la **dimensión 1**, observamos que las cargas más altas son todas positivas y corresponden a `Tkl+Int` (0,51), `Tkl` (0,44), `Int` (0,43), `TklDriAtt` (0,40), `Clr` (0,30) y `BlkSh` (0,28). Esto implica que los valores elevados en este componente se asocian a un mayor volumen de acciones defensivas de interrupción y despeje, por lo que lo denominaremos **"volumen e intensidad defensiva directa"**.
En cuanto a la **dimensión 2**, las cargas positivas más altas corresponden a `Clr` (0,44), `BlkSh` (0,41) y `AerWon` (0,40), mientras que las negativas más destacadas son `ToTkl` (-0,43), `TklDriAtt` (-0,30) y `Tkl` (-0,27). Por lo tanto, los valores positivos de esta dimensión reflejan un perfil defensivo basado en acciones aéreas y bloqueos, mientras que los valores negativos reflejan un perfil basado en duelos en el suelo y presión directa, lo denominaremos **Calidad/Estilo del trabajo defensivo**.
```{r, echo=FALSE}
pca_result$rotation[,1:2]
tagList(
datatable(
pca_result$rotation[,1:2],
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">Rotaltional</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 7.</b> PCA Rotational.")
)
)
```
**Varianza**
El componente principal 1 (PC1) explica el 31,27 % de la varianza total del conjunto de variables defensivas, mientras que el componente 2 (PC2) explica el 19,66 %. En conjunto, las dos primeras dimensiones retienen el 50,93 % de la varianza total, esto se debe a una alta variabilidad en los datos y conteos de acciones con distribuciones asimétricas, se puede decir centrarse en las dos primeras dimensiones permite una interpretación que no pierde una cantidad sustancial de información, facilitando la discusión de los perfiles defensivos en términos de "volumen" (PC1) y "estilo" (PC2).
La grafica de proporcion de varianza nos muestra, a partir del tercer componente, esta cae por debajo del 15 % (PC3 = 14,96 %), y el resto de componentes aportan cada vez menos información relevante (PC4 = 8,9 %, PC5 = 7,9 %...).
```{r,echo=FALSE}
summary(pca_result)$importance[, 1:2]
prop_varianza <- pca_result$sdev^2 / sum(pca_result$sdev^2)
ggplot(data = data.frame(prop_varianza, pc = 1:length(prop_varianza)),
aes(x = pc, y = prop_varianza)) +
geom_col(width = 0.3) +
scale_y_continuous(limits = c(0,1)) +
theme_bw() +
labs(x = "Componente principal",
y = "Prop. de varianza explicada")
par(mar=c(1,1,1,1))
plot(brand.pc , type="l")
```
**Graficas PCA**
**Análisis por jugador**
En el análisis de componentes principales sobre variables defensivas no se observa un comportamiento marcado de alguno de los conjuntos de puntos, es decir no hay una separación clara entre los jugadores de las cinco grandes ligas europeas. Los centroides de las ligas se agrupan en una región reducida del plano (PC1 entre –0.20 y 0.31; PC2 entre –0.32 y 0.12), y las nubes de puntos individuales se superponen. Podemos decir entonces que las variables de defensa aumenten o disminuyan, no dependerán de la liga en la que se esté compitiendo. Solo se observa una ligera tendencia de la Ligue 1 hacia un mayor volumen de acciones defensivas y un menor énfasis en el juego aéreo, aunque esta diferencia es pequeña.
```{r, echo=FALSE}
# Calcular centroides (medias por liga)
centroids <- pca_df_filtered %>%
group_by(Comp) %>%
summarise(PC1_mean = mean(PC1),
PC2_mean = mean(PC2))
# Graficar con centroides añadidos
pca_Nation1 <- ggplot(pca_df_filtered, aes(x = PC1, y = PC2, color = Comp)) +
geom_point(alpha = 0.4, size = 1.5) + # puntos individuales
stat_ellipse(aes(fill = Comp), alpha = 0.1, geom = "polygon") + # elipses de confianza
geom_point(data = centroids, aes(x = PC1_mean, y = PC2_mean, color = Comp),
size = 5, shape = 13, stroke = 2) + # centroides como cruces grandes
theme_minimal() +
labs(title = "ACP defensivo por ligas",
x = paste0("PC1 (31.3%)"),
y = paste0("PC2 (19.7%)"),
color = "Liga") +
geom_hline(yintercept = 0, linetype = "dashed", color = "gray") +
geom_vline(xintercept = 0, linetype = "dashed", color = "gray")
pca_Nation1
centroids
```
**Análisis por ligas**
Vemos que ciertas variables se acercan a ciertas ligas, es decir, que en esas ligas, sus medias son altas tenemos: Ligue 1 se ubicará hacia la derecha del biplot, en la dirección de las flechas de Tkl, Int, Tkl+Int y probablemente ToTkl (regates defensivos intentados). Esto confirma que, en promedio, la Ligue 1 es la liga más intensa en recuperación de balón y duelos en el suelo.
La Liga y Serie A se ubicarán hacia la zona donde apuntan las flechas de AerWon (duelos aéreos ganados) y Clr (despejes), y quizás Age (mayor edad defensiva), indicando un perfil más posicional y aéreo.
Bundesliga y Premier League quedaron en una posición intermedia, sin un sesgo claro hacia ningún extremo, confirmando que sus promedios defensivos son muy similares a las demás ligas.
```{r}
par(mar=c(1,1,1,1))
biplot(brand.mu.pc , main="Lagues vs defensive variables" , cex=c(0.55 , 0.55))
```
**Análisis de cosenos cuadrados**
Este gráfico nos indica para cuáles variables tienen mayor peso las interpretaciones alcanzadas, en función de su contribución a la explicación de la varianza en las dimensiones determinadas. A mayor valor del coseno cuadrado, mayor relevancia tendrá esa variable en la discusión de los resultados.
Las variables con los cosenos cuadrados más altos fueron Tkl+Int (0,286), Clr (0,278), Tkl (0,271), BlkSh (0,251) y TklDriAtt (0,246), lo que señala que estas cinco variables describen adecuadamente la estructura subyacente de las acciones defensivas.
Por el contrario, los valores más bajos de cos2 corresponden a MP (0,008), AerLost (0,035) y Age (0,068). En consecuencia, las interpretaciones de sus posiciones en el biplot no deben considerarse representativas, ya que su variabilidad no queda explicada satisfactoriamente por los componentes principales aquí generados.
```{r, echo=FALSE}
# Coordenadas de las variables (loadings)
coordenadas <- pca_result$rotation[, 1:2]
# Calcular cos2 (calidad de representación en el plano 1-2)
cos2 <- coordenadas^2
cos2_total <- rowSums(cos2) # suma de cuadrados en PC1 y PC2
# Crear tabla con coordenadas y cos2
tabla_var <- data.frame(
Variable = rownames(coordenadas),
PC1 = coordenadas[, 1],
PC2 = coordenadas[, 2],
cos2_PC1 = cos2[, 1],
cos2_PC2 = cos2[, 2],
cos2_total = cos2_total
)
# Mostrar ordenado por cos2 total descendente
tagList(
datatable(
tabla_var[order(-tabla_var$cos2_total), ][2:3],
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">PCA Cos^2</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 8.</b> PCA Cos^2.")
)
)
par(mar=c(1,1,1,1))
fviz_pca_var(pca_result, col.var = "cos2",
geom.var = "arrow",
labelsize = 2,
repel = FALSE)
```
**Análisis anova**
Para contrastar si las diferencias observadas en las puntuaciones de los componentes principales entre las cinco grandes ligas europeas alcanzan significancia estadística, se presentan los resultados de los análisis de varianza (ANOVA) realizados a la dos primeras dimensiones.
```{r, echo=FALSE}
# ANOVA para PC1 (volumen defensivo)
aov_PC1 <- aov(PC1 ~ Comp, data = pca_df_filtered)
#summary(aov_PC1)
#aov_PC1
# ANOVA para PC2 (estilo defensivo)
aov_PC2 <- aov(PC2 ~ Comp, data = pca_df_filtered)
#aov_PC2
#summary(aov_PC2)
# Si alguno es significativo (p < 0.05), haz pruebas post-hoc (Tukey)
#TukeyHSD(aov_PC1)
#TukeyHSD(aov_PC2)
# Crear dataframe manual con los resultados de los ANOVA
tabla_anova <- data.frame(
Componente = c("PC1 (Defensive volumen)", "PC2 (Defensive style: Air vs. grass)"),
gl = c(4, 4), # Grados de libertad del factor (ligas)
SS_factor = c(64.989, 57.188), # Suma de cuadrados entre ligas
SS_residual = c(7039.014, 4407.615), # Suma de cuadrados residual (dentro de ligas)
F = c(4.757, 6.685), # Estadístico F
p = c(0.000804, 0.0000241) # p-valor (PC2 es 2.41e-05)
)
# Calcular eta cuadrado (η² = SS_factor / (SS_factor + SS_residual))
tabla_anova <- tabla_anova %>%
mutate(
eta_cuadrado = round(SS_factor / (SS_factor + SS_residual), 4),
p_formateado = ifelse(p < 0.001, "< 0.001", as.character(round(p, 4))),
# Interpretación cualitativa del tamaño del efecto según Cohen (1988)
interpretacion_eta = case_when(
eta_cuadrado < 0.01 ~ "Muy pequeño (< 0.01)",
eta_cuadrado >= 0.01 & eta_cuadrado < 0.06 ~ "Pequeño (0.01 - 0.05)",
eta_cuadrado >= 0.06 & eta_cuadrado < 0.14 ~ "Mediano (0.06 - 0.13)",
eta_cuadrado >= 0.14 ~ "Grande (≥ 0.14)"
)
)
# Seleccionar columnas para mostrar en la tabla final
tabla_final_anova <- tabla_anova %>%
select(Componente, gl, SS_factor, SS_residual, F, p_formateado, eta_cuadrado, interpretacion_eta)
tagList(
datatable(
tabla_final_anova,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">PCA Anova</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 9.</b> PCA Anova.")
)
)
```
Para PC1 y PC2 se encontraron diferencias significativas entre ligas. Sin embargo, el tamaño del efecto, medido mediante eta cuadrado, fue de 0,0091 para PC1 y de 0,0128 para PC2. Según los criterios de Cohen, estos valores se consideran muy pequeños o pequeños, lo que indica que la pertenencia a una liga explica menos del 1,3 % de la varianza total en ambos componentes. En consecuencia, la variabilidad defensiva está determinada fundamentalmente por factores individuales o tácticos internos a cada competición, y no por la pertenencia a una liga específica, las interpretaciones obtenidas deben considerarse como descriptivas y no inferenciales.
**Análisis post-hoc**
"10.Presentación y Análisis de Resultados – Prueba de Hipótesis: En su forma actual, los resultados se basan principalmente en la interpretación descriptiva de los gráficos ACP (distribución de observaciones y cargas de variables). Para aumentar la fuerza probatoria del trabajo, se recomienda complementar los resultados con pruebas estadísticas o métricas que confirmen las diferencias entre grupos. Por ejemplo, después de realizar el ACP, se puede probar si las ligas individuales o los grupos de nacionalidad difieren significativamente en sus valores de componentes principales (PC1, PC2) – por ejemplo, usando ANOVA o pruebas post-hoc – y proporcionar tamaños del efecto. Actualmente, el lector debe confiar en la evaluación subjetiva de los gráficos, lo que puede plantear dudas sobre la significancia de las diferencias observadas. También es aconsejable proporcionar valores numéricos específicos que ilustren las diferencias (por ejemplo, "los jugadores de la Ligue 1 realizan en promedio un X% más de acciones ofensivas que los jugadores de la Premier League en nuestro conjunto de datos", si se hicieron tales comparaciones). Esto hará que las conclusiones sean más específicas y convincentes. Si la hipótesis del estudio era la existencia de diferencias técnicas y tácticas medibles dependiendo de la liga y la nacionalidad (como implica el objetivo del estudio), los resultados deben probar directamente esta hipótesis o refutarla claramente. Es importante asegurarse de que la narrativa de los resultados aborde la pregunta de investigación y no simplemente presente una imagen general de los datos."
Las medias de las puntuaciones en los componentes principales para cada liga nos dicen que la Ligue 1 presentó la media más alta en, mientras que La Liga mostró la más baja. Las pruebas post‑hoc de Tukey revelaron que la Ligue 1 difiere significativamente de La Liga y de la Serie A en PC1, con diferencias medias de 0.512 y 0.430 unidades, respectivamente, esto se interpeta como que los jugadores de la Ligue 1 presentan, en promedio, un 25 % más de acciones defensivas de recuperación (entradas + intercepciones + despejes) que los de La Liga.
En PC2, la Ligue 1 también se diferenció significativamente de la Bundesliga y de la Premier League , con una media más negativa, lo que indica un perfil defensivo menos aéreo y más orientado a duelos en el suelo en comparación con esas ligas. El tamaño del efecto global confirma que estas diferencias, pueden llegar a ser estadísticamente significativas, pero explican una proporción muy reducida de la varianza total.
```{r, echo=FALSE}
# -------------------------------------------
tabla_medias <- pca_df_filtered %>%
group_by(Comp) %>%
summarise(
n = n(),
PC1_mean = mean(PC1),
PC1_sd = sd(PC1),
PC2_mean = mean(PC2),
PC2_sd = sd(PC2)
) %>%
mutate(
# Formato: Media (DE)
PC1 = paste0(round(PC1_mean, 3), " (", round(PC1_sd, 3), ")"),
PC2 = paste0(round(PC2_mean, 3), " (", round(PC2_sd, 3), ")")
) %>%
select(Liga = Comp, n, PC1, PC2)
# -------------------------------------------
# TABLA 2: COMPARACIONES POST-HOC SIGNIFICATIVAS (Tukey) CON INTERPRETACIÓN
# -------------------------------------------
# Extraer comparaciones significativas para PC1
posthoc_PC1 <- as.data.frame(TukeyHSD(aov_PC1)$Comp) %>%
filter(`p adj` < 0.05) %>%
rownames_to_column("Par_de_ligas") %>%
mutate(
Componente = "PC1 (Volumen defensivo)",
Diferencia = round(diff, 3),
`p_ajustado` = round(`p adj`, 4),
# Interpretación cualitativa de PC1
Interpretacion = case_when(
diff > 0 ~ paste0("La liga '", sub("-(.*)", "", Par_de_ligas),
"' presenta MAYOR volumen de acciones defensivas (entradas, intercepciones y despejes) que '",
sub(".*-", "", Par_de_ligas), "'."),
diff < 0 ~ paste0("La liga '", sub("-(.*)", "", Par_de_ligas),
"' presenta MENOR volumen de acciones defensivas que '",
sub(".*-", "", Par_de_ligas), "'.")
)
) %>%
select(Componente, Par_de_ligas, Diferencia, `p_ajustado`, Interpretacion)
# Extraer comparaciones significativas para PC2
posthoc_PC2 <- as.data.frame(TukeyHSD(aov_PC2)$Comp) %>%
filter(`p adj` < 0.05) %>%
rownames_to_column("Par_de_ligas") %>%
mutate(
Componente = "PC2 (Estilo: aéreo vs. suelo)",
Diferencia = round(diff, 3),
`p_ajustado` = round(`p adj`, 4),
# Interpretación cualitativa de PC2 (recordar: positivo = aéreo, negativo = suelo)
Interpretacion = case_when(
diff > 0 ~ paste0("La liga '", sub("-(.*)", "", Par_de_ligas),
"' tiene un perfil MÁS AÉREO (más despejes, bloqueos y duelos de cabeza) que '",
sub(".*-", "", Par_de_ligas), "'."),
diff < 0 ~ paste0("La liga '", sub("-(.*)", "", Par_de_ligas),
"' tiene un perfil MÁS ORIENTADO AL SUELO (más duelos y entradas en contacto directo) que '",
sub(".*-", "", Par_de_ligas), "'.")
)
) %>%
select(Componente, Par_de_ligas, Diferencia, `p_ajustado`, Interpretacion)
# Unir ambas tablas post-hoc
tabla_posthoc <- bind_rows(posthoc_PC1, posthoc_PC2)
tagList(
datatable(
tabla_medias,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">Mean and SD PCA</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 10.</b>Mean and SD PCA.")
)
)
tagList(
datatable(
tabla_posthoc,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">Post-Hoc</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 11.</b>Post Hoc.")
)
)
```
## Análisis de Componentes principales ataque
Realizamos el análisis para variables de ataque, primero mostramos la correlacion entre sus cruces y luego por ligas:
```{r, echo=FALSE}
analisis_pca2<-cbind(datos_baja_cor1[, c(mixtas$Variable[4],mixtas$Variabl[1:2])],datos_baja_cor1[, c(ofensivas_importance$Variable)])
variables_a_eliminar <- c("AerWon", "AerLost", "TouDef3rd", "TouDefPen", "ToTkl")
analisis_pca2 <- analisis_pca2[, !(colnames(analisis_pca2) %in% variables_a_eliminar)]
analisis_pca2$TouAtt3rd<-log(analisis_pca2$TouAtt3rd+1)
analisis_pca2$RecProg<-log(analisis_pca2$RecProg+1)
analisis_pca2$TouAttPen<-log(analisis_pca2$TouAttPen+1)
result1 <- PCA(analisis_pca2[,2:length(colnames(analisis_pca2))],graph=FALSE,scale.unit = FALSE)
#result$var
#plot(result1,choix="var")
analisis_pca2<-cbind(datos_baja_cor1[, c(mixtas$Variable[4],mixtas$Variabl[1:2])],datos_baja_cor1[, c(ofensivas_importance$Variable)])
variables_a_eliminar <- c("AerWon", "AerLost", "TouDef3rd", "TouDefPen", "ToTkl")
analisis_pca2 <- analisis_pca2[, !(colnames(analisis_pca2) %in% variables_a_eliminar)]
analisis_pca2$TouAtt3rd<-log(analisis_pca2$TouAtt3rd+1)
analisis_pca2$RecProg<-log(analisis_pca2$RecProg+1)
analisis_pca2$TouAttPen<-log(analisis_pca2$TouAttPen+1)
analisis_pca_M2<-as.matrix(analisis_pca2[2:length(colnames(analisis_pca2))])
brand.sc1 <- analisis_pca2
brand.sc1 [ , 2:length(colnames(analisis_pca2))] <- data.frame(scale(analisis_pca2 [ , 2:length(colnames(analisis_pca2))]))
#summary(brand.sc)
corrplot::corrplot(cor(brand.sc1 [ , 2:length(colnames(analisis_pca2))], method = "kendall") , order="hclust")
brand.mean1 <- aggregate (. ~ Comp , data=brand.sc1 , mean)
#brand.mean
rownames(brand.mean1) <- brand.mean1 [ , 1] # la marca como nombre de filas
brand.mean1 <- brand.mean1 [ , -1] # eliminamos la columna de marca
#brand.mean
par(mar=c(1,1,1,1))
pheatmap(
as.matrix(brand.mean1),
cluster_rows = FALSE, # Desactiva clustering/dendrograma en filas
cluster_cols = FALSE,
fontsize_row = 4, # Tamaño etiquetas filas
fontsize_col = 4, # Tamaño etiquetas columnas
display_numbers = TRUE,
fontsize_number = 5, # Mostrar valores de correlación
number_format = "%.2f", # Formato de 2 decimales
number_color = "black",
na_col = "white", # Color para celdas NA (triángulo superior)
main = "Correlación matrix "
)
```
Realizamos el análisis de componentes principales
```{r, include=FALSE,message=FALSE, warning=FALSE}
brand.pc1 <- prcomp(brand.sc1 [ , 2:length(colnames(analisis_pca2))])
#summary(brand.pc)
par(mar=c(1,1,1,1))
plot(brand.pc1 , type="l")
numero_variables<-7
filas_deseadas <- c(levels(analisis_pca2$Comp))
#cambiar las filas deseadas para agregar mas ligas
ligas<-as.data.frame(rownames(brand.mean1))
# Obtener los índices de las columnas
indices_filas <- which(ligas$`rownames(brand.mean1)` %in% filas_deseadas)
indices_filas
brand.mean1<-brand.mean1[indices_filas,1:numero_variables]
#brand.mean1<-cbind(brand.mean1[1:3],brand.mean1[5:7])
brand.mu.pc1 <- prcomp(brand.mean1 , scale=TRUE)
summary(brand.mu.pc)
#brand.mu.pc$center
#biplot(brand.mu.pc1 , main="Leagues" , cex=c(0.7 , 0.7))
brand.mu.pc1 <- prcomp(brand.mean1 , scale=TRUE)
summary(brand.mu.pc1)
#brand.mu.pc$center
biplot(brand.mu.pc1 , main="League vs attack variables" , cex=c(0.55 , 0.55))
#summary(brand.mu.pc1)
# Normalizar las variables numéricas
data_pca_scaled1 <- scale(select(analisis_pca2, -Comp))
# Aplicar PCA
pca_result1 <- prcomp(data_pca_scaled1, center = TRUE, scale. = TRUE)
pca_result1
# Convertir los resultados del PCA en un dataframe para graficar
pca_df1 <- as.data.frame(pca_result1$x)
#pca_df
pca_df1$Comp <- analisis_pca2$Comp # Agregar la Nationición del jugador
# Obtener valores únicos de League en tablefrec
unique_leagues <- unique(tablefrec$League)
# Filtrar pca_df con los valores únicos de League
pca_df_filtered1 <- pca_df1 %>% filter(Comp %in% unique_leagues)
# Graficar PCA con ggplot2
pca_Nation1<-ggplot(pca_df_filtered1, aes(x = PC1, y = PC2, color = Comp)) +
geom_point(alpha = 0.7) +
theme_minimal() +
labs(title = "PCA for players leagues", x = "Principal Component 1", y = "Principal Component 2")
pca_Nation1
# Graficar un Biplot para ver la contribución de cada variable
#par(mar=c(1,1,1,1))
#biplot(pca_result, scale = 0)
fviz_pca_var(pca_result1, col.var = "cos2",
geom.var = "arrow",
labelsize = 2,
repel = FALSE)
par(mar=c(1,1,1,1))
#biplot(pca_result, scale = 0, cex = 0.5, col = c("dodgerblue3", "deeppink3"))
```
**Rotacional**
Se muestra a continuación la matriz de rotación del análisis de componentes principales para las variables ofensivas.
En la **dimensión 1**, observamos que **todas las cargas son negativas y de magnitud muy similar**, oscilando entre -0,32 (`Car3rd`) y -0,42 (`RecProg`). Las cargas más altas en valor absoluto corresponden a `RecProg` (-0,42), `TouAtt3rd` (-0,40), `ToAtt` (-0,38) y `TouAttPen` (-0,38). Dado que todas las variables contribuyen con el mismo signo y una intensidad comparable, este componente no separa distintos tipos de ataque, sino que mide el **volumen global de participación ofensiva** se denomina **"volumen de implicación ofensiva"**.
La **dimensión 2**, presenta un marcado carácter bipolar que diferencia dos estilos ofensivos claramente opuestos. Las **cargas positivas** más altas corresponden a `Car3rd` (0,72), `TouAtt3rd` (0,20) y `ToAtt` (0,19). Por su parte, las **cargas negativas** más destacadas son `TouAttPen` (-0,48), `CarMis` (-0,38), `CPA` (-0,13) y `RecProg` (-0,04). En consecuencia, los **valores positivos** de esta dimensión reflejan un perfil ofensivo basado en la **progresión y presencia en el último tercio**, acciones que alcanzan el tercio ofensiv, sin llegar al área. Los **valores negativos**, muestran acciones de **penetración y finalización en el área rival**, se denomina **"estilo ofensivo: progresión fuera del área vs dentro del área"**.
```{r, echo=FALSE}
pca_result1$rotation[,1:2]
tagList(
datatable(
pca_result1$rotation[,1:2],
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">PCA attack rotational</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 12.</b> PCA attack rotational.")
)
)
```
**Varianza**
La componente principal 1 (PC1) explica el 69,10 % de la varianza total del conjunto de variables ofensivas, mientras que la componente 2 (PC2) explica el 11,38 %. En conjunto, las dos primeras dimensiones retienen el 80,48 % de la varianza total.
```{r, echo=FALSE}
summary(pca_result1)$importance[, 1:2]
prop_varianza1 <- pca_result1$sdev^2 / sum(pca_result1$sdev^2)
ggplot(data = data.frame(prop_varianza1, pc = 1:length(prop_varianza1)),
aes(x = pc, y = prop_varianza1)) +
geom_col(width = 0.3) +
scale_y_continuous(limits = c(0,1)) +
theme_bw() +
labs(x = "Componente principal",
y = "Prop. de varianza explicada")
par(mar=c(1,1,1,1))
plot(brand.pc , type="l")
```
**Graficas PCA**
**Análisis por jugador**
En el análisis de componentes principales sobre las variables ofensivas, no se observa un comportamiento marcado de alguno de los conjuntos de puntos, es decir no hay una separación clara entre los jugadores de las cinco grandes ligas europeas.
```{r, echo=FALSE}
# Calcular centroides (medias por liga)
centroids1 <- pca_df_filtered1 %>%
group_by(Comp) %>%
summarise(PC1_mean = mean(PC1),
PC2_mean = mean(PC2))
# Graficar con centroides añadidos
pca_Nation1 <- ggplot(pca_df_filtered1, aes(x = PC1, y = PC2, color = Comp)) +
geom_point(alpha = 0.4, size = 1.5) + # puntos individuales
stat_ellipse(aes(fill = Comp), alpha = 0.1, geom = "polygon") + # elipses de confianza
geom_point(data = centroids1, aes(x = PC1_mean, y = PC2_mean, color = Comp),
size = 5, shape = 13, stroke = 2) + # centroides como cruces grandes
theme_minimal() +
labs(title = "Offensive ACP by players league",
x = paste0("PC1 (69.1%)"),
y = paste0("PC2 (11.3%)"),
color = "Liga") +
geom_hline(yintercept = 0, linetype = "dashed", color = "gray") +
geom_vline(xintercept = 0, linetype = "dashed", color = "gray")
pca_Nation1
centroids1
```
**Análisis por ligas**
Vemos que ciertas variables ofensivas se asocian a ligas concretas, lo que indica que en esas competiciones las medias de dichas variables son más elevadas. La *Ligue 1* se proyecta hacia el extremo negativo de PC1, en la dirección de las flechas de `TouAttPen` (toques en el área penal) y `CarMis` (pérdidas de balón en conducción). Esto indica que, en promedio, la *Ligue 1* es la liga con mayor volumen de penetración en el área rival, aunque con una mayor frecuencia de pérdidas en las conducciones ofensivas.
La *Bundesliga* se sitúa en el extremo positivo de PC2, en la dirección de `Car3rd` (conducciones en el último tercio) y, en menor medida, `ToAtt` (regates intentados), lo que refleja un perfil ofensivo basado en la progresión externa y la conducción sin llegar a penetrar masivamente en el área penal.
*La Liga* y *Serie A* se posicionan en el lado opuesto de la *Ligue 1* en el eje de volumen ofensivo (PC1), lo que sugiere que presentan los menores volúmenes de acciones ofensivas entre las cinco ligas, con una menor frecuencia de toques en el área y recepciones progresivas.
La *Premier League* ocupa una posición intermedia en ambos ejes, sin un sesgo claro hacia ningún extremo, lo que indica que su perfil ofensivo promedio se asemeja al conjunto global de las ligas analizadas.
```{r, echo=FALSE}
par(mar=c(1,1,1,1))
biplot(brand.mu.pc1 , main="Lagues vs offensive variables" , cex=c(0.55 , 0.55))
```
**Análisis de cosenos cuadrados**
Para la explicación de contribución de varianza en el análisis de variables de ataque los más altos fueron `Car3rd` (0,629), `TouAttPen` (0,377), `CarMis` (0,276), `TouAtt3rd` (0,203) y `ToAtt` (0,183), lo que indica que estas variables describen adecuadamente las acciones ofensivas, se destaca `Car3rd`, cuyo cos2 de 0,629 indica que más del 60 % de su variabilidad queda explicada.
`RecProg` (0,179) y `CPA` (0,154) presentan los valores más bajos de cos2, esto nos dice que todas las variables ofensivas incluidas cuentan con una representación aceptable en el plano PC1–PC2.
```{r, echo=FALSE}
# Coordenadas de las variables (loadings)
coordenadas1 <- pca_result1$rotation[, 1:2]
# Calcular cos2 (calidad de representación en el plano 1-2)
cos21 <- coordenadas1^2
cos2_total1 <- rowSums(cos21) # suma de cuadrados en PC1 y PC2
# Crear tabla con coordenadas y cos2
tabla_var1 <- data.frame(
Variable = rownames(coordenadas1),
PC1 = coordenadas1[, 1],
PC2 = coordenadas1[, 2],
cos2_PC1 = cos21[, 1],
cos2_PC2 = cos21[, 2],
cos2_total = cos2_total1
)
# Mostrar ordenado por cos2 total descendente
tagList(
datatable(
tabla_var1[order(-tabla_var1$cos2_total), ][2:3],
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">PCA Attack Cos^2</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 13.</b> PCA attack Cos^2.")
)
)
par(mar=c(1,1,1,1))
fviz_pca_var(pca_result1, col.var = "cos2",
geom.var = "arrow",
labelsize = 2,
repel = FALSE)
```
**Análisis Anova**
```{r, echo=FALSE}
# ANOVA para PC1
aov_PC11 <- aov(PC1 ~ Comp, data = pca_df_filtered1)
#summary(aov_PC11)
#aov_PC1
# ANOVA para PC2 (estilo defensivo)
aov_PC21 <- aov(PC2 ~ Comp, data = pca_df_filtered1)
#aov_PC2
#summary(aov_PC2)
# Si alguno es significativo (p < 0.05), haz pruebas post-hoc (Tukey)
#TukeyHSD(aov_PC1)
#TukeyHSD(aov_PC2)
# Crear dataframe manual con los resultados de los ANOVA ofensivos
tabla_anova_ofensiva <- data.frame(
Componente = c("PC1 (Volumen ofensivo)", "PC2 (Estilo ofensivo: progresión vs. penetración)"),
gl = c(4, 4), # Grados de libertad del factor (ligas)
SS_factor = c(34, 57.188), # Suma de cuadrados entre ligas
SS_residual = c(9955, 4407.615), # Suma de cuadrados residual (dentro de ligas)
F = c(1.740, 6.685), # Estadístico F
p = c(0.138, 0.0000241) # p-valor
)
# Calcular eta cuadrado (η² = SS_factor / (SS_factor + SS_residual))
tabla_anova_ofensiva <- tabla_anova_ofensiva %>%
mutate(
eta_cuadrado = round(SS_factor / (SS_factor + SS_residual), 4),
p_formateado = ifelse(p < 0.001, "< 0.001", as.character(round(p, 4))),
# Interpretación cualitativa del tamaño del efecto según Cohen (1988)
interpretacion_eta = case_when(
eta_cuadrado < 0.01 ~ "Muy pequeño (< 0.01)",
eta_cuadrado >= 0.01 & eta_cuadrado < 0.06 ~ "Pequeño (0.01 - 0.05)",
eta_cuadrado >= 0.06 & eta_cuadrado < 0.14 ~ "Mediano (0.06 - 0.13)",
eta_cuadrado >= 0.14 ~ "Grande (≥ 0.14)"
)
)
# Seleccionar columnas para mostrar en la tabla final
tabla_final_anova_ofensiva <- tabla_anova_ofensiva %>%
select(Componente, gl, SS_factor, SS_residual, F, p_formateado, eta_cuadrado, interpretacion_eta)
tabla_final_anova_ofensiva
tagList(
datatable(
tabla_final_anova_ofensiva,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">PCA attack - ANOVA</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 14.</b>PCA attack - ANOVA.")
)
)
```
En el componente PC1 (Volumen ofensivo) **no se encontraron diferencias significativas entre ligas, con un tamaño del efecto muy pequeño. Esto indica que el volumen global de acciones ofensivas (toques en el último tercio, recepciones progresivas, regates, etc.) no difiere de manera estadísticamente significativa entre las cinco grandes ligas, y que las ligeras diferencias observadas en los gráficos son descriptivas y no infieren variabilidad interna de cada competición.
En el componente PC2 (Estilo ofensivo: progresión externa vs. penetración interna), **sí se encontraron diferencias significativas entre ligas**, con un tamaño del efecto pequeño, según los criterios de Cohen, lo que indica que la pertenencia a una liga explica solo el **1,28 %** de la varianza total en este componente, mientras que el 98,72 % restante corresponde a factores individuales o tácticos internos a cada equipo.
**Análisis Post-hoc**
Las medias de las puntuaciones en el componente principal PC2 (Estilo ofensivo: progresión externa vs. penetración interna) para cada liga muestran que la *Bundesliga* presentó la media más negativa (*PC2 = -0,241*), lo que indica un perfil ofensivo orientado a la **penetración en el área rival** (mayores toques en el área penal, pases al área tras conducción y pérdidas en conducción). La *Ligue 1* mostró la media más positiva (*PC2 = 0,178*), reflejando un estilo basado en la **progresión externa y conducciones en el último tercio**, con menor presencia en el área penal. *La Liga* (0,071), *Premier League* (-0,032) y *Serie A* (-0,008) ocuparon posiciones intermedias.
Las pruebas post-hoc de Tukey revelaron que, en el componente PC2, todas las ligas difieren significativamente de la *Bundesliga*. En concreto:
- *La Liga* presenta una diferencia media de **0,311** unidades (*p < 0,001*), lo que indica un perfil significativamente más orientado a la progresión externa que la *Bundesliga*.
- *Ligue 1* presenta una diferencia de **0,419** (*p < 0,001*), confirmando su marcado estilo de conducción en el último tercio frente a la penetración en área de la *Bundesliga*.
- *Premier League* presenta una diferencia de **0,209** (*p = 0,009*), también con mayor progresión externa.
- *Serie A* presenta una diferencia de **0,233** (*p = 0,002*), con el mismo patrón.
Además, se observan diferencias significativas entre la *Ligue 1* y la *Premier League* (diferencia = **-0,210**, *p = 0,006*), y entre la *Ligue 1* y la *Serie A* (diferencia = **-0,185**, *p = 0,018*). En ambos casos, la *Ligue 1* presenta un perfil de progresión externa significativamente mayor que la *Premier League* y la *Serie A*, que se sitúan más cerca del polo de penetración en área.
Estos resultados indican que la *Bundesliga* es la liga con un estilo ofensivo más orientado a la **penetración en el área penal**, mientras que la *Ligue 1* destaca por su **juego de conducción y progresión externa** en el último tercio. Sin embargo, el tamaño del efecto global (\(\eta^2 = 0,0128\)) confirma que, aunque estas diferencias son estadísticamente significativas, explican una proporción muy reducida de la varianza total (solo el 1,28 %), por lo que la variabilidad dentro de cada liga sigue siendo predominante.
```{r, echo=FALSE}
# -------------------------------------------
tabla_medias1 <- pca_df_filtered1 %>%
group_by(Comp) %>%
summarise(
n = n(),
PC1_mean = mean(PC1),
PC1_sd = sd(PC1),
PC2_mean = mean(PC2),
PC2_sd = sd(PC2)
) %>%
mutate(
# Formato: Media (DE)
PC1 = paste0(round(PC1_mean, 3), " (", round(PC1_sd, 3), ")"),
PC2 = paste0(round(PC2_mean, 3), " (", round(PC2_sd, 3), ")")
) %>%
select(Liga = Comp, n, PC1, PC2)
# -------------------------------------------
# TABLA 2: COMPARACIONES POST-HOC SIGNIFICATIVAS (Tukey) CON INTERPRETACIÓN
# -------------------------------------------
# Extraer comparaciones significativas para PC1
posthoc_PC11 <- as.data.frame(TukeyHSD(aov_PC11)$Comp) %>%
filter(`p adj` < 0.05) %>%
rownames_to_column("Par_de_ligas") %>%
mutate(
Componente = "PC1",
Diferencia = round(diff, 3),
`p_ajustado` = round(`p adj`, 4),
# Interpretación cualitativa de PC1
Interpretacion = case_when(
diff > 0 ~ paste0("La liga '", sub("-(.*)", "", Par_de_ligas),
"' presenta MAYOR volumen de acciones ofensivas que '",
sub(".*-", "", Par_de_ligas), "'."),
diff < 0 ~ paste0("La liga '", sub("-(.*)", "", Par_de_ligas),
"' presenta MENOR volumen de acciones ofensivas que '",
sub(".*-", "", Par_de_ligas), "'.")
)
) %>%
select(Componente, Par_de_ligas, Diferencia, `p_ajustado`, Interpretacion)
# Extraer comparaciones significativas para PC2
posthoc_PC21 <- as.data.frame(TukeyHSD(aov_PC21)$Comp) %>%
filter(`p adj` < 0.05) %>%
rownames_to_column("Par_de_ligas") %>%
mutate(
Componente = "PC2 (Estilo ataque: area vs. externo area)",
Diferencia = round(diff, 3),
`p_ajustado` = round(`p adj`, 4),
# Interpretación cualitativa de PC2 (recordar: positivo = aéreo, negativo = suelo)
Interpretacion = case_when(
diff > 0 ~ paste0("La liga '", sub("-(.*)", "", Par_de_ligas),
"' tiene un perfil MÁS de Area que '",
sub(".*-", "", Par_de_ligas), "'."),
diff < 0 ~ paste0("La liga '", sub("-(.*)", "", Par_de_ligas),
"' tiene un perfil mas de ataques fuera del area que '",
sub(".*-", "", Par_de_ligas), "'.")
)
) %>%
select(Componente, Par_de_ligas, Diferencia, `p_ajustado`, Interpretacion)
# Unir ambas tablas post-hoc
tabla_posthoc1 <- bind_rows(posthoc_PC11, posthoc_PC21)
tagList(
datatable(
tabla_medias,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">Mean and SD PCA</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 15.</b>Mean and SD PCA.")
)
)
tagList(
datatable(
tabla_posthoc,
rownames = FALSE,
extensions = c("Buttons", "Scroller"),
options = list(
scrollX = TRUE,
scrollY = "500px",
scroller = TRUE,
dom = "Bfrtip",
buttons = c("copy", "csv", "excel"),
initComplete = JS(
"function(settings, json) {",
" $(this.api().table().container()).prepend(",
" '<h2 style=\"text-align: center; color: navy;\">Post-Hoc</h2>'",
" );",
"}"
)
)
),
div(
style = "text-align: center; font-size: 0.9em; margin-top: 8px;",
HTML("<b>Table 16.</b>Post Hoc.")
)
)
```
## Ficha tecnica
"
6.Todos los análisis estadísticos se realizaron utilizando RStudio (versión 4.1.0; RStudio, Inc., Boston, MA, EE. UU.), con un nivel de significancia establecido en p < 0.05". Sin embargo, el análisis principal del estudio (ACP) es una técnica exploratoria no inferencial y no proporciona pruebas de significancia. Por lo tanto, el nivel de significancia reportado (p < 0.05) no se aplica a los resultados basados en el ACP y no puede respaldar las afirmaciones inferenciales hechas en la sección de Resultados.
Todos los análisis estadísticos se realizaron utilizando RStudio (versión 4.6.0; RStudio, Inc., Boston, MA, EE. UU.). El análisis de componentes principales (ACP) se empleó como técnica exploratoria de reducción de dimensionalidad y visualización de patrones, por lo que no se le aplicaron pruebas de significancia. Para contrastar si las diferencias observadas en las puntuaciones de los componentes entre ligas eran estadísticamente significativas, se realizaron análisis de varianza (ANOVA) complementarios, con un nivel de significancia establecido en p < 0.05. Las diferencias post-hoc se evaluaron mediante la prueba HSD de Tukey.