Resumen

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:

  • Hay relación entre la reputación internacional de un jugador y la remuneración y/o valor del contrato?.
  • Hay relación entre habilidades y ganancia de los jugadores?.
  • Cuáles son estas habilidades?.
  • Hay relación entre el país de origen y las ganancias del jugador?.
  • Existe relación entre edad de los futbolistas y sus habilidades y ganancias?.
  • El peso, altura y tipo de cuerpo tienen relación con la posición de juego?, y esta, a su vez, con la reputación internacional?.
  • Es posible hacer una buena predicción de las ganancias del jugador en base a las características de este?.

Limpieza de datos

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))

Carga de datos.

El dataset tiene 89 variables, de los cuales se de eliminarán las siguientes por no representar información relevante:

  • Unnamed: Variable que enumera las filas.
  • Photo: Enlace a una imagen del jugador.
  • Flag: Enlace a una imagen de la bandera del país.
  • Club Logo: Club al que pertenece el jugador.
  • Real Face: Sin información de la variable.
  • Jersey.Number: Número de camiseta.
  • Joined: Fecha de ingreso al equipo.
  • Loaned From: Equipo anterior, muchos \(NA\) presentes.
  • Contract.Valid.Until: Fecha de término de contrato.

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",]

Revisión, limpieza y transformación de variables.

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 distribución de edad de los futbolistas es distinta al resto de los jugadores. Situación que es justificable debido a que estos normalmente juegan sólo de porteros (es una posición muy específica).
  • En el dataset no hay información de habilidad de los porteros en otras posiciones.
  • La variable Special, de acuerdo al punto anterior, se ve muy afectada mostrando una clara diferencia entre estos dos grupos.
  • En muchas de las habilidades de ofensiva, técnica, movimiento, potencia, mentalidad, defensa y potero la distribución se ve afectada dependiendo de que grupo se análisa.

