Investigación Caso: Academia de Deportistas

Contexto

El “Maestro”, convencido de su capacidad para vislumbrar estrellas deportivas, ha puesto una academia para ayudar a jóvenes deportistas a lograr su mayor desempeño. En esta academia, el Maestro se enfoca particularmente en cuatro deportes: Fútbol, Basketball, Voleibol y Rugby. Si bien ha visto que la mayoría de atletas jóvenes disfrutan practicando varios deportes, más adelante podrían preferir especializarse en uno en particular.
Al haber trabajado con atletas por muchos años, el Maestro ha ido recolectando un extenso conjunto de datos, y se pregunta ahora si sería posible sacar provecho a toda esa información para predecir el deporte más apropiado para los nuevos atletas. Él desearía poder recomendar a estos atletas el deporte en que tendrían mayor éxito si se especializaran en él.

Análisis preliminar de Datos

Atributo Tipo Descripción
Edad integer Edad del deportista
Fuerza integer En base a ejercicios, en un rango del 0 al 10. Los resultados están entre 0 y 8
Velocidad integer En base a un test, en un rango del 0 al 6
Lesiones Binomial Si sufrió una lesión grave
Visión integer En base a tests, en un rango del 0 al 4. Los resultados están entre 0 y 3
Resistencia integer En base a ejercicios, en un rango de 0 a 10. Los resultados están entre 0 y 6
Agilidad integer En base a pruebas, en un rango de 0 a 100. Los resultados están entre 13 y 80
Capacidad Decisión integer En base a simulaciones, en un rango del 0 al 100. Los resultados válidos son entre 3 y 100
Deporte Primario (var objetivo) polinomial Deporte que el atleta está mejor calificado a participar (fútbol, voleibol, rugby o basketball)

Tratamiento de Datos

  • Sabemos que el campo Capacidad Decisión tiene valores errados, los cuales debemos corregir. Al ser proporcionalmente pocos, los podemos eliminar.
  • Hay atributos cuyos dominios no están representados completamente por los datos, por lo que se puede subentrenar para datos fuera de lo que contamos.

Procedimiento en Python

Primero importamos librerías y cargamos los dataset.

import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import ConfusionMatrixDisplay, classification_report
from sklearn.model_selection import train_test_split

input_file1 = "sports_Scoring.csv"
input_file2 = "sports_Training.csv"
dfScoring = pd.read_csv(input_file1, header=0)
dfTrain = pd.read_csv(input_file2, header=0)
dfTrain.sample(n=5)
Edad Fuerza Velocidad Lesiones Vision Resistencia Agilidad CapacidadDecision DeportePrimario
184 15.8 3 1 1 3 5 23 44 Rugby
160 18.8 7 1 1 0 3 24 20 Voleibol
272 13.3 3 2 0 3 5 22 45 Voleibol
431 18.3 4 2 1 2 5 25 3 Voleibol
131 14.5 5 3 0 0 1 42 19 Futbol
dfTrain.describe()
Edad Fuerza Velocidad Lesiones Vision Resistencia Agilidad CapacidadDecision
count 493.000000 493.000000 493.000000 493.000000 493.000000 493.000000 493.000000 493.000000
mean 15.941785 3.519270 1.973631 0.638945 1.697769 3.849899 33.685598 30.172414
std 1.808235 1.464392 1.499768 0.480794 1.133352 1.330454 12.446329 21.484270
min 13.000000 0.000000 0.000000 0.000000 0.000000 0.000000 13.000000 0.000000
25% 14.300000 3.000000 1.000000 0.000000 1.000000 3.000000 23.000000 11.000000
50% 15.900000 4.000000 1.000000 1.000000 2.000000 5.000000 32.000000 29.000000
75% 17.600000 4.000000 2.000000 1.000000 3.000000 5.000000 42.000000 41.000000
max 19.000000 7.000000 6.000000 1.000000 3.000000 6.000000 80.000000 103.000000

Tratamos los datos con lo especificado antes.

dfCleanScoring = dfScoring[(dfScoring['CapacidadDecision'] >= 3) & (dfScoring['CapacidadDecision'] <= 100)]

dfCleanTrain = dfTrain[(dfTrain['CapacidadDecision'] >= 3) & (dfTrain['CapacidadDecision'] <= 100)]

dfCleanTrain.describe()
Edad Fuerza Velocidad Lesiones Vision Resistencia Agilidad CapacidadDecision
count 482.000000 482.000000 482.000000 482.000000 482.000000 482.000000 482.000000 482.000000
mean 15.954564 3.500000 1.983402 0.639004 1.692946 3.856846 33.680498 29.157676
std 1.817320 1.460854 1.505269 0.480788 1.134010 1.331782 12.523973 19.477265
min 13.000000 0.000000 0.000000 0.000000 0.000000 0.000000 13.000000 3.000000
25% 14.300000 3.000000 1.000000 0.000000 1.000000 3.000000 23.000000 11.000000
50% 15.900000 4.000000 1.000000 1.000000 2.000000 5.000000 31.500000 29.000000
75% 17.600000 4.000000 2.000000 1.000000 3.000000 5.000000 42.750000 40.000000
max 19.000000 7.000000 6.000000 1.000000 3.000000 6.000000 80.000000 100.000000

Separamos las entradas de la salida y dividimos los datos para entrenar y testear. (Sobre el set de train)

X = dfCleanTrain[['Edad','Fuerza','Velocidad','Lesiones','Vision','Resistencia','Agilidad','CapacidadDecision']].values
y = dfCleanTrain['DeportePrimario'].values

train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.3, random_state=0, shuffle=True)

Con los datos separados y definidos, entrenamos el modelo.

lda = LinearDiscriminantAnalysis()
lda = lda.fit(train_X, train_y)

Y pasamos a la predicción y vemos el desempeño.

y_pred = lda.predict(test_X)
print(classification_report(test_y, y_pred, digits=3))
ConfusionMatrixDisplay.from_predictions(test_y, y_pred)
              precision    recall  f1-score   support

  Basketball      0.600     0.176     0.273        34
      Futbol      0.462     0.652     0.541        46
       Rugby      0.375     0.545     0.444        33
    Voleibol      0.273     0.188     0.222        32

    accuracy                          0.414       145
   macro avg      0.427     0.390     0.370       145
weighted avg      0.433     0.414     0.386       145






<sklearn.metrics._plot.confusion_matrix.ConfusionMatrixDisplay at 0x2353fa68940>

Pelican

Comparación RapidMiner

Procedemos a implementar el mismo proceso en RapidMiner para ver como se comparan los modelos que construyen.
Pelican
Pelican

Predicción

Ahora que tenemos el modelo entrenado y validado, podemos pasar a predecir para el set de scoring.
Para esto re-entrenamos el set con todos los datos de train que disponemos (tras limpieza), para asegurar el mejor performance posible.

lda2 = LinearDiscriminantAnalysis()
lda2 = lda2.fit(dfCleanTrain[['Edad','Fuerza','Velocidad','Lesiones','Vision','Resistencia','Agilidad','CapacidadDecision']].values, dfCleanTrain['DeportePrimario'].values)

scoringPred = lda.predict(dfCleanScoring)
C:\Users\gatom\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\sklearn\base.py:457: UserWarning: X has feature names, but LinearDiscriminantAnalysis was fitted without feature names
  warnings.warn(
#Vemos los primeros 15 resultados de ejemplo
print(scoringPred[:16])

print("Predicciones Futbol:",np.count_nonzero(scoringPred == 'Futbol'))
print("Predicciones Voleibol:",np.count_nonzero(scoringPred == 'Voleibol'))
print("Predicciones Basketball:",np.count_nonzero(scoringPred == 'Basketball'))
print("Predicciones Rugby:",np.count_nonzero(scoringPred == 'Rugby'))
['Voleibol' 'Rugby' 'Futbol' 'Rugby' 'Rugby' 'Rugby' 'Futbol' 'Rugby'
 'Futbol' 'Voleibol' 'Futbol' 'Rugby' 'Futbol' 'Futbol' 'Basketball'
 'Voleibol']
Predicciones Futbol: 772
Predicciones Voleibol: 366
Predicciones Basketball: 139
Predicciones Rugby: 490

En RapidMiner resulta:
Pelican
Pelican
Pelican

Conclusiones

  • A pesar de no tener resultados excelentes, la precisión obtenida (~40%) es sustancialmente mejor que simplemente adivinar (que tendría un 25% probabilidad de acierto)
  • En comparación a RapidMiner, SKLearn predice mejor deportes como voleibol y rugby, dándole una precisión general mayor.
  • En la aplicación de modelo, ambos dan resultados diferentes.
  • Como es esperado, el modelo de RapidMiner favorece las predicciones a fútbol, mientras que en SKLearn es más balanceado.