python
numpy
pandas
matplotlib
]
Comenzamos la tarea de analizar a los atletas profesionales mejor pagados importando las librerías de Python y el conjunto de datos que vamos a necesitar.
in[1]: import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="darkgrid")
plt.style.use("seaborn-pastel")
df = pd.read_excel("Forbes Athlete List 2012-2019.xlsx")
df.head()
out[1]: Rank Name Pay Salary/Winnings Endorsements Sport Year
#1 Lionel Messi $127 M $92 M $35 M Soccer 2019
#2 Cristiano Ronaldo $109 M $65 M $44 M Soccer 2019
#3 Neymar $105 M $75 M $30 M Soccer 2019
#4 Canelo Alvarez $94 M $92 M $2 M Boxing 2019
#5 Roger Federer $93.4 M $7.4 M $86 M Tennis 2019
Nuestro conjunto de datos contiene 7 columnas y 795 filas, vamos a describir cada una de sus características:
El conjunto de datos que estamos utilizando es de Forbes. Algunas columnas no son consistentes en el conjunto de datos debido a que Forbes ha agregado un # antes de los valores en la columna Rank. Vamos a arreglar esto y quitar el signo de dólar $ y M. Además, cambiamos los nombres de las columnas de nuestro conjunto de datos y el nombre de los deportes dentro de la columna Deporte para una mejor comprensión de nuestro conjunto de datos.
in[2]: df.Rank = df.Rank.apply(lambda x: int(x.split("#")[1]) if type(x) == np.str else x)
df.Pay = df.Pay.apply(lambda x: float(x.split(" ")[0].split("$")[1]))
df.Endorsements = df.Endorsements.apply(lambda x: float(x.split(" ")[0].split("$")[1]))
df["Salary/Winnings"].replace("-",'$nan M',inplace=True)
df["Salary/Winnings"] = df["Salary/Winnings"].apply(lambda x: float(x.split(" ")[0].split("$")[1]))
df.columns = ['Ranking', 'Nombre', 'Ingresos', 'Salario', 'Patrocinio', 'Deporte', 'Año']
df.Deporte.replace({"Soccer":"Fútbol", "Football":"Fútbol Americano", "Baseball":"Beisbol",
"Basketball":"Basquetbol", "Mixed Martial Arts":"MMA", "Auto racing":"Automovilismo",
"Auto Racing":"Automovilismo", "Tennis":"Tenis", "Boxing":"Boxeo","Basketbal":"Basquetbol",
"Motorcycle":"Motociclismo",
},inplace=True)
df.head()
out[2]: Ranking Nombre Ingresos Salario Patrocinio Deporte Año
1 Lionel Messi 127.0 92.0 35.0 Fútbol 2019
2 Cristiano Ronaldo 109.0 65.0 44.0 Fútbol 2019
3 Neymar 105.0 75.0 30.0 Fútbol 2019
4 Canelo Alvarez 94.0 92.0 2.0 Boxeo 2019
5 Roger Federer 93.4 7.4 86.0 Tenis 2019
Buscamos valores nulos en nuestro conjunto de datos y procedemos a eliminarlos
in[3]: df.isnull().any()
out[3]: Ranking False
Nombre False
Ingresos False
Salario True
Patrocinio False
Deporte False
Año False
dtype: bool
Podemos ver que la columna Salario contiene valores nulos. A continuación, buscamos más detalles:
in[4]: df[df["Salario"].isnull()]
out[4]: Ranking Nombre Ingresos Salario Patrocinio Deporte Año
520 79 Russell Westbrook 0.0 NaN 0.0 Basquetbol 2015
Nuestro conjunto de datos tiene una instancia con valores nulos. Procedemos a eliminarla usando el índice de dicha instancia.
in[5]: df.drop(520, inplace=True)
Finalmente, verificamos que nuestro conjunto de datos no tenga más valores nulos.
in[6]: df.isnull().any()
out[6]: Ranking False
Nombre False
Ingresos False
Salario False
Patrocinio False
Deporte False
Año False
dtype: bool
Ahora que nuestro conjunto de datos ya no contiene valores nulos podemos visualizar los atletas mejor pagados del mundo en base al deporte que practican
in[7]: df.groupby("Nombre").first()["Deporte"].value_counts().plot(kind="pie", autopct="%.0f%%",figsize=(15,15),wedgeprops=dict(width=0.4),pctdistance=0.8)
plt.ylabel(None)
plt.title("Atletas mejor pagados por deporte",fontweight="bold")
plt.show()

Algunos deportes representan menos del 1% del conjunto de datos. Procedemos a eliminarlos para una mejor visualizacion de los datos.
in[8]: df = df[(df["Deporte"] != "MMA") & (df["Deporte"] != "Track") & (df["Deporte"] != "Motociclismo")]
df.groupby("Nombre").first()["Deporte"].value_counts().plot(kind="pie",autopct="%.0f%%", figsize=(15,15),wedgeprops=dict(width=0.4),pctdistance=0.8)
plt.ylabel(None)
plt.title("Atletas mejor pagados por deporte",fontweight="bold")
plt.show()

