Analizamos 510 temporadas de equipos de la MLB entre 2000 y 2016 para responder una pregunta sencilla: ¿los equipos que gastan más en salarios ganan más partidos?
Cada temporada se habla de los equipos que “compran” campeonatos. Pero, ¿qué dicen los datos? Aquí medimos la relación entre lo que cada equipo paga a sus jugadores y los partidos que gana en la temporada regular.
Salaries.csv (salario
de cada jugador por equipo y temporada) y Teams.csv
(victorias y derrotas de cada equipo por temporada).Usamos una regresión lineal simple:
\[ \text{Victorias}_{i,t} = a + b \times \text{Salario relativo}_{i,t} + e_{i,t} \]
donde i es el equipo y t la temporada.
¿Por qué “salario relativo” y no el salario en dólares? Porque los salarios suben cada año: gastar 100 millones en 2005 no es lo mismo que en 2016. Por eso dividimos el gasto de cada equipo entre el promedio de la liga en esa misma temporada:
Así, el coeficiente b se lee como: cuántas victorias más gana un equipo cuando pasa de gastar el promedio a gastar el doble.
salarios <- read.csv("Salaries.csv", fileEncoding = "UTF-8-BOM")
equipos <- read.csv("Teams.csv", fileEncoding = "UTF-8-BOM")
str(salarios)
## 'data.frame': 26428 obs. of 5 variables:
## $ yearID : int 2004 2007 2008 2009 2010 2011 2012 1986 1987 1988 ...
## $ teamID : chr "SFN" "CHA" "BOS" "SEA" ...
## $ lgID : chr "NL" "AL" "AL" "AL" ...
## $ playerID: chr "aardsda01" "aardsda01" "aardsda01" "aardsda01" ...
## $ salary : int 300000 387500 403250 419000 2750000 4500000 500000 600000 625000 675000 ...
# Quitamos salarios en cero (registros sin pago)
salarios <- salarios[salarios$salary > 0, ]
# En 2016 la tabla de salarios usa otros códigos de equipo que la tabla de equipos.
# Los cambiamos para que coincidan.
codigos <- c(CHC = "CHN", CHW = "CHA", KCR = "KCA", LAD = "LAN", NYM = "NYN", NYY = "NYA",
SDP = "SDN", SFG = "SFN", STL = "SLN", TBR = "TBA", WSN = "WAS")
cambiar <- salarios$teamID %in% names(codigos)
salarios$teamID[cambiar] <- codigos[salarios$teamID[cambiar]]
# Sumamos los salarios de todos los jugadores: gasto total por equipo y temporada
payroll <- aggregate(salary ~ yearID + teamID, data = salarios, FUN = sum)
names(payroll)[3] <- "payroll"
# Nos quedamos con las temporadas 2000-2016 y las columnas que usamos
equipos <- equipos[equipos$yearID >= 2000 & equipos$yearID <= 2016,
c("yearID", "teamID", "name", "W", "L")]
# Unimos victorias con salarios
datos <- merge(equipos, payroll, by = c("yearID", "teamID"))
# Salario relativo: gasto del equipo / promedio de la liga en esa temporada
prom <- aggregate(payroll ~ yearID, data = datos, FUN = mean)
names(prom)[2] <- "prom_liga"
datos <- merge(datos, prom, by = "yearID")
datos$sal_rel <- datos$payroll / datos$prom_liga
datos$payroll_mill <- datos$payroll / 1e6
# Revisión: deben ser 30 equipos x 17 temporadas = 510 filas
nrow(datos)
## [1] 510
summary(datos[, c("W", "payroll_mill", "sal_rel")])
## W payroll_mill sal_rel
## Min. : 43.00 Min. : 14.67 Min. :0.1769
## 1st Qu.: 72.00 1st Qu.: 59.07 1st Qu.:0.7174
## Median : 82.00 Median : 80.41 Median :0.9360
## Mean : 80.96 Mean : 86.50 Mean :1.0000
## 3rd Qu.: 90.00 3rd Qu.:104.09 3rd Qu.:1.2077
## Max. :116.00 Max. :231.98 Max. :2.8552
modelo <- lm(W ~ sal_rel, data = datos)
summary(modelo)
##
## Call:
## lm(formula = W ~ sal_rel, data = datos)
##
## Residuals:
## Min 1Q Median 3Q Max
## -34.506 -7.397 0.329 7.517 33.420
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 69.696 1.235 56.419 <2e-16 ***
## sal_rel 11.269 1.146 9.835 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 10.43 on 508 degrees of freedom
## Multiple R-squared: 0.16, Adjusted R-squared: 0.1583
## F-statistic: 96.73 on 1 and 508 DF, p-value: < 2.2e-16
b <- coef(modelo)[2]
r2 <- summary(modelo)$r.squared
correlacion <- cor(datos$W, datos$sal_rel)
plot(datos$sal_rel, datos$W,
pch = 19, col = rgb(13, 132, 54, 110, maxColorValue = 255),
xlab = "Salario relativo (1 = promedio de la liga)",
ylab = "Victorias en la temporada",
main = "Salarios vs. victorias en la MLB, 2000-2016")
abline(modelo, col = "#E23D2E", lwd = 3, lty = 2)
abline(v = 1, col = "gray60", lty = 3)
Guardamos los residuos del modelo. Un residuo positivo significa que el equipo ganó más de lo que su salario predecía. Uno negativo, que ganó menos.
datos$esperadas <- round(fitted(modelo), 1)
datos$residuo <- round(resid(modelo), 1)
datos$payroll_mill <- round(datos$payroll_mill, 1)
datos$sal_rel <- round(datos$sal_rel, 2)
cols <- c("name", "yearID", "payroll_mill", "sal_rel", "W", "esperadas", "residuo")
# Los más eficientes: ganaron mucho más de lo que su salario predecía
eficientes <- head(datos[order(-datos$residuo), cols], 5)
# Gastaron más que el promedio y ganaron mucho menos de lo esperado
caros <- datos[datos$sal_rel > 1, ]
derrochadores <- head(caros[order(caros$residuo), cols], 5)
# Gráfica para Instagram (1080 x 1080) y datos limpios
png("grafica_salarios_victorias.png", width = 1080, height = 1080, res = 150)
plot(datos$sal_rel, datos$W, pch = 19,
col = rgb(13, 132, 54, 110, maxColorValue = 255),
xlab = "Salario relativo (1 = promedio)", ylab = "Victorias",
main = "Salarios vs. victorias, MLB 2000-2016")
abline(modelo, col = "#E23D2E", lwd = 3, lty = 2)
dev.off()
## png
## 2
write.csv(datos, "datos_salarios_victorias.csv", row.names = FALSE)
\[ \widehat{\text{Victorias}} = 69.70 + 11.27 \times \text{Salario relativo} \]
Cómo se lee: un equipo que gasta igual que el promedio de la liga (salario relativo = 1) gana, según el modelo, unas 81 victorias. Por cada vez que su gasto sube en una unidad (por ejemplo, de gastar el promedio a gastar el doble), gana en promedio 11.3 partidos más.
| Indicador | Valor |
|---|---|
| Temporadas analizadas | 510 |
| Victorias extra al gastar el doble del promedio (b) | 11.3 |
| Victorias extra por cada 10 % más de gasto | 1.1 |
| R² (parte explicada por el salario) | 16 % |
| Correlación | 0.4 |
Lectura sencilla: gastar más sí ayuda a ganar, y la relación es estadísticamente significativa. Pero el salario solo explica cerca del 16 % de las diferencias en victorias. Hay equipos que ganan mucho gastando poco, y otros que gastan mucho y no ganan.
Ganaron muchas más victorias de las que su salario predecía.
| Equipo | Temporada | Salarios (millones US$) | Salario relativo | Victorias | Esperadas | Diferencia |
|---|---|---|---|---|---|---|
| Seattle Mariners | 2001 | 74.7 | 1.14 | 116 | 82.6 | 33.4 |
| Oakland Athletics | 2002 | 40.0 | 0.59 | 103 | 76.4 | 26.6 |
| Oakland Athletics | 2001 | 33.8 | 0.52 | 102 | 75.5 | 26.5 |
| Tampa Bay Rays | 2008 | 43.8 | 0.49 | 97 | 75.2 | 21.8 |
| St. Louis Cardinals | 2004 | 83.2 | 1.21 | 105 | 83.3 | 21.7 |
Gastaron más que el promedio de la liga y ganaron muchas menos victorias de las esperadas.
| Equipo | Temporada | Salarios (millones US$) | Salario relativo | Victorias | Esperadas | Diferencia |
|---|---|---|---|---|---|---|
| Arizona Diamondbacks | 2004 | 69.8 | 1.01 | 51 | 81.1 | -30.1 |
| Seattle Mariners | 2008 | 117.7 | 1.31 | 61 | 84.5 | -23.5 |
| New York Mets | 2003 | 116.9 | 1.65 | 66 | 88.3 | -22.3 |
| Boston Red Sox | 2012 | 173.2 | 1.77 | 69 | 89.7 | -20.7 |
| Minnesota Twins | 2011 | 112.7 | 1.21 | 63 | 83.4 | -20.4 |
Salaries.csv y
Teams.csv en la misma carpeta que este archivo
.Rmd.Hecho por Sports Economics · Sports economics made simple.