Value.

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("&dagger; ", 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("&dagger; 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("&dagger; 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.

ID.

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("&dagger; ", 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.

Name.

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("&dagger; 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.

Age.

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("&dagger; ", 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.

Nationality.

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("&dagger; 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.

Overall.

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("&dagger; ", 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.

Potential.

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("&dagger; ", 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.

Club.

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("&dagger; 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.

Wage.

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("&dagger; ", 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.

Special.

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("&dagger; ", 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.

International.Reputation.

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.

Preferred.Foot.

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("&dagger; ", 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.

Weak.Foot.

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.

Skill.Moves.

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.

Work.Rate.

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("&dagger; ", 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:

  • Razón de trabajo alta: estos jugadores tienen un desempeño medio-alto tanto en defensa como en delantera. Es la mayoría de los jugadores (85%).
  • Razón de trabajo defensiva: son los jugadores que tienen bajo trabajo ofensivo, pero medio-alto trabajo defensivo. Representan el (9.5%).
  • Razón de trabajo ofensivo: son los jugadores que tienen bajo trabajo defensivo, pero medio-alto trabajo ofensivo (5%).
  • Razón de trabajo bajo: son jugadores que no presentan buen desempeño ofensivo como defensivo (0.5%).

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.

Body.Type.

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("&dagger; ", 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.

Position.

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("&dagger; ", 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:

  • Defensas: 6409 (40%)
  • Mediocampistas: 4963 (31%)
  • Delanteros: 4546 (29%)

Las posiciones más comunes entre los defensas son:

  • Right Wing Back (RWB): Lateral derecho.
  • Right Back (RB): Defensa derecho.
  • Left Center Back (LCB): Defensa central izquierdo.
  • Left Back (LB): Defensa izquierdo.
  • Center Back (CB): Defensa central.

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:

  • Right Defender Midfield (RDM): Mediocampista defensivo derecho.
  • Right Midfield (RM): Mediocampista derecho.
  • Left Center Midfield (LCM): Mediocampista central izquierdo.
  • Center Attacking Midfielder (CAM): Medicampista central de ataque.

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:

  • Left Wing (LW): Delantero ala izquierda.
  • Striker (ST): Delantero (centro, izquierda, derecha).

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.

Height.

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("&dagger; ", 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.

Weight.

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("&dagger; ", 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.

Skills.

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("&dagger; 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("&dagger; 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))
}

Release.Clause

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("&dagger; ", 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..

Análisis y predicción.

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\)).

Relación entre Value, 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()

Relación entre Habilidades y Ganancias.

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_Of

GV_tec

GV_mov

GV_pot

GV_men

La 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_Of

GW_tec

GW_mov

GW_pot

GW_men

Las 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.

Relación entre el país de origen y ganancias.

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))

Relación entre edad, habilidades y ganancias.

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))

Relación características físicas.

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]]

Predicción de valor de contrato y remuneración.

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("&dagger; 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)

Anexo

Descripción de variables:

Las variables del dataset contienen el siguiente tipo de información:

  • Unnamed: Variable que enumera las filas.
  • ID: Identificador del jugador.
  • Name: Nombre del Jugador.
  • Age: Edad del Jugador.
  • Photo: Enlace a una imagen del jugador.
  • Nationality: Nacionalidad del Jugador.
  • Flag: Enlace a una imagen de la bandera del país.
  • Overall: Puntaje de habilidad general (0-99).
  • Potential: Puntaje potencial de habilidad (0-99).
  • Club: Club al que pertenece el jugador.
  • Club Logo: Enlace a una imagen del logo del club.
  • Value: Valor del jugador en €.
  • Wage: Salario del jugador en €.
  • Special: Total Estadístiscas de cada jugador.
  • Preferred Foot: Pie preferido.
  • International Reputation: Reputación del jugador (1-5).
  • Weak Foot: Habilidad con pierna no preferida (1-5).
  • Skill Moves: Movilidad del jugador (1-5).
  • Work Rate: Ratio de trabajo ofensivo/defensivo.
  • Body Type: Tipo de cuerpo, categorías delgado, normal, fornido.
  • Real Face: Sin información de la variable.
  • Position: Posición en el campo.
  • Jersey Number: Número de camiseta.
  • Joined: Fecha de ingreso al equipo.
  • Loaned From: Equipo anterior.
  • Contract Valid Until: Fecha término de contrato.
  • Height: Altura
  • Weight: Peso
  • LS: Habilidad como Left Striker (0-99).
  • ST: Habilidad como Striker (0-99).
  • RS: Habilidad como Right Striker (0-99).
  • LW: Habilidad como Left Wing (0-99).
  • LF: Habilidad como Left Forward (0-99).
  • CF: Habilidad como Center Forward (0-99).
  • RF: Habilidad como Right Forward (0-99).
  • RW: Habilidad como Right Wing (0-99).
  • LAM: Habilidad como Left Attacking Midfielder (0-99).
  • CAM: Habilidad como Center Attacking Midfielder (0-99).
  • RAM: Habilidad como Right Attacking Midfielder (0-99).
  • LM: Habilidad como Left Midfielder (0-99).
  • LCM: Habilidad como Left Center Midfielder (0-99).
  • CM: Habilidad como Center Midfielder (0-99).
  • RCM: Habilidad como Right Center Midfielder (0-99).
  • RM: Habilidad como Right Midfielder (0-99).
  • LWB: Habilidad como Left Wing Back (0-99).
  • LDM: Habilidad como Left Defensive Midfielder (0-99).
  • CDM: Habilidad como Center Defensive Midfielder (0-99).
  • RDM: Habilidad como Right Defensive Midfielder (0-99).
  • RWB: Habilidad como Right Wing Back (0-99).
  • LB: Habilidad como Left Back (0-99).
  • LCB: Habilidad como Left Center Back (0-99).
  • CB: Habilidad como Center Back (0-99).
  • RCB: Habilidad como Right Center Back (0-99).
  • RB: Habilidad como Right Back (0-99).
  • Crossing: Ofensiva, habilidad en centros (0-99).
  • Finishing: Ofensiva, habilidad en definición (0-99).
  • HeadingAccuracy: Ofensiva, precisión con la cabeza (0-99).
  • ShortPassing: Ofensiva, habilidad en pases cortos (0-99).
  • Volleys: Ofensiva, habilidad en voleas (0-99).
  • Dribbling: Técnica, habilidad en regates (0-99).
  • Curve: Técnica, habilidad en balones con efecto (0-99).
  • FKAccuracy: Técnica, habilidad en precisión faltas (0-99).
  • LongPassing: Técnica, habilidad en pases largos (0-99).
  • BallControl: Técnica, habilidad en control del balón (0-99).
  • Acceleration: Movimiento, aceleración (0-99).
  • SprintSpeed: Movimiento, velocidad (0-99).
  • Agility: Movimiento, agilidad (0-99).
  • Reactions: Movimiento, reflejos (0-99).
  • Balance: Movimiento, equilibrio (0-99).
  • ShotPower: Potencia, potencia (0-99).
  • Jumping: Potencia, salto (0-99).
  • Stamina: Potencia, resistencia (0-99).
  • Strength: Potencia, fuerza (0-99).
  • LongShots: Potencia, tiros lejanos (0-99).
  • Aggression: Mentalidad, agresividad (0-99).
  • Interceptions: Mentalidad, intercepción (0-99).
  • Positioning: Mentalidad, colocación (0-99).
  • Vision: Mentalidad, visión (0-99).
  • Penalties: Mentalidad, penales (0-99).
  • Composure: Mentalidad, compostura (0-99).
  • Marking: Defensa, marcaje (0-99)
  • StandingTackle: Defensa, robos (0-99)
  • SlidingTackle: Defensa, entrada agresiva (0-99)
  • GKDiving: Portero, estirada (0-99)
  • GKHandling: Portero, paradas (0-99)
  • GKKicking: Portero, saques (0-99)
  • GKPositioning: Portero, colocación (0-99)
  • GKReflexes: Portero, reflejos (0-99)
  • Release Clause: Clausula de liberación en €.

Referencias.

Sesió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