Para poder crear nuestra barra de animación del acumulado de ingresos de los atletas mejor pagados del mundo debemos convertir la columna Año en un objeto DateTime.
in[9]: df.Año = pd.to_datetime(df.Año,format="%Y")
Después, creamos una tabla dinámica donde las columnas están compuestas por los nombres de los atletas y los índices por los años.
in[10]: racing_bar_data = df.pivot_table(values="Ingresos",index="Año",columns="Nombre")
racing_bar_data.head()
out[10]: Nombre A.J. Burnett A.J. Green Aaron Donald Aaron Rodgers Adam Wainwright
Año
2012-01-01 NaN NaN NaN NaN NaN
2013-01-01 16.6 NaN NaN 49.0 NaN
2014-01-01 NaN NaN NaN 22.0 NaN
2015-01-01 NaN NaN NaN 19.1 19.8
2016-01-01 NaN 33.3 NaN NaN NaN
La mayoría de los atletas tienen valores NaN. Solo por curiosidad, veamos cuales son los atletas que aparecen de manera constante desde el 2012 en el Top 100 de los atletas mejor pagados del mundo.
in[11]: racing_bar_data.columns[racing_bar_data.isnull().sum() == 0]
out[11]: Index(['Carmelo Anthony', 'Cristiano Ronaldo', 'Dwight Howard',
'Justin Verlander', 'LeBron James', 'Lionel Messi', 'Phil Mickelson',
'Rafael Nadal', 'Roger Federer', 'Tiger Woods'],
dtype='object', name='Nombre')
Ahora vamos a interpolar los valores de forma lineal, y rellenaremos los valores NaN restantes con el método backfilling. El método bfill reemplaza los valores nulos con los valores de la siguiente fila.
in[12]: racing_bar_completa = racing_bar_data.interpolate(method="linear").fillna(method="bfill")
Después, convertimos los datos en una suma acumulativa de los ingresos de cada atleta a lo largo de varios años.
in[13]: racing_bar_completa = racing_bar_completa.cumsum()
racing_bar_completa.head()
out[13]: Nombre A.J. Burnett A.J. Green Aaron Donald Aaron Rodgers Adam Wainwright
Año
2012-01-01 16.6 33.3 41.4 49.00 19.8
2013-01-01 33.2 66.6 82.8 98.00 39.6
2014-01-01 49.8 99.9 124.2 120.00 59.4
2015-01-01 66.4 133.2 165.6 139.10 79.2
2016-01-01 83.0 166.5 207.0 175.75 99.0
A continuación, hacemos un muestreo semanal del conjunto de datos con una interpolación lineal para tener una transición suave en nuestra animación.
in[14]: racing_bar_completa = racing_bar_completa.resample("1D").interpolate(method="linear")[::7]
racing_bar_completa.head()
out[14]: Nombre A.J. Burnett A.J. Green Aaron Donald Aaron Rodgers Adam Wainwright
Año
2012-01-01 16.60 33.30 41.40 49.00 19.80
2012-01-08 16.92 33.94 42.19 49.94 20.18
2012-01-15 17.23 34.57 42.98 50.87 20.56
2012-01-22 17.55 35.21 43.78 51.81 20.94
2012-01-29 17.87 35.85 44.57 52.75 21.31
Finalmente, importamos los paquetes de Python necesarias para crear, ejecutar y guardar animaciones y sus elementos (líneas, barras, textos, etc.). El siguiente código generará una animación para los 10 atletas mejor pagados del mundo entre 2012 y 2019:
in[15]: from matplotlib.animation import FuncAnimation, PillowWriter
seleccion = racing_bar_completa.iloc[-1,:].sort_values(ascending=False)[:20].index
data = racing_bar_completa[seleccion].round()
fig,ax = plt.subplots(figsize=(9.3,7))
fig.subplots_adjust(left=0.18)
no_of_frames = data.shape[0]
#iniciamos el barplot con los valores de la primera fila
barras = sns.barplot(y=data.columns,x=data.iloc[0,:],orient="h",ax=ax)
ax.set_xlim(0,1500)
txts = [ax.text(0,i,0,va="center") for i in range(data.shape[1])]
titulo_txt = ax.text(650,-1,"Fecha: ",fontsize=12)
ax.set_xlabel("Ingresos (Millones USD)")
ax.set_ylabel(None)
def func_animacion(i):
#obtener fila
y = data.iloc[i,:]
#actualizar título de barplot
titulo_txt.set_text(f"Fecha: {str(data.index[i].date())}")
#actualizar elementos del plot
for j, b, in enumerate(barras.patches):
#actualizar medida de barra
b.set_width(y[j])
#actualizar texto de cada barra
txts[j].set_text(f"${y[j].astype(int)}M")
txts[j].set_x(y[j])
animacion = FuncAnimation(fig,func_animacion,repeat=False,frames=no_of_frames,interval=1,blit=False)
animacion.save('atletas-mejor-pagados.gif', writer='pillow', fps=120)
plt.close(fig)

Puedes descargar el cuaderno del projecto aquí