FIFA 19 (de la saga FIFA) es un videojuego de simulación de fútbol desarrollado por EA Vancouver como parte de la serie FIFA de Electronic Arts.
El primer juego de la saga se caracterizaba por su perspectiva isométrica o de tres cuartos, que se diferenciaba de los otros títulos que ofrecían una vista desde arriba o vista de pájaro. Un aspecto importante era el sonido del público en el estadio, que estaba basado en grabaciones en vivo y que le proporcionaban un mayor realismo al desarrollo del juego con cánticos de los aficionados. El juego presentaba representativos nacionales, y un equipo especial formado por un selectivo de jugadores, este equipo se llama EA Sports.
A pesar de todos los defectos que presentaba no hay duda que en su época fue todo un éxito, la gente de EA Sports año tras año continuaba mejorando sus juegos FIFA. La nueva generación de FIFA cambio mucho, la inteligencia artificial (IA) de los jugadores es ahora más desarrollada.
El juego presenta características actualizadas de jugadores de todo el mundo, lo que permite plantearse diversas preguntas:
Acontinuación se realizará una limpieza y transformación a cada variable, dejándolas ajustadas para el análisis y predicciones.
suppressMessages(library(readr))
suppressMessages(library(lubridate))
suppressMessages(library(ggplot2))
suppressWarnings(suppressMessages(library(ggpubr)))
suppressMessages(library(htmlTable))
suppressMessages(library(corrplot))
suppressMessages(library(RColorBrewer))
suppressMessages(library(GGally))
suppressMessages(library(h2o))
suppressMessages(library(dplyr))El dataset tiene 89 variables, de los cuales se de eliminarán las siguientes por no representar información relevante:
Las variable \(ID\) y \(Name\) aunque no representen información útil, se consideraran como informativas.
Nota: La descripción de todas las variables se encuentra en el Anexo (Descripción de Variables).
dataset <- read.csv("data.csv")
dataset = dataset[dataset$Position!="GK",]El dataset contiene información de futbolistas en cualquier posición del campo. En los análisis siguientes se considerará el dataset sin los porteros, esto se debe a varias razones:
La variable \(Value\) es el valor del contrato de cada jugador, está en formato factor y con codificación no apropiada, por lo que se transformará a condificación UTF-8 y se transformará a número.
Los valores \(NA\) en esta variable corresponden por un lado a jugadores sin contrato y sin equipos, y por otro a jugadores con edad avanzada (alrededor de 40 años) cercanos al retiro. Por lo que estas observaciones no son consideradas para los análisis.
# Cambia codificación del texto
dataset$Value = parse_character(as.character(dataset$Value),
locale=locale(encoding="UTF-8"))
# elimina el simbolos de €
dataset$Value = gsub("^\\€", "", dataset$Value)
# transforma texto en número de acuerdo a si es M€, K€ o €.
numeric_value = function(char){
num = as.numeric(substring(char, 1, nchar(char)-1))
k = substring(char,nchar(char),nchar(char))
mult = 1
if(k=='M'){mult = 1000000}
if(k=='K'){mult = 1000}
num*mult
}
dataset$Value = sapply(dataset$Value, numeric_value)
suma = data.frame(t(summary(dataset$Value)))
suma[,3] = round(suma[,3],0)
names(suma) = c("Var1", "", "Valor (€)")
htmlTable(suma[,2:3],
caption = "Tabla 1. Resumen variable Value.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))#6633FF F7F7F7| Tabla 1. Resumen variable Value. | ||
| Valor (€) | ||
|---|---|---|
| 1 | Min. | 10000 |
| 2 | 1st Qu. | 350000 |
| 3 | Median | 750000 |
| 4 | Mean | 2547931 |
| 5 | 3rd Qu. | 2200000 |
| 6 | Max. | 118500000 |
| 7 | NA’s | 216 |
| † 16182 observaciones | ||
htmlTable(head(dataset[is.na(dataset$Value)&(dataset$Joined==""),
c('Name', 'Age', 'Joined', "Value")]),
tfoot = paste0("† 6 observaciones de ",
dim(dataset[is.na(dataset$Value)&(dataset$Joined==""),])[1],
" jugadores."),
caption = "Tabla 2. Jugadores sin contrato y sin equipo.",
col.rgroup = c("none","#9999F7"))| Tabla 2. Jugadores sin contrato y sin equipo. | ||||
| Name | Age | Joined | Value | |
|---|---|---|---|---|
| 453 | L. Paredes | 24 | ||
| 539 | A. Granqvist | 33 | ||
| 678 | I. Smolnikov | 29 | ||
| 875 | A. Dzyuba | 29 | ||
| 954 | LuÃs Neto | 30 | ||
| 998 | D. Kuzyaev | 25 | ||
| † 6 observaciones de 208 jugadores. | ||||
htmlTable(head(dataset[is.na(dataset$Value)&(dataset$Joined!=""),
c('Name', 'Age', 'Joined', "Value")]),
tfoot = paste0("† 6 observaciones de ",
dim(dataset[is.na(dataset$Value)&(dataset$Joined!=""),])[1],
" jugadores."),
caption = "Tabla 3. Jugadores con contrato y edad avanzada.",
col.rgroup = c("none","#9999F7"))| Tabla 3. Jugadores con contrato y edad avanzada. | ||||
| Name | Age | Joined | Value | |
|---|---|---|---|---|
| 865 | Hilton | 40 | Aug 1, 2011 | |
| 3551 | S. Nakamura | 40 | Jan 10, 2017 | |
| 4229 | B. Nivet | 41 | Jul 1, 2012 | |
| 10357 | F. Kippe | 40 | Feb 22, 2002 | |
| 12193 | H. Sulaimani | 41 | Jun 11, 2018 | |
| 12454 | W. DÃaz | 40 | Jan 10, 2016 | |
| † 6 observaciones de 8 jugadores. | ||||
dataset = dataset[!is.na(dataset$Value),-c(1, 5, 7, 11, 21, 23:26)]
# Distribucion
graph_hist <- function(x, n, var){
cols <- colorRampPalette(c("#6633FF","orange","#88CC00"))
dataxx = data.frame(Name = x[,n], stringsAsFactors = FALSE)
p1 = ggplot(data = dataxx, aes(x = Name)) +
geom_histogram(aes(y = ..density.., fill = ..count..), bins = 50) +
scale_fill_gradientn(colours = cols(20)) +
stat_function(fun = dnorm, colour = "firebrick",
args = list(mean = mean(dataxx$Name),
sd = sd(dataxx$Name))) +
ggtitle("Histograma") +
xlab(n) +
theme_bw()
p2 = ggplot(dataxx, aes(sample = Name)) +
stat_qq(col = "#6633FF") + stat_qq_line(col="red") +
ggtitle("Gráfico Q-Q Normal") +
theme_bw()
figure = ggarrange(p1, p2, common.legend = TRUE,
legend = 'left', ncol = 2, nrow = 1, heights = 0.5)
titulo = paste0("Distribución de Variable ",var)
annotate_figure(figure, top = text_grob(titulo, color = "#000000",
face = "bold", size = 18))
}
graph_hist(dataset, "Value", "Value")dataset2 = dataset
dataset2$Value = log(dataset$Value + 1)
graph_hist(dataset2, "Value", "Log(Value)")Se observa que la variable \(Value\) presenta una distribución muy diferente a una distribución normal, esto puede perjudicar la aplicación de métodos que tengan una distribución normal como requisito. Para solucionar esto se aplica el \(log(Value)\) lo que muestra una mejora sustancial, donde pordemos considerar que el \(log(Value)\) es aproximadamente normal.
La variable \(ID\) representa un indicar único por jugador. No requiere transformación ni limpieza.
No presenta valores tipo \(NA\) o vacios para esta variable.
suma = data.frame(t(summary(dataset$ID)))
suma[,3] = round(suma[,3],0)
names(suma) = c("Var1", "", "Valor")
htmlTable(suma[,2:3],
caption = "Tabla 4. Resumen variable ID.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 4. Resumen variable ID. | ||
| Valor | ||
|---|---|---|
| 1 | Min. | 16 |
| 2 | 1st Qu. | 200880 |
| 3 | Median | 221986 |
| 4 | Mean | 215086 |
| 5 | 3rd Qu. | 236652 |
| 6 | Max. | 246620 |
| † 15966 observaciones | ||
# Distribucion
graph_hist(dataset, "ID", "ID")La distribución anterior tampoco es normal, en este caso no presenta un problema, ya que la variable \(ID\) es sólo informativa y la utilizaremos como referencia de cada jugador en cojunto con \(Name\). No es posible utilizar sólo \(Name\), debido a que existen jugadores con nombre repetido.
La variable \(Name\) es el nombre del jugador, está en formato factor y con codificación no apropiada, por lo que se transformará a tipo character con condificación UTF-8. Esto sucede para todas las variables tipo caracter en el dataset.
No presenta valores tipo \(NA\) o vacios para esta variable.
var = data.frame(Raw = t(head(dataset$Name, 10)),
Transformation = factor(t(head(parse_character(as.character(dataset$Name),
locale=locale(encoding="UTF-8")), 10))))
dataset$Name = parse_character(as.character(dataset$Name),
locale=locale(encoding="UTF-8"))
htmlTable(var,
caption = "Tabla 5. Datos brutos y transformados de variable Name.",
tfoot = paste0("† 10 observaciones de ",
dim(dataset)[1],
" jugadores."),
col.rgroup = c("none","#9999F7"))| Tabla 5. Datos brutos y transformados de variable Name. | ||
| Raw | Transformation | |
|---|---|---|
| 1 | L. Messi | L. Messi |
| 2 | Cristiano Ronaldo | Cristiano Ronaldo |
| 3 | Neymar Jr | Neymar Jr |
| 4 | K. De Bruyne | K. De Bruyne |
| 5 | E. Hazard | E. Hazard |
| 6 | L. Modrić | L. Modric |
| 7 | L. Suárez | L. Suárez |
| 8 | Sergio Ramos | Sergio Ramos |
| 9 | R. Lewandowski | R. Lewandowski |
| 10 | T. Kroos | T. Kroos |
| † 10 observaciones de 15966 jugadores. | ||
# Distribucion
graph_hist_factor <- function(x, n, var, xlab="xlab", ylab="ylab", tit="title",
list = 17){
cols <- colorRampPalette(c("#6633FF","orange","#88CC00"))
ratio=ifelse(list>17,list/17,1)
cuenta = summary(x[,n], maxsum = nlevels(x[,n]))
datag = data.frame(Name = names(cuenta), Cuenta = cuenta)
datag = datag[order(datag$Cuenta, decreasing = TRUE),]
dataxx = data.frame(Name = cuenta, stringsAsFactors = FALSE)
p1 = ggplot(data = dataxx, aes(x = Name)) +
geom_histogram(aes(y = ..density.., fill = ..count..), bins = 50) +
scale_fill_gradientn(colours = cols(20)) +
stat_function(fun = dnorm, colour = "firebrick",
args = list(mean = mean(dataxx$Name),
sd = sd(dataxx$Name))) +
ggtitle("Histograma") +
xlab(n) +
theme_bw()
p2 = ggplot(dataxx, aes(sample = Name)) +
stat_qq(col = "#6633FF") + stat_qq_line(col="red") +
ggtitle("Gráfico Q-Q Normal") +
theme_bw()
figure = ggarrange(p1, p2, common.legend = TRUE,
legend = 'left', ncol = 2, nrow = 1)
titulo = paste0("Distribución de Variable ",var)
g1 = annotate_figure(figure, top = text_grob(titulo, color = "#000000",
face = "bold", size = 18))
g2 = ggplot(data = head(datag, list), aes(reorder(Name, Cuenta), Cuenta)) +
geom_bar(stat = 'identity', fill = "#6633FF") +
xlab(xlab) + ylab(ylab) +
theme(axis.text.y = element_text(size=8))+
ggtitle(tit) + coord_flip() + theme_bw()
ggarrange(g1, g2, common.legend = TRUE,
legend = 'left', ncol = 1, nrow = 2, heights = c(1, ratio))
}
dataset2 = dataset
dataset2$Name = factor(dataset2$Name)
graph_hist_factor(dataset2, "Name", "Name", "Nombres", "Cantidad de Jugadores",
"Nombres v/s jugadores")La distribución de \(Name\) no es normal, se observan que los nombres se repiten, por lo que es necesario utilizar ests variable junto a \(ID\) para individualizar a cada jugador.
La variable \(Age\) es la edad de jugador. No requiere transformación ni limpieza.
No presenta valores tipo \(NA\) o vacios para esta variable.
suma = data.frame(t(summary(dataset$Age)))
suma[,3] = round(suma[,3],0)
names(suma) = c("Var1", "", "Valor (años)")
htmlTable(suma[,2:3],
caption = "Tabla 6. Resumen variable Age.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 6. Resumen variable Age. | ||
| Valor (años) | ||
|---|---|---|
| 1 | Min. | 16 |
| 2 | 1st Qu. | 21 |
| 3 | Median | 25 |
| 4 | Mean | 25 |
| 5 | 3rd Qu. | 28 |
| 6 | Max. | 39 |
| † 15966 observaciones | ||
# Distribucion
graph_hist(dataset, "Age", "Age")\(Age\) cuenta con una distribución aproximadamente normal, las colas superior e inferior muestran una diferencia con la curva teórica, esto se debe por un lado a que los jugadores comienzan a entrar en el futbol profesional sobre los 16 años, por lo que normalmente esas edades son menos comunes y por otro lado los futbolistas se comienzan a retirar alrededor de los 35 años hacia arriba.
La variable \(Nationality\) representa la nacionalidad del jugador, está en formato factor y con dificación no apropiada, por lo que se transformará a condificación UTF-8.
No presenta valores tipo \(NA\) o vacios para esta variable.
dataset$Nationality = parse_character(as.character(dataset$Nationality),
locale=locale(encoding="UTF-8"))
dataset$Nationality = factor(dataset$Nationality)
suma = data.frame((summary(dataset$Nationality)))
#suma[,3] = round(suma[,3],0)
names(suma) = c("Jugadores")
htmlTable(head(suma,10),
caption = "Tabla 7. Número de jugadores por país.",
tfoot = paste0("† 10 observaciones de ",
nlevels(dataset$Nationality), " países en total"),
col.rgroup = c("none","#9999F7"))| Tabla 7. Número de jugadores por país. | |
| Jugadores | |
|---|---|
| England | 1488 |
| Germany | 1034 |
| Spain | 956 |
| Argentina | 839 |
| France | 812 |
| Brazil | 758 |
| Italy | 610 |
| Colombia | 565 |
| Japan | 414 |
| Netherlands | 397 |
| † 10 observaciones de 162 países en total | |
# Distribucion
graph_hist_factor(dataset, "Nationality", "Nationality", "Países",
"Cantidad de Jugadores", "Cantidad de Jugadores por País")La nacionalidad de los jugadores no sigue una distribución normal, hay algunos países que concentran una gran cantidad de jugadores y el resto unos pocos. Se observa que los países más futbolizados tienen más jugadores y además que estos países por si solos presentan una mayor reputación, mejores ligas y un mercado más desarrollado en el fútbol.
La variable \(Overall\) es la habilidad general del cada jugador en un rango de 0-99. No requiere transformación ni limpieza.
No presenta valores tipo \(NA\) o vacios para esta variable.
suma = data.frame(t(summary(dataset$Overall)))
suma[,3] = round(suma[,3],0)
names(suma) = c("Var1", "", "Valor")
htmlTable(suma[,2:3],
caption = "Tabla 8. Resumen variable Overall.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 8. Resumen variable Overall. | ||
| Valor | ||
|---|---|---|
| 1 | Min. | 46 |
| 2 | 1st Qu. | 62 |
| 3 | Median | 66 |
| 4 | Mean | 66 |
| 5 | 3rd Qu. | 71 |
| 6 | Max. | 94 |
| † 15966 observaciones | ||
# Distribucion
graph_hist(dataset, "Overall", "Overall")La habilidad general (\(Overall\)) de cada jugador está distribuida uniformemente en el universo de futbolistas.
La variable \(Potential\) es la habilidad potencial del cada jugador en un rango de 0-99. No requiere transformación ni limpieza.
No presenta valores tipo \(NA\) o vacios para esta variable.
suma = data.frame(t(summary(dataset$Potential)))
suma[,3] = round(suma[,3],0)
names(suma) = c("Var1", "", "Valor")
htmlTable(suma[,2:3],
caption = "Tabla 8. Resumen variable Potential.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 8. Resumen variable Potential. | ||
| Valor | ||
|---|---|---|
| 1 | Min. | 48 |
| 2 | 1st Qu. | 67 |
| 3 | Median | 71 |
| 4 | Mean | 72 |
| 5 | 3rd Qu. | 75 |
| 6 | Max. | 95 |
| † 15966 observaciones | ||
# Distribucion
graph_hist(dataset, "Potential", "Potential")La habilidad potencial (\(Potential\)) de cada jugador está distribuida uniformemente en el universo de futbolistas.
La variable \(Club\) es el club de cada jugador, está en formato factor y con codificación no apropiada, por lo que se transformará a condificación UTF-8.
No presenta valores tipo \(NA\) o vacios para esta variable.
dataset$Club = parse_character(as.character(dataset$Club),
locale=locale(encoding="UTF-8"))
dataset$Club = factor(dataset$Club)
suma = data.frame((summary(dataset$Club)))
names(suma) = c("Jugadores")
htmlTable(head(suma,10),
caption = "Tabla 9. Número de jugadores por club.",
tfoot = paste0("† 10 observaciones de ",
nlevels(dataset$Club), " clubes en total"),
col.rgroup = c("none","#9999F7"))| Tabla 9. Número de jugadores por club. | |
| Jugadores | |
|---|---|
| Arsenal | 30 |
| Atlético Madrid | 30 |
| Borussia Dortmund | 30 |
| Cardiff City | 30 |
| Everton | 30 |
| Frosinone | 30 |
| Liverpool | 30 |
| Manchester United | 30 |
| Rayo Vallecano | 30 |
| RC Celta | 30 |
| † 10 observaciones de 651 clubes en total | |
# Distribucion
graph_hist_factor(dataset, "Club", "Club", "Clubes", "Cantidad de Jugadores",
"Jugadores por Club")La cantidad de jugadores en cada club muestra una aproximadamente normal, la cola inferior se tiende a alejar de la curva teórica, este puede ser debido a que la mayoría de los equipos prefieren tener sobre 20 jugadores para tener más reemplazos en los juegos de cada uno de sus ligas. Estos equipos podrían tener problemas de cantidad de jugadores si alguno es suspendido o se lesiona.
La variable \(Wage\) es la remunaración cada jugador, está en formato factor y con codificación no apropiada, por lo que se transformará a condificación UTF-8 y luego en valor numérico.
No presenta valores tipo \(NA\) o vacios para esta variable.
# Cambia codificación del texto
dataset$Wage = parse_character(as.character(dataset$Wage),
locale=locale(encoding="UTF-8"))
# elimina el simbolos de €
dataset$Wage = gsub("^\\€", "", dataset$Wage)
dataset$Wage = sapply(dataset$Wage, numeric_value)
suma = data.frame(t(summary(dataset$Wage)))
suma[,3] = round(suma[,3],0)
names(suma) = c("Var1", "", "Valor (€)")
htmlTable(suma[,2:3],
caption = "Tabla 10. Resumen variable Wage.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 10. Resumen variable Wage. | ||
| Valor (€) | ||
|---|---|---|
| 1 | Min. | 1000 |
| 2 | 1st Qu. | 1000 |
| 3 | Median | 3000 |
| 4 | Mean | 10232 |
| 5 | 3rd Qu. | 10000 |
| 6 | Max. | 565000 |
| † 15966 observaciones | ||
# Distribucion
graph_hist(dataset, "Wage", "Wage")dataset2 = dataset
dataset2$Wage = log(dataset2$Wage + 1)
graph_hist(dataset2, "Wage", "Log(Wage)")Se observa que la variable \(Wage\) presenta una distribución muy diferente a una distribución normal, esto puede perjudicar la aplicación de métodos que tengan una distribución normal como requeisito. Para solucionar esto se aplica el \(log(Wage)\) lo que muestra una mejora sustancial.
La cola inferior muestra que hay muchos jugadores con la misma remuneración (1.000 €), que es el mínimo. La cola superior muestra que hay algunos jugadores que se escapan y reciben remuneraciones muy altas, estos son jugadores de elite y aportan a los equipos más que un muy buen futbol, contratos de publicidad, camisetas, etc. como L. Messi, Cristiano Ronaldo y varios otros jugadores del mismo nivel.
La variable \(Special\) es el total de estadísticas de cada jugador. No requiere transformación ni limpieza.
No presenta valores tipo \(NA\) o vacios para esta variable.
suma = data.frame(t(summary(dataset$Special)))
suma[,3] = round(suma[,3],0)
names(suma) = c("Var1", "", "Valor")
htmlTable(suma[,2:3],
caption = "Tabla 11. Resumen variable Special.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 11. Resumen variable Special. | ||
| Valor | ||
|---|---|---|
| 1 | Min. | 1000 |
| 2 | 1st Qu. | 1526 |
| 3 | Median | 1669 |
| 4 | Mean | 1667 |
| 5 | 3rd Qu. | 1805 |
| 6 | Max. | 2346 |
| † 15966 observaciones | ||
# Distribucion
graph_hist(dataset, "Special", "Special")Las estadísticas acumuladas (\(Special\)) de cada jugador está distribuida uniformemente en el universo de futbolistas.
La variable \(International.Reputation\) es la reputación del futbolista. No requiere transformación ni limpieza.
Existen 48 valores \(NA\) en esta variable. Estas observaciones no tienen datos en 72 de las 83 variables del dataset, por lo que no son consideradas para el análisis.
dataset = dataset[!is.na(dataset$International.Reputation),]
dataset$International.Reputation = factor(dataset$International.Reputation)
# Distribucion
graph_hist_factor(dataset, "International.Reputation", "International.Reputation",
"Reputacion", "Cantidad de Jugadores",
"Reputacion por jugador")La \(International.Reputation\) es una variable absolutamente no normal, presenta una distribución interesante.
Los futbolistas con reputación 1, 2 o 3 se pueden catalogar como promedio, buenos y muy buenos.
Los futbolistas con reputación 4 son pocos (en torno a 50) y se pueden considerar como super estrellas entre ellos se encuentran B. Schweinsteiger, J. Mascherano, Dani Alves y A. Sánchez.
Los futbolistas con reputación 5 son 5 y son las máximas estrellas del futbol mundial, estos son L. Messi, L. Suárez, Neymar Jr, Cristiano Ronaldo y Z. Ibrahimovic.
La variable \(Preferred.Foot\) representa la nacionalidad del jugador, está en formato factor y con codificación no apropiada, por lo que se transformará a condificación UTF-8.
dataset$Preferred.Foot = parse_character(as.character(dataset$Preferred.Foot),
locale=locale(encoding="UTF-8"))
dataset$Preferred.Foot = factor(dataset$Preferred.Foot)
suma = data.frame((summary(dataset$Preferred.Foot)))
names(suma) = c("Número de jugadores")
htmlTable(head(suma,10),
caption = "Tabla 13. Pierna preferida utilizada por los jugadores.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 13. Pierna preferida utilizada por los jugadores. | |
| Número de jugadores | |
|---|---|
| Left | 3954 |
| Right | 11964 |
| † 15918 observaciones | |
# Distribucion
graph_hist_factor(dataset, "Preferred.Foot", "Preferred.Foot",
"Pie preferido", "Cantidad de Jugadores",
"Pie preferido por jugador")Los jugadores son mayoritariamente diestros (aprox. 75%), esto es menor que el porcentaje a nivel mundial (aprox. 90%), esto se puede deber a que un futbolista zurdo es bien visto, ya que hay pocos, y se incentiva el uso de la pierna zurda para ciertas posiciones.
La variable \(Weak.Foot\) es la valoración (1-5) de la habilidad del jugador con pie menos hábil. No requiere transformación ni limpieza.
No presenta valores tipo \(NA\) o vacios para esta variable.
dataset$Weak.Foot = factor(dataset$Weak.Foot)
# Distribucion
graph_hist_factor(dataset, "Weak.Foot", "Weak.Foot",
"Pie menos hábil", "Cantidad de Jugadores",
"Pie menos hábil por jugador")La mayoría de lo jugadores presentan una habilidad media de juego con su pierna menos hábil.
La variable \(Skill.Moves\) es la movilidad del jugador(1-5). No requiere transformación ni limpieza.
No presenta valores tipo \(NA\) o vacios para esta variable.
dataset$Skill.Moves = factor(dataset$Skill.Moves)
# Distribucion
graph_hist_factor(dataset, "Skill.Moves", "Skill.Moves",
"Habilidades de movimiento", "Cantidad de Jugadores",
"Habilidad de movimiento por jugador")Se observa que la mayoría de los jugadores presentan movilidad media/baja.
La variable \(Work.Rate\) es el Ratio de trabajo ofensivo/defensivo del jugador.
No presenta valores tipo \(NA\) o vacios para esta variable.
dataset$Work.Rate = factor(as.character(dataset$Work.Rate))
suma = data.frame((summary(dataset$Work.Rate)))
names(suma) = c("Número de jugadores")
htmlTable(head(suma,10),
caption = "Tabla 16. Resumen variable Work.Rate.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 16. Resumen variable Work.Rate. | |
| Número de jugadores | |
|---|---|
| High/ High | 1007 |
| High/ Low | 685 |
| High/ Medium | 3130 |
| Low/ High | 434 |
| Low/ Low | 34 |
| Low/ Medium | 438 |
| Medium/ High | 1660 |
| Medium/ Low | 840 |
| Medium/ Medium | 7690 |
| † 15918 observaciones | |
# Distribucion
graph_hist_factor(dataset, "Work.Rate", "Work.Rate",
"Trabajo Ofensivo/Defensivo", "Cantidad de Jugadores",
"Razón de trabajo por jugador")Se puede dividir esta variable en 4 sub grupos:
De esto podemos concluir que se privilegia el trabajo en toda la cancha, los jugadores deben ser capaces de cambiar de posición respecto a las circunstancias. Luego, en menor medida se privilegia un poco más el trabajo defensivo.
La variable \(Body.Type\) es el tipo de cuerpo de cada jugador. Hay varios jugadores que tienen nivel propio, esto se modificará a una de las siguientes características lean, normal o stocky parageneralizar.
No presenta valores tipo \(NA\) o vacios para esta variable.
dataset$Body.Type = as.character(dataset$Body.Type)
# los jugadores específicos son los siguientes:
dataset$Body.Type[dataset$Body.Type=='Akinfenwa']='Stocky'
dataset$Body.Type[dataset$Body.Type=='C. Ronaldo']='Normal'
dataset$Body.Type[dataset$Body.Type=='Courtois']='Normal'
dataset$Body.Type[dataset$Body.Type=='Messi']='Normal'
dataset$Body.Type[dataset$Body.Type=='Neymar']='Lean'
dataset$Body.Type[dataset$Body.Type=='PLAYER_BODY_TYPE_25']='Normal'
dataset$Body.Type[dataset$Body.Type=='Shaqiri']='Normal'
dataset$Body.Type = factor(dataset$Body.Type)
suma = data.frame((summary(dataset$Body.Type)))
names(suma) = c("Número de jugadores")
htmlTable(head(suma,10),
caption = "Tabla 17. Resumen variable Body.Type.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 17. Resumen variable Body.Type. | |
| Número de jugadores | |
|---|---|
| Lean | 5911 |
| Normal | 9014 |
| Stocky | 993 |
| † 15918 observaciones | |
# Distribucion
graph_hist_factor(dataset, "Body.Type", "Body.Type",
"Tipo de cuerpo", "Cantidad de Jugadores",
"Tipo de cuerpo por jugador")Se privilegia más un cuerpo normal o delgado en los equipos, esto es alrededor de un 94% de los jugadores.
La variable \(Position\) es la posición en el campo de cada jugador.
No presenta valores tipo \(NA\) o vacios para esta variable.
dataset$Position = factor(as.character(dataset$Position))
# agrupaciones posición general
suma = data.frame((summary(dataset$Position)))
id_m = grepl("M$", levels(dataset$Position))
id_b = grepl("B$", levels(dataset$Position))
id_d = !(id_m|id_b)
columnas = c(levels(dataset$Position)[id_b],
levels(dataset$Position)[id_m],
levels(dataset$Position)[id_d])
htmlTable(suma,
header = "Número de jugadores",
rnames = columnas,
rgroup = c("Defensas", "Mediocampistas", "Delanteros"),
n.rgroup = c(sum(id_b), sum(id_m), sum(id_d)),
caption="Tabla 18. Resumen variable Position.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 18. Resumen variable Position. | |
| Número de jugadores | |
|---|---|
| Defensas | |
| CB | 946 |
| LB | 1751 |
| LCB | 936 |
| LWB | 74 |
| RB | 1377 |
| RCB | 21 |
| RWB | 1304 |
| Mediocampistas | |
| CAM | 635 |
| CDM | 389 |
| CM | 239 |
| LAM | 15 |
| LCM | 1086 |
| LDM | 206 |
| LM | 374 |
| RAM | 78 |
| RCM | 21 |
| RDM | 1268 |
| RM | 652 |
| Delanteros | |
| CF | 387 |
| LF | 246 |
| LS | 16 |
| LW | 1114 |
| RF | 201 |
| RS | 365 |
| RW | 87 |
| ST | 2130 |
| † 15918 observaciones | |
# Distribucion
graph_hist_factor(dataset, "Position", "Position",
"Posición", "Cantidad de Jugadores",
"Posición por jugador", list = 26)Estas posiciones se agrupan en 3 grupos:
Las posiciones más comunes entre los defensas son:
De lo anterior podemos concluir que la mayoría de los equipos atacan (desde defensa) con su lateral derecho y defienden más a la izquierda (que es la derecha del otro equipo).
Las posiciones más comunes entre los mediocampistas son:
Los mediocampistas en general, tienden a defender la zona derecha y central y enlazan el ataque con los mediocampistas centrales, izquierdos y de ataque.
Las posiciones más comunes entre los delanteros son:
Los delanteros complementan el ataque decentro izquierda de las posiciones LW y ST con el ataque del defensa RWB por la derecha.
Esto hace que el juego en general se mueva a ofensiva por la derecha y el final de la cancha se ataque por 3 flancos.
La variable \(Height\) representa la altura del jugador en pies más pulgadas, está en formato factor y con codificación no apropiada, por lo que se transformará a condificación UTF-8 y luego a valor numérico expresado en cms.
No presenta valores tipo \(NA\) o vacios para esta variable.
dataset$Height = as.character(dataset$Height)
dataset$Height = as.numeric(gsub("\'\\w+$", "", dataset$Height))*30.48 +
as.numeric(gsub("^\\w+'", "", dataset$Height))*2.54
suma = data.frame(t(summary(dataset$Height)))
suma[,3] = round(suma[,3],0)
names(suma) = c("Var1", "", "Valor (cm)")
htmlTable(suma[,c(2,3)],
caption = "Tabla 20. Resumen variable Height.",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 20. Resumen variable Height. | ||
| Valor (cm) | ||
|---|---|---|
| 1 | Min. | 155 |
| 2 | 1st Qu. | 175 |
| 3 | Median | 180 |
| 4 | Mean | 180 |
| 5 | 3rd Qu. | 185 |
| 6 | Max. | 203 |
| † 15918 observaciones | ||
# Distribución
graph_hist(dataset, "Height", "Height")Las estadísticas acumuladas (\(Height\)) de cada jugador está distribuida uniformemente en el universo de futbolistas.
La variable \(Weight\) representa el peso del jugador en libras, está en formato factor y con codificación no apropiada, por lo que se transformará a condificación UTF-8 y luego a valor numérico expresado en kgs.
No presenta valores tipo \(NA\) o vacios para esta variable.
dataset$Weight = as.character(dataset$Weight)
dataset$Weight = as.numeric(gsub("lbs$", "", dataset$Weight))*0.453592
suma = data.frame(t(summary(dataset$Weight)))
suma[,3] = round(suma[,3],0)
names(suma) = c("Var1", "", "Valor (kgs)")
htmlTable(suma[,c(2,3)],
caption = "Tabla 20. Resumen variable Weight",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 20. Resumen variable Weight | ||
| Valor (kgs) | ||
|---|---|---|
| 1 | Min. | 50 |
| 2 | 1st Qu. | 70 |
| 3 | Median | 74 |
| 4 | Mean | 74 |
| 5 | 3rd Qu. | 79 |
| 6 | Max. | 110 |
| † 15918 observaciones | ||
# Distribución
graph_hist(dataset, "Weight", "Weight")Las estadísticas acumuladas (\(Weight\)) de cada jugador está distribuida uniformemente en el universo de futbolistas.
Las variables desde LS hasta RB representan la habilidad del jugador en cada posición. Como se observa sus datos están en formato tipo texto ‘88+2’, donde el ‘88’ representa la habilidad del jugador en la posición (0-99) al inicio del campeonato y el ‘+2’ representa el incremento en habilidad durante el campeonato. Para efectos prácticos no se considera está última parte en el análisis, sólo el puntaje base, por lo que se transforma este valor a tipo numérico.
Las variables desde Crossing hasta GKReflexes representan una habilidad específica del jugador (0-99). Los datos no requieren transformación.
En todo este conjunto de variables hay muchas muy correlacionadas, por lo que se eliminaran las variables que tengan correlación mayor a 0.9.
htmlTable(head(dataset[,20:28]),
caption = "Tabla 21. Resumen variable Weight sin transformación de variables.",
tfoot = paste0("† Primeras 8 variables del grupo en tabla."),
col.rgroup = c("none","#9999F7"))| Tabla 21. Resumen variable Weight sin transformación de variables. | |||||||||
| LS | ST | RS | LW | LF | CF | RF | RW | LAM | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 88+2 | 88+2 | 88+2 | 92+2 | 93+2 | 93+2 | 93+2 | 92+2 | 93+2 |
| 2 | 91+3 | 91+3 | 91+3 | 89+3 | 90+3 | 90+3 | 90+3 | 89+3 | 88+3 |
| 3 | 84+3 | 84+3 | 84+3 | 89+3 | 89+3 | 89+3 | 89+3 | 89+3 | 89+3 |
| 5 | 82+3 | 82+3 | 82+3 | 87+3 | 87+3 | 87+3 | 87+3 | 87+3 | 88+3 |
| 6 | 83+3 | 83+3 | 83+3 | 89+3 | 88+3 | 88+3 | 88+3 | 89+3 | 89+3 |
| 7 | 77+3 | 77+3 | 77+3 | 85+3 | 84+3 | 84+3 | 84+3 | 85+3 | 87+3 |
| † Primeras 8 variables del grupo en tabla. | |||||||||
dataset = dataset[,-c(75:79)]# elimina variables asociadas a porteros
for (i in 20:45) {
dataset[,i] = as.character(dataset[,i])
dataset[,i] = as.numeric(gsub("\\+\\w+$", "", dataset[,i]))
}
for (i in 46:74) {
dataset[,i] = as.numeric(as.character(dataset[,i]))
}
htmlTable(head(dataset[,20:28]),
caption = "Tabla 22. Resumen de habilidades por posición de cada
jugador.",
tfoot = paste0("† Primeras 8 variables del grupo en tabla."),
col.rgroup = c("none","#9999F7"))| Tabla 22. Resumen de habilidades por posición de cada jugador. | |||||||||
| LS | ST | RS | LW | LF | CF | RF | RW | LAM | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 88 | 88 | 88 | 92 | 93 | 93 | 93 | 92 | 93 |
| 2 | 91 | 91 | 91 | 89 | 90 | 90 | 90 | 89 | 88 |
| 3 | 84 | 84 | 84 | 89 | 89 | 89 | 89 | 89 | 89 |
| 5 | 82 | 82 | 82 | 87 | 87 | 87 | 87 | 87 | 88 |
| 6 | 83 | 83 | 83 | 89 | 88 | 88 | 88 | 89 | 89 |
| 7 | 77 | 77 | 77 | 85 | 84 | 84 | 84 | 85 | 87 |
| † Primeras 8 variables del grupo en tabla. | |||||||||
# Correlacion
corr_mat=cor(dataset[,20:74],method="pearson")
corrplot(corr_mat, method = "square", outline = T, addgrid.col = "darkgray",
cl.pos = "b", tl.col = "#6633CC", tl.cex = 0.5, cl.cex = 0.5,
col = colorRampPalette(c("#88CC00","orange","#6633FF"))(100))corr_mat2 = corr_mat
k=1
elim = c()
while (k<dim(corr_mat2)[1]) {
list = abs(corr_mat2[k,])<0.9
list[1:k] = TRUE
elim = c(elim, colnames(corr_mat2)[!list])
corr_mat2 = corr_mat2[list,list]
k=k+1
}
corrplot(corr_mat2, method = "color", outline = T, addgrid.col = "darkgray",
cl.pos = "b", tl.col = "#6633CC", tl.cex = 0.7, cl.cex = 0.7,
addCoef.col = "white", number.digits = 2, number.cex = 0.55,
col = colorRampPalette(c("#88CC00","orange","#6633FF"))(100))pos_elim = sapply(paste0("^", elim, "$"), grep, x = names(dataset),
useBytes = TRUE)
dataset = dataset[,-pos_elim]Eliminando las variables más correlacionadas se logra reducir de 55 a 27 variables.
A continuación se muestra la distribución de cada una de las variables. Estas son aproximadamente normales.
# Graficos
grap_list = list()
for (i in 20:(length(names(dataset))-1)) {
grap_list[[names(dataset)[i]]] = graph_hist(dataset, names(dataset)[i],
names(dataset)[i])
}
for (i in 1:9) {
d = (i-1)*3
print(ggarrange(grap_list[[1+d]], grap_list[[2+d]], grap_list[[3+d]],
common.legend = FALSE, legend = 'left',
ncol = 1, nrow = 3))
}La variable \(Release.Clause.\) es la clausula de salida cada jugador, está en formato factor y con codificación no apropiada, por lo que se transformará a condificación UTF-8 y luego en valor numérico.
Hay 1264 valores tipo \(NA\) o vacios para esta variable, se completarán con ‘0’ asumiendo que estos jugadores no tienen clausula de salida.
# Cambia codificación del texto
dataset$Release.Clause = parse_character(as.character(dataset$Release.Clause),
locale=locale(encoding="UTF-8"))
# elimina el simbolos de €
dataset$Release.Clause = gsub("^\\€", "", dataset$Release.Clause)
dataset$Release.Clause[is.na(dataset$Release.Clause)]= as.character(min(dataset$Release.Clause[!is.na(dataset$Release.Clause)]))
dataset$Release.Clause = sapply(dataset$Release.Clause, numeric_value)
suma = data.frame(t(summary(dataset$Release.Clause)))
suma[,3] = round(suma[,3],0)
names(suma) = c("Var1", "", "Valor (€)")
htmlTable(suma[,2:3],
caption = "Tabla 24. Resumen variable Release.Clause",
tfoot = paste0("† ", dim(dataset)[1], " observaciones"),
col.rgroup = c("none","#9999F7"))| Tabla 24. Resumen variable Release.Clause | ||
| Valor (€) | ||
|---|---|---|
| 1 | Min. | 13000 |
| 2 | 1st Qu. | 618000 |
| 3 | Median | 1100000 |
| 4 | Mean | 4517292 |
| 5 | 3rd Qu. | 3300000 |
| 6 | Max. | 228100000 |
| † 15918 observaciones | ||
# Distribución
graph_hist(dataset, "Release.Clause", "Release.Clause")dataset2 = dataset
dataset2$Release.Clause = log(dataset2$Release.Clause + 1)
graph_hist(dataset2, "Release.Clause", "Log(Release.Clause)")Se observa que la variable \(Release.Clause\) presenta una distribución muy diferente a una distribución normal, esto puede perjudicar la aplicación de métodos que tengan una distribución normal como requisito. Para solucionar esto se aplica el \(log(Release.Clause)\) lo que muestra una mejora sustancial, donde pordemos considerar que el \(log(Release.Clause)\) es aproximadamente normal, con una pequeña diferencia en la cola superior..
A continuación se desarrolla un análisis entre distintas variables para encontrar relaciones entre estas, principalmente con la variable \(Value\). El objetivo final es predecir \(Value\) en función del resto de variables (excepto \(Wage\) y \(Release.Clause\)).
Primero se revisa si las varibles relacionadas con dinero tienen correlación. La correlación entre \(Value\) y \(Wage\) es relativamente alta 0.86 y para \(Release.Clause\) es muy alta con 0.97. Para futuros análisis consideraremos sólo el valor del contrato debido a la tan alta correlación entre estas dos variables.
cols <- colorRampPalette(c("#6633FF","orange","#88CC00"))
id_num = (sapply(dataset, class)=="integer")|(sapply(dataset, class)=="numeric")
corr_mat=cor(dataset[, id_num], method="pearson")
ReleaseMin = min(dataset$Release.Clause[dataset$Release.Clause>0])
corrplot(corr_mat[c(5,6,37),c(5,6,37)], method = "color",
outline = T, addgrid.col = "darkgray",
cl.pos = "b", tl.col = "#6633CC", tl.cex = 0.7, cl.cex = 0.7,
addCoef.col = "white", number.digits = 2, number.cex = 0.55,
col = colorRampPalette(c("#88CC00","orange","#6633FF"))(100))ggplot(data = dataset[dataset$Release.Clause>ReleaseMin,],
aes(x = Value, y = Release.Clause))+
geom_hex(alpha = 0.9, bins = 50) +
scale_fill_gradientn(colours = cols(20))+
geom_smooth(method = "glm", color = "red", size = 0.5) +
ggtitle("Relación Valor de contrato vs Remuneración") +
theme_bw()ggplot(data = dataset, aes(x = log(Value+1), y = log(Wage+1)))+
geom_hex(alpha = 0.9, bins = 50) +
scale_fill_gradientn(colours = cols(20))+
geom_smooth(method = "glm", color = "red", size = 0.5) +
ggtitle("Relación Valor de contrato vs Remuneración") +
theme_bw()Hay una clara tendencia hacia mayor \(International.Reputation\), mayor \(Value\). Entre los jugadores con mayor reputación hay un valor atípico inferior, este es Z. Ibrahimovic, en su caso tiene reputación 5 y su valor es de 14M€, esto se puede deber a su edad (tiene 36 años), su estado físico y/o al equipo en que juega. Hay que considerar que sólo hay 5 jugadores con reputación 5 L. Messi, Cristiano Ronaldo, Neymar Jr, L. Suárez y Z. Ibrahimovic, por los que los datos en esta categoría no son generalizables.
Se observa que para la remuneración el análisis es similar y también hay una relación de a mayor reputación mayor remuneración.
ggplot(data = dataset, aes(International.Reputation, log(Value+1),
fill = International.Reputation)) +
geom_violin(alpha = 0.5) +
scale_fill_manual(values = cols(5)) +
geom_point(stat= "summary", fun.y=mean, shape=16, size=1, color="red") +
ggtitle("Valor de contrato para cada nivel de Reputación") +
theme_bw()ggplot(data = dataset, aes(International.Reputation, log(Wage+1),
fill = International.Reputation)) +
geom_violin(alpha = 0.5) +
scale_fill_manual(values = cols(5)) +
geom_point(stat= "summary", fun.y=mean, shape=16, size=1, color="red") +
ggtitle("Remuneración para cada nivel de Reputación") +
theme_bw()Existen 3 variables generales que resumen las habilidades de cada jugador \(Overall\), \(Potential\) y \(Special\) (estas variables no están altamente correlacionadas).
En cada una de ellas se observa que tiende a haber una relación lineal con las ganancias de los jugadores (\(Value\) o \(Wage\)). Para estimar que habilidades son más relevantes se utilizarán el detalle de las variables asociadas a habilidad.
corrplot(corr_mat[c(3,4,7),c(3,4,7)], method = "color", outline = T, addgrid.col = "darkgray",
cl.pos = "b", tl.col = "#6633CC", tl.cex = 0.7, cl.cex = 0.7,
addCoef.col = "white", number.digits = 2, number.cex = 0.55,
col = colorRampPalette(c("#88CC00","orange","#6633FF"))(100))p <- list()
p[[1]] = ggplot(data = dataset, aes(x = Overall, y = log(Value+1)))+
geom_hex(alpha = 0.9, bins = 30) +
scale_fill_gradientn(colours = cols(20))+
geom_smooth(method = "glm", color = "red", size = 0.5) +
ylim(c(9,19)) +
ggtitle("Overall") +
theme_bw()
p[[2]] = ggplot(data = dataset, aes(x = Potential, y = log(Value+1)))+
geom_hex(alpha = 0.9, bins = 30) +
scale_fill_gradientn(colours = cols(20))+
geom_smooth(method = "glm", color = "red", size = 0.5) +
ylim(c(9,19)) +
ggtitle("Potential") +
theme_bw()
p[[3]] = ggplot(data = dataset, aes(x = Special, y = log(Value+1)))+
geom_hex(alpha = 0.9, bins = 30) +
scale_fill_gradientn(colours = cols(20))+
geom_smooth(method = "glm", color = "red", size = 0.5) +
ylim(c(9,19)) +
ggtitle("Special") +
theme_bw()
p[[4]] = ggplot(data = dataset, aes(x = Overall, y = log(Wage+1)))+
geom_hex(alpha = 0.9, bins = 30) +
scale_fill_gradientn(colours = cols(20))+
geom_smooth(method = "glm", color = "red", size = 0.5) +
ylim(c(5,14)) +
ggtitle("Overall") +
theme_bw()
p[[5]] = ggplot(data = dataset, aes(x = Potential, y = log(Wage+1)))+
geom_hex(alpha = 0.9, bins = 30) +
scale_fill_gradientn(colours = cols(20))+
geom_smooth(method = "glm", color = "red", size = 0.5) +
ylim(c(5,14)) +
ggtitle("Potential") +
theme_bw()
p[[6]] = ggplot(data = dataset, aes(x = Special, y = log(Wage+1)))+
geom_hex(alpha = 0.9, bins = 30) +
scale_fill_gradientn(colours = cols(20))+
geom_smooth(method = "glm", color = "red", size = 0.5) +
ylim(c(5,14)) +
ggtitle("Special") +
theme_bw()
figure1 = ggarrange(p[[1]], p[[2]], p[[3]],
common.legend = FALSE, legend = 'bottom',
ncol = 3, nrow = 1, heights = 0.5)
figure2 = ggarrange(p[[4]], p[[5]], p[[6]],
common.legend = FALSE, legend = 'bottom',
ncol = 3, nrow = 1, heights = 0.5)
annotate_figure(figure1,
top = text_grob("Valor de Contrato vs habilidades",
color = "#000000", face = "bold", size = 18))annotate_figure(figure2,
top = text_grob("Remuneración vs habilidades",
color = "#000000", face = "bold", size = 18))A continuación se muestran las habilidades agrupadas por tipo de habilidad (ofensivas, técnicas, movimiento, potencia y mentalidad).
La mayoría de las variables por si solas no muestran una relación directa con \(Value\), aunque \(LongPassing\), \(Reactions\), \(Composure\) y \(Vision\) si presentan relación directa.
GHV <- function(i, x, var = 8, xlim = c(0,100)){
ggplot(data = x, aes(x = x[,i], y = log(x[,var]+1))) +
geom_hex(alpha = 0.9, bins = 30) +
scale_fill_gradientn(colours = cols(20))+
xlab(names(x)[i])+ ylab(paste0("Log(", names(x)[var], " + 1)"))+
xlim(xlim) +
ggtitle(names(x)[i]) + theme_bw()
}
Graf_Hab_Value <- lapply(c(25:46), GHV, x = dataset)
Graf_Hab_Wage <- lapply(c(25:46), GHV, x = dataset, var = 9)
names(Graf_Hab_Value) <- names(dataset[,25:46])
names(Graf_Hab_Wage) <- names(dataset[,25:46])
# Habilidades ofensivas
GV_Of <- ggarrange(Graf_Hab_Value[[1]], Graf_Hab_Value[[2]],
Graf_Hab_Value[[3]], Graf_Hab_Value[[4]],
common.legend = FALSE, legend = 'left',
ncol = 2, nrow = 2, heights = 0.5)
GV_Of <- annotate_figure(GV_Of,
top = text_grob("Valor contrato vs habilidades ofensivas",
face = "bold", size = 18))
GW_Of <- ggarrange(Graf_Hab_Wage[[1]], Graf_Hab_Wage[[2]],
Graf_Hab_Wage[[3]], Graf_Hab_Wage[[4]],
common.legend = FALSE, legend = 'left',
ncol = 2, nrow = 2, heights = 0.5)
GW_Of <- annotate_figure(GW_Of,
top = text_grob("Remuneración vs habilidades ofensivas",
face = "bold", size = 18))
# Habilidades tecnicas
GV_tec <- ggarrange(Graf_Hab_Value[[5]], Graf_Hab_Value[[6]],
Graf_Hab_Value[[7]],
common.legend = FALSE, legend = 'left',
ncol = 2, nrow = 2, heights = 0.5)
GV_tec <- annotate_figure(GV_tec,
top = text_grob("Valor contrato vs habilidades técnicas",
face = "bold", size = 18))
GW_tec <- ggarrange(Graf_Hab_Wage[[5]], Graf_Hab_Wage[[6]],
Graf_Hab_Wage[[7]],
common.legend = FALSE, legend = 'left',
ncol = 2, nrow = 2, heights = 0.5)
GW_tec <- annotate_figure(GW_tec,
top = text_grob("Remuneración vs habilidades técnicas",
face = "bold", size = 18))
# Habilidades de movimiento
GV_mov <- ggarrange(Graf_Hab_Value[[8]], Graf_Hab_Value[[9]],
Graf_Hab_Value[[10]], Graf_Hab_Value[[11]],
Graf_Hab_Value[[12]],
common.legend = FALSE, legend = 'left',
ncol = 3, nrow = 2, heights = 0.3)
GV_mov <- annotate_figure(GV_mov,
top = text_grob("Valor contrato vs habilidades de movimiento",
face = "bold", size = 18))
GW_mov <- ggarrange(Graf_Hab_Wage[[8]], Graf_Hab_Wage[[9]],
Graf_Hab_Wage[[10]], Graf_Hab_Wage[[11]],
Graf_Hab_Wage[[12]],
common.legend = FALSE, legend = 'left',
ncol = 3, nrow = 2, heights = 0.3)
GW_mov <- annotate_figure(GW_mov,
top = text_grob("Remuneración vs habilidades de movimiento",
face = "bold", size = 18))
# Habilidades de potencia
GV_pot <- ggarrange(Graf_Hab_Value[[13]], Graf_Hab_Value[[14]],
Graf_Hab_Value[[15]], Graf_Hab_Value[[16]],
Graf_Hab_Value[[17]],
common.legend = FALSE, legend = 'left',
ncol = 3, nrow = 2, heights = 0.3)
GV_pot <- annotate_figure(GV_pot,
top = text_grob("Valor contrato vs habilidades de potencia",
face = "bold", size = 18))
GW_pot <- ggarrange(Graf_Hab_Wage[[13]], Graf_Hab_Wage[[14]],
Graf_Hab_Wage[[15]], Graf_Hab_Wage[[16]],
Graf_Hab_Wage[[17]],
common.legend = FALSE, legend = 'left',
ncol = 3, nrow = 2, heights = 0.3)
GW_pot <- annotate_figure(GW_pot,
top = text_grob("Remuneración vs habilidades de potencia",
face = "bold", size = 18))
# Habilidades de mentalidad
GV_men <- ggarrange(Graf_Hab_Value[[18]], Graf_Hab_Value[[19]],
Graf_Hab_Value[[20]], Graf_Hab_Value[[21]],
Graf_Hab_Value[[22]],
common.legend = FALSE, legend = 'left',
ncol = 3, nrow = 2, heights = 0.3)
GV_men <- annotate_figure(GV_men,
top = text_grob("Valor contrato vs habilidades de mentalidad",
face = "bold", size = 18))
GW_men <- ggarrange(Graf_Hab_Wage[[18]], Graf_Hab_Wage[[19]],
Graf_Hab_Wage[[20]], Graf_Hab_Wage[[21]],
Graf_Hab_Wage[[22]],
common.legend = FALSE, legend = 'left',
ncol = 3, nrow = 2, heights = 0.3)
GW_men <- annotate_figure(GW_men,
top = text_grob("Remuneración vs habilidades de mentalidad",
face = "bold", size = 18))
GV_OfGV_tecGV_movGV_potGV_menLa mayoría de las variables por si solas no muestran una relación directa con \(Wage\), aunque \(Reactions\), \(Composure\) y \(Vision\) si presentan relación directa.
GW_OfGW_tecGW_movGW_potGW_menLas habilidades de \(Reactions\), \(Composure\) y \(Vision\) son las más valoradas e implican ciertas características de adaptación rápida a cambios y dificultades en el juego.
Para este análsis se consideran países con más de 50 jugadores en el mercado. Se genera un indicador de estadísticas ponderadas, este indicadorson las estadísticas acumuladas (\(Special\)) multiplicada por \(Internacional.Reputation\).
Se observa que en general a mayor estadísticas ponderadas \(Value\) y \(Wage\) son más altos.
Existen varias excepciones, sobre todo en remuneración. Por ejemplo Paraguay y Nigeria tienen valores de \(Value\) y \(Wage\) más altos que los que deberían de acuerdo a su habilidad y reputación promedio. EL caso contrario lo presentan por ejemplo Russia y Greece que presentan valores más bajos de \(Value\) y \(Wage\) de los que deberían.
Esto se puede deber a varios factores, entre los cuales están el costo de vida y la fama de los jugadores de un país en particular.
data2 = dataset
data2$International.Reputation = as.numeric(as.character(data2$International.Reputation))
Paises <- group_by(data2, Nationality) %>%
summarise(Value_ac = sum(Value), Value_m = mean(Value),
Wage_ac = sum(Wage), Wage_m = mean(Wage),
Special_ac = sum(Special), Special_m = mean(Special),
Rep = mean(International.Reputation),
Players = n()) %>%
arrange(desc(Value_ac))
VPP <- ggplot(data = Paises[Paises$Players>50,],
aes(x = reorder(Nationality, Value_m),
y = Value_m, fill = Special_m*Rep)) +
geom_bar(stat = "identity", alpha = 0.9) +
scale_fill_gradientn(colours = cols(20),
name = "Estadística\nPonderada")+
geom_text(aes(label = round(Special_m*Rep,0)), size = 2.5) +
ggtitle("Valor de Contrato medio por país") +
xlab("Nacionalidad") + ylab("Valor de Contrato") +
coord_flip()+
theme_bw()
RPP <- ggplot(data = Paises[Paises$Players>50,],
aes(x = reorder(Nationality, Wage_m),
y = Wage_m, fill = Special_m*Rep)) +
geom_bar(stat = "identity", alpha = 0.9) +
scale_fill_gradientn(colours = cols(20),
name = "Estadística\nPonderada")+
geom_text(aes(label = round(Special_m*Rep,0)), size = 2.5) +
ggtitle("Remuneración media por país") +
xlab("Nacionalidad") + ylab("Remuneración") +
coord_flip()+
theme_bw()
GPP <- ggarrange(VPP, RPP, common.legend = TRUE, legend = 'left',
ncol = 2, nrow = 1, heights = 0.3)
annotate_figure(GPP, top = text_grob("Ganancias Jugadores por país",
face = "bold", size = 18))A continuación se muestra la relación entre la edad de los jugadores y el valor de contrato y remuneración de cada uno de ellos.
Se oberva que el mayor valor de contrato se obtiene entre los 25 y 30 años aprox. y luego baja al nivel deinicio del jugador en el futbol, esto es independiente de las estadísticas ponderadas, ya que aunque los jugadores de más edad cuenten con mayores estadísticas ponderadas, presentan valor de contrato menor.
En el caso de la remuneración es similar, con la diferencia que la remuneración de los futbolistas de mayor edad no baja tanto en comparación con los futbolistas jovenes, esto se podría deber a que la remuneración de los futbolistas llega directamente a cada uno y los mayores no estarían dispuestos a bajar el monto tan bruscamente considerando su experiencia.
data2 = dataset
data2$International.Reputation = as.numeric(as.character(data2$International.Reputation))
data2$Age <- factor(data2$Age)
Edad <- group_by(data2, Age) %>%
summarise(Value_ac = sum(Value), Value_m = mean(Value),
Wage_ac = sum(Wage), Wage_m = mean(Wage),
Special_ac = sum(Special), Special_m = mean(Special),
Rep = mean(International.Reputation),
Players = n()) %>%
arrange(desc(Value_ac))
VPP <- ggplot(data = Edad,
aes(x = Age,
y = Value_m, fill = Special_m*Rep)) +
geom_bar(stat = "identity", alpha = 0.9) +
scale_fill_gradientn(colours = cols(20),
name = "Estadística\nPonderada")+
geom_text(aes(label = round(Special_m*Rep,0)), size = 2.5) +
ggtitle("Valor de Contrato por edad") +
xlab("Edad") + ylab("Valor de Contrato") +
coord_flip()+
theme_bw()
RPP <- ggplot(data = Edad,
aes(x = Age,
y = Wage_m, fill = Special_m*Rep)) +
geom_bar(stat = "identity", alpha = 0.9) +
scale_fill_gradientn(colours = cols(20),
name = "Estadística\nPonderada")+
geom_text(aes(label = round(Special_m*Rep,0)), size = 2.5) +
ggtitle("Remuneración por edad") +
xlab("Edad") + ylab("Remuneración") +
coord_flip()+
theme_bw()
GPP <- ggarrange(VPP, RPP, common.legend = TRUE, legend = 'left',
ncol = 2, nrow = 1, heights = 0.3)
annotate_figure(GPP, top = text_grob("Ganancias Jugadores por edad",
face = "bold", size = 18))Las posiciones con mejores contratos son los mediocampistas y delanteros. Estos tienden a tener peso y altura medio/bajo.
Cuando se agrupa por tipo de cuerpo, se observa que para los jugadores con cuerpos tipo Lean los mejor pagados son los delanteros y mediocampistas, donde tienden a ser bajos y delgados.
En el caso de jugadores con cuerpo tipo Normal las ganancias se concentran en punta derecha e izquierda (LF y RF) y mediocampista de ataque izquierdo (LAM). Donde tienden a ser bajos y delgados.
Para los jugadores con cuerpo tipo Stocky las ganancias son mejores para los mediocampistas y delanteros, aunque algunas posiciones defensivas suben sus ganancias. En este caso los delanteros y medio campistas son bajos y delgados, y los defensas con mejores ganancias son más altos y pesados.
A nivel general para obtener mejores contratos es recomendable ser bajo y delgado, condiciones que se adaptan mejor para las posiciones de mediocampistas y delanteros.
data2 = dataset
data2$International.Reputation = as.numeric(as.character(data2$International.Reputation))
GB <- list()
for (k in 1:nlevels(data2$Body.Type)) {
Body <- group_by(data2[data2$Body.Type==levels(data2$Body.Type)[k],], Position) %>%
summarise(Height = mean(Height),
Weight = mean(Weight),
Wage = mean(Wage),
Value = mean(Value),
Players = n()) %>%
arrange(desc(Wage))
VPP <- ggplot(data = Body,
aes(x = reorder(Position, Value),
y = Height, fill = Value)) +
geom_bar(stat = "identity", alpha = 0.9) +
scale_fill_gradientn(colours = cols(20),
name = "Value")+
geom_text(aes(label = round(Value,0)), size = 2.5) +
ggtitle("Altura por posición") +
ylab("Altura (cms)") + xlab("Posición") +
coord_flip(ylim = c(0.995*range(data2$Height)[1],
1.005*range(data2$Height)[2]))+
theme_bw()
RPP <- ggplot(data = Body,
aes(x = reorder(Position, Value),
y = Weight, fill = Value)) +
geom_bar(stat = "identity", alpha = 0.9) +
scale_fill_gradientn(colours = cols(20),
name = "Value")+
geom_text(aes(label = round(Value,0)), size = 2.5) +
ggtitle("Peso por posición") +
ylab("Peso (Kg)") + xlab("Posición") +
coord_flip(ylim = c(0.995*range(data2$Weight)[1],
1.005*range(data2$Weight)[2]))+
theme_bw()
GPP <- ggarrange(VPP, RPP, common.legend = TRUE, legend = 'left',
ncol = 2, nrow = 1, heights = 0.3)
text_gb <- paste0("Características físicas por posición\n (tipo de cuerpo ",
levels(data2$Body.Type)[k], ")")
GB[[levels(data2$Body.Type)[k]]] <- annotate_figure(GPP,
top = text_grob(text_gb,
face = "bold",
size = 18))
}
Body <- group_by(data2, Position) %>%
summarise(Height = mean(Height),
Weight = mean(Weight),
Wage = mean(Wage),
Value = mean(Value),
Players = n()) %>%
arrange(desc(Wage))
VPP <- ggplot(data = Body,
aes(x = reorder(Position, Value),
y = Height, fill = Value)) +
geom_bar(stat = "identity", alpha = 0.9) +
scale_fill_gradientn(colours = cols(20),
name = "Value")+
geom_text(aes(label = round(Value,0)), size = 2.5) +
ggtitle("Altura por posición") +
ylab("Altura (cms)") + xlab("Posición") +
coord_flip(ylim = c(0.995*range(data2$Height)[1],
1.005*range(data2$Height)[2]))+
theme_bw()
RPP <- ggplot(data = Body,
aes(x = reorder(Position, Value),
y = Weight, fill = Value)) +
geom_bar(stat = "identity", alpha = 0.9) +
scale_fill_gradientn(colours = cols(20),
name = "Value")+
geom_text(aes(label = round(Value,0)), size = 2.5) +
ggtitle("Peso por posición") +
ylab("Peso (Kg)") + xlab("Posición") +
coord_flip(ylim = c(0.995*range(data2$Weight)[1],
1.005*range(data2$Weight)[2]))+
theme_bw()
GPP <- ggarrange(VPP, RPP, common.legend = TRUE, legend = 'left',
ncol = 2, nrow = 1, heights = 0.3)
text_gb <- paste0("Características físicas por posición")
GB[[4]] <- annotate_figure(GPP, top = text_grob(text_gb,
face = "bold", size = 18))
GB[[4]]GB[[1]]GB[[2]]GB[[3]]Para hacer la predicción se utiliza la función \(h2o.automl\) de la librería h2o. H2O AutoML es una plataforma de inteligencia artificial que automatiza el proceso de creación, selección y optimización de un gran número de modelos de aprendizaje automático mediante el metodo de Stacked Ensembles.
Los métodos de aprendizaje automático basados en Stacked Ensembles utilizan múltiples algoritmos de aprendizaje para obtener un mejor rendimiento predictivo que el que se podría obtener de cualquiera de los algoritmos de aprendizaje constituyentes. Muchos de los algoritmos populares de aprendizaje automático son en realidad conjuntos.
En esta predicción no se consideran las variables \(Wage\) ni \(Release.Clause\). Los datos se dividen en conjunto de entrenamiento y test (70% y 30%). Se utiliza validación cruzada con 10 folds, y la métrica a optimizar es el RMSLE.
dataset2 = dataset[,-c(9, 47)]
dataset2$Value = log(dataset2$Value + 1)
tiempo=3600*0.5
# Inicializa cluster
h2o.init(nthreads = -1, # Utiliza todoslos cores disponibles
max_mem_size = "4g") # Maxima memoria disponible para el cluster.
h2o.no_progress()
particiones <- h2o.splitFrame(data = as.h2o(dataset2),
ratios = c(0.7),
seed = 123)
datos_train_h2o <- h2o.assign(data = particiones[[1]], key = "datos_train_H2O")
datos_test_h2o <- h2o.assign(data = particiones[[2]], key = "datos_test_H2O")
y1 <- "Value"
x1 <- setdiff(names(datos_train_h2o), y1)
aml1 <- h2o.automl(x = x1,
y = y1,
training_frame = datos_train_h2o,
validation_frame = datos_test_h2o,
leaderboard_frame = NULL,
nfolds = 10,
fold_column = NULL,
weights_column = NULL,
balance_classes = FALSE,
class_sampling_factors = NULL,
max_after_balance_size = 5,
max_runtime_secs = tiempo,
max_models = NULL,
stopping_metric = "RMSLE",
stopping_tolerance = NULL,
stopping_rounds = 5,
seed = 123,
project_name = NULL,
exclude_algos = NULL,
keep_cross_validation_predictions = FALSE,
keep_cross_validation_models = FALSE,
keep_cross_validation_fold_assignment = FALSE,
sort_metric = "RMSLE",
export_checkpoints_dir = NULL)Una vez realizado el entrenamiento, tenemos el RMSLE¨ dedistintos algoritmos de regresión. El algoritmo de Assemble Stacked* selecciona la combinación de algoritmos con mejor rendimiento, asignandole un peso a cada uno de ellos.
Observando el resultado del entrenamiento se tiene que la predicción es buena, presentando un error bajo y similar tanto en el conjunto de entrenamiento, test y validación cruzada.
lb1 <- as.data.frame(aml1@leaderboard[c(1:10),c(1,6)])
lb1$rmsle <- round(lb1$rmsle,5)
htmlTable(lb1,
caption = "Tabla 25. Resumen error modelos.",
tfoot = paste0("† Los 10 modelos con mejor RMSLE"),
col.rgroup = c("none","#9999F7"))| Tabla 25. Resumen error modelos. | ||
| model_id | rmsle | |
|---|---|---|
| 1 | GBM_grid_1_AutoML_20191005_154252_model_3 | 0.0069 |
| 2 | GBM_grid_1_AutoML_20191005_162250_model_3 | 0.0069 |
| 3 | GBM_grid_1_AutoML_20191005_123946_model_3 | 0.0069 |
| 4 | GBM_grid_1_AutoML_20191004_002336_model_3 | 0.0069 |
| 5 | GBM_grid_1_AutoML_20191005_171935_model_3 | 0.0069 |
| 6 | GBM_5_AutoML_20191005_162250 | 0.00849 |
| 7 | GBM_5_AutoML_20191005_154252 | 0.00849 |
| 8 | GBM_5_AutoML_20191004_002336 | 0.00849 |
| 9 | GBM_5_AutoML_20191005_171935 | 0.00849 |
| 10 | GBM_5_AutoML_20191005_123946 | 0.00849 |
| † Los 10 modelos con mejor RMSLE | ||
# Get model ids for all models in the AutoML Leaderboard
model_ids1 <- as.data.frame(aml1@leaderboard$model_id)[,1]
# Get the "All Models" Stacked Ensemble model
se1 <- h2o.getModel(grep("StackedEnsemble_AllModels", model_ids1, value = TRUE)[1])
# Get the Stacked Ensemble metalearner model
metalearner1 <- h2o.getModel(se1@model$metalearner$name)
# Importancia de los modelos
modelImportV <- h2o.varimp(metalearner1)[,c(1,3)]
names(modelImportV) <- c("Modelos", "Importancia")
# modelImportV <- modelImportV[!is.na(modelImportV$Modelos),]
ggplot(data = modelImportV,
aes(x = Modelos,
y = Importancia, fill = Importancia)) +
geom_bar(stat = "identity", alpha = 0.9) +
scale_fill_gradientn(colours = cols(20),
name = "Importancia")+
geom_text(aes(label = round(Importancia,3)), size = 2.5) +
ggtitle("Nivel de importancia por modelo") +
ylab("Importancia relativa") + xlab("Modelos") +
coord_flip()+
theme_bw()#h2o.varimp_plot(metalearner1, num_of_features = 10)
RMSLE <- data.frame(RMSLE = c(h2o.rmsle(metalearner1, train = TRUE),
h2o.rmsle(metalearner1, valid = TRUE),
h2o.rmsle(metalearner1, xval = TRUE)),
row.names = c("Train", "Test", "K-fold"),
stringsAsFactors = FALSE)
htmlTable(RMSLE,
caption = "Tabla 26. Resultados de entrenamiento.",
tfoot = paste0(""),
col.rgroup = c("none","#9999F7"))| Tabla 26. Resultados de entrenamiento. | |
| RMSLE | |
|---|---|
| Train | 0.0129512104342772 |
| Test | 0.0128517524817997 |
| K-fold | 0.0129566309459299 |
pred <- as.data.frame(h2o.predict(aml1, datos_test_h2o))
test <- as.data.frame(datos_test_h2o)
test = cbind(test["ID"], test["Name"], test["Nationality"],
(exp(test[y1])-1)/1000000,
(exp(pred)-1)/1000000)
test$Error = abs(test$Value - test$predict)
ggplot(data = test, aes(x = Value, y = predict, color = Error)) +
geom_point(alpha = 0.6, size = 3) +
scale_color_gradient(high = cols(2)[2], low = cols(2)[1]) +
ggtitle("Comparación entre Value y predicción (conjunto de test)") +
xlab("Value (M€)") + ylab("Predicción (M€)") +
geom_smooth(method = "glm", color = "red", size = 0.5) +
theme_bw()# h2o.shutdown(prompt = FALSE)Las variables del dataset contienen el siguiente tipo de información:
sessionInfo()R version 3.6.0 (2019-04-26)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 17134)
Matrix products: default
locale:
[1] LC_COLLATE=Spanish_Chile.1252 LC_CTYPE=Spanish_Chile.1252
[3] LC_MONETARY=Spanish_Chile.1252 LC_NUMERIC=C
[5] LC_TIME=Spanish_Chile.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] hexbin_1.27.3 dplyr_0.8.1 h2o_3.26.0.2
[4] GGally_1.4.0 RColorBrewer_1.1-2 corrplot_0.84
[7] htmlTable_1.13.2 ggpubr_0.2.3 magrittr_1.5
[10] ggplot2_3.1.1 lubridate_1.7.4 readr_1.3.1
loaded via a namespace (and not attached):
[1] Rcpp_1.0.1 pillar_1.4.1 compiler_3.6.0 plyr_1.8.4
[5] bitops_1.0-6 tools_3.6.0 digest_0.6.19 lattice_0.20-38
[9] jsonlite_1.6 checkmate_1.9.4 evaluate_0.14 tibble_2.1.3
[13] gtable_0.3.0 pkgconfig_2.0.2 rlang_0.3.4 rstudioapi_0.10
[17] yaml_2.2.0 xfun_0.7 gridExtra_2.3 withr_2.1.2
[21] stringr_1.4.0 knitr_1.23 htmlwidgets_1.3 hms_0.4.2
[25] cowplot_1.0.0 grid_3.6.0 tidyselect_0.2.5 reshape_0.8.8
[29] glue_1.3.1 R6_2.4.0 rmarkdown_1.13 purrr_0.3.2
[33] backports_1.1.4 scales_1.0.0 htmltools_0.3.6 assertthat_0.2.1
[37] colorspace_1.4-1 ggsignif_0.5.0 labeling_0.3 stringi_1.4.3
[41] RCurl_1.95-4.12 lazyeval_0.2.2 munsell_0.5.0 crayon_1.3.4