Biblioteca Online : ¡La Suscripción ENI por 9,90 € el primer mes!, con el código PRIMER9. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Inteligencia artificial fácil
  3. Machine Learning y los Pokémon: segunda parte
Extrait - Inteligencia artificial fácil Machine Learning y Deep Learning prácticos
Extractos del libro
Inteligencia artificial fácil Machine Learning y Deep Learning prácticos
3 opiniones
Volver a la página de compra del libro

Machine Learning y los Pokémon: segunda parte

Lo que vamos a descubrir y requisitos

En el capítulo anterior hemos formado un conjunto de observaciones que va a permitirnos iniciar el proceso de análisis y de búsqueda de soluciones a nuestro problema, como determinar el Pokémon que se ha de utilizar durante un combate con la finalidad de ganarlo.

Vamos a empezar este capítulo con algunas estadísticas, pero no tema porque son fáciles de comprender.

Requisitos necesarios para abordar este capítulo correctamente: haber leído los capítulos Los fundamentos del lenguaje Python, Estadísticas para comprender los datos, Principales algoritmos de Machine Learning y haber realizado las etapas del capítulo Machine Learning y los Pokémon: primera parte.

Algunas estadísticas

Antes de entrar de lleno en el tema, vamos a hacer algunas estadísticas en nuestro conjunto de observaciones con ayuda de la función describe() del módulo Pandas.

print(nuevoPokedex.describe()) 

El objetivo de esta función es explicar estadísticamente todas las características de nuestro conjunto de observaciones para extraer algunas características interesantes.

Vamos a tomar como ejemplo el resultado del análisis estadístico de la característica NIVEL_ATAQUE.

Módulo

Definición

Valor

Count

Cantidad de observaciones

800

Mean

Media de las observaciones

79.001250

Std

Desviación típica

32.457366

min

Valor mínimo de las observaciones

5

25 %

55

50 %

75

75 %

100

Max

Valor máximo de las observaciones

190

1. La cantidad de datos (count)

Se constata que se han completado 800 observaciones para la característica NIVEL_ATAQUE. Lo que significa que no faltan datos.

2. La media (mean)

El nivel de ataque medio de los Pokémon es 79, es decir, que por debajo de esta media se puede considerar que el Pokémon tiene un nivel débil, y por encima tiene un nivel fuerte que puede ayudarnos a ganar el combate. Así que ya tenemos una primera información interesante.

3. La desviación típica (Std para Standard Deviation)

La desviación típica es un valor estadístico que permite mostrar la distribución de los datos alrededor de la media. Cuanto más pequeño es su valor, más próximos están los datos de la media y, en el caso contrario...

¿Cuáles son los tipos de Pokémon que debe tener un domador?

Responder a nuestro problema es como ponerse en la piel de un domador de Pokémon. Para maximizar las posibilidades de ganar, el domador de los Pokémon tiene en su colección los principales Pokémon del Pokédex.

En efecto, tener los Pokémon que se encuentran más habitualmente significa que hay muchas posibilidades de que los adversarios posean los mismos. Saber que dos Pokémon del mismo tipo pueden bloquear los ataques puede servirnos para evitar perder el combate (https://pokemondb.net/type/dual).

A fin de conocer los Pokémon indispensables para cualquier domador, vamos a utilizar un gráfico donde podremos visualizar rápidamente su cantidad en función de su tipo. Este es el programa que hay que utilizar:

Hay que destacar la importación del módulo matplotlib y el uso del módulo seaborn. Los dos son necesarios para la representación gráfica de los datos.

import matplotlib.pyplot as plt  
import seaborn as sns  
  
eje_X = sns.countplot(x="TIPO_1", hue="LEGENDARIO",  
data=nuevoPokedex)  
plt.xticks(rotation= 90)  
plt.xlabel('TIPO_1')  
plt.ylabel('Total ')  
plt.title("POKEMON DE TIPO_1")  
plt.show() 
images/Ch06_02.PNG

Visualización de la cantidad...

Los tipos de Pokémon ganadores y perdedores

En nuestra opinión, es importante conocer los tipos de Pokémon ganadores. En efecto, asegurándose de tenerlos en su colección y usarlos en los combates, el domador tiene muchas posibilidades de ganar.

Para obtener esta información, se calcula la media de los porcentajes de victorias de cada Pokémon. Esta media calculada y agrupada por tipo de Pokémon luego se ordena de menor a mayor:

print(nuevoPokedex.groupby('TIPO_1').agg({"PORCENTAJE_VICTORIA": 
"mean"}).sort_values(by = "PORCENTAJE_VICTORIA")) 

En la figura podemos ver el resultado obtenido:

images/Ch06_04.PNG

Clasificación de los Pokémon según el porcentaje medio de sus victorias

Podemos deducir, pues, que los Pokémon ganadores son del tipo:

  • Siniestro

  • Eléctrico

  • Dragón

  • Volador

También podemos afirmar que los siguientes tipos de Pokémon a menudo están condenados a perder su combate:

  • Hada

  • Roca

  • Acero

  • Veneno

  • Bicho

¿Ya podemos deducir algo? Si consideramos el Pokémon protagonista de la serie, llamado Pikachu, que es de tipo eléctrico, y lo comparamos con un Pokémon Hada, podemos deducir que Pikachu tiene muchas posibilidades de ganar el combate.

Si usted juega a los Pokémon, ¿tiene la mayoría de los Pokémon del Pokédex? ¿También tiene Pokémon...

Intentamos encontrar una relación entre los datos

Una relación entre dos datos significa que tienen un fuerte vínculo entre ellos. Como por ejemplo el estado de adulto y que la edad sea de 18 años, el hecho de saber volar y tener alas…

En nuestro caso, se trata de determinar la existencia de características que tienen un fuerte vínculo con la capacidad de ganar un combate. ¿Hay que ser rápido? ¿Hay que tener un nivel elevado de ataque? Eso es lo que vamos a descubrir.

En primer lugar, tenemos que valorar la utilidad del conjunto de datos preguntándonos: «¿Esta característica puede afectar al hecho de ganar o perder un combate?».

  • El número: no, porque es diferente para cada Pokémon.

  • El nombre: no, porque es diferente para cada Pokémon.

  • El tipo_1: sí, porque acabamos de ver que determinados tipos de Pokémon son propicios para conseguir la victoria.

  • El tipo_2: no, porque no todos los Pokémon tienen segundo tipo.

  • Los puntos de vida: sí, porque cuantos más puntos de vida se tienen, hay más posibilidades de ganar.

  • Los distintos niveles (ataque, defensa, ataque especial, defensa especial): sí, porque son características propias del combate.

  • La velocidad: sí, porque también es una característica del combate.

  • Legendario: sí, porque un Pokémon legendario tendría fuerza...

Resumen de nuestras observaciones

Si resumimos las observaciones que hemos realizado, podemos decir que para conseguir la victoria durante un combate el domador de Pokémon tiene que hacer lo siguiente:

  • Poseer Pokémon de tipo planta, agua, bicho y normal para poder bloquear los ataques.

  • Poseer Pokémon de tipo siniestro, eléctrico, dragón y volador porque son los que tienen un índice de victorias superior.

  • Usar un Pokémon que tenga una gran velocidad.

  • Usar un Pokémon que tenga un buen nivel de ataque.

Verificamos nuestras hipótesis

Ahora tenemos que verificar nuestras hipótesis seleccionando algunos combates dentro del archivo combates.csv.

155,321,155  
101,583,583  
404,32,32 

NÚMERO

NOMBRE

TIPO

NIVEL

ATAQUE

VELOCIDAD

VENCEDOR

155

Mega-Aerodactyl

Roca

135

150

321

Makuhita

Combate

60

25

NÚMERO

NOMBRE

TIPO

NIVEL

ATAQUE

VELOCIDAD

VENCEDOR

101

Haunter

Fantasma

50

95

583

Zebstrica

Eléctrico

100

116

NÚMERO

NOMBRE

TIPO

NIVEL

ATAQUE

VELOCIDAD

VENCEDOR

275

Sceptile

Planta

85

120

155

Mega-Aerodactyl

Roca

135

150

NÚMERO

NOMBRE

TIPO

NIVEL

ATAQUE

VELOCIDAD

VENCEDOR

404

Gorebyss

Agua

84

52

32

Raichu

Eléctrico

90

110

A la vista de estos resultados, podemos considerar que se han verificado nuestras hipótesis.

Pasamos a la fase de aprendizaje

El problema que tenemos que resolver consiste en determinar si un Pokémon tiene muchas posibilidades de ganar durante un combate.

Como disponemos de datos de aprendizaje, entonces estamos en un caso de Machine Learning denominado «supervisado». Es decir, que la máquina va a aprender en función de lo que se le proporciona como entrada.

En este tipo de casos disponemos de dos tipos de algoritmos: los dedicados a la clasificación o los dedicados a la regresión.

La clasificación permite organizar las predicciones en grupo, mientras que la regresión permite definir un valor.

En nuestro caso tenemos que predecir el porcentaje de victoria, que es un valor, y obviamente utilizaremos los algoritmos de regresión que hemos aprendido en el capítulo Principales algoritmos de Machine Learning, y que son los siguientes: 

  • La regresión lineal.

  • Los árboles de decisiones.

  • Los bosques aleatorios.

1. Distribución de las observaciones en conjunto de aprendizaje y conjunto de pruebas

La primera etapa antes de cualquier aprendizaje es distribuir las observaciones de las que disponemos en un conjunto de aprendizaje con el que aprenderá la máquina y un conjunto de pruebas con el que la máquina evaluará lo aprendido. Para eso, vamos a utilizar el módulo Scikit-Learn, el cual le invitamos a añadir a su proyecto.

Para evitar ejecutar las distintas tareas de análisis de datos y de preparación de estos antes de cada aprendizaje, hemos guardado el Dataframe en un archivo llamado dataset.csv con el tabulador como separador (sep=’\t’).

#Guardado del Dataframe Pokedex  
dataset = nuevoPokedex  
dataset.to_csv("datas/dataset.csv", sep='\t') 

En un archivo nuevo de script de Python, primero vamos a cargar este archivo y eliminar las filas para las que faltan valores, como la fila 12 del archivo:

images/Ch06_06.PNG

Datos que faltan en el archivo dataset.csv

#Carga de dataset con tabulaciones como separador  
dataset = pnd.read_csv("datas/dataset.csv",delimitar='\t')  
  
#Eliminación de las filas donde faltan valores  
dataset = dataset.dropna(axis=0, how='any') 

A continuación, vamos a extraer las características que serán fuente de aprendizaje (datos X), es decir, las columnas:...

Fenómenos de sobreajuste (overfitting)  y de subajuste (underfitting)

Cuando buscamos una solución a un problema en Machine Learning, queremos que se pueda generalizar.

Es decir, que la solución encontrada debe ser aplicable a datos desconocidos por las soluciones utilizadas durante el aprendizaje. Para conseguirlo necesitamos que los datos utilizados durante el aprendizaje sean lo más cercanos posible a la realidad del problema que hay que resolver.

El sobreajuste (overfitting) es un fenómeno que se manifiesta por el hecho de que la solución está demasiado adaptada a los datos de aprendizaje y no se puede generalizar a datos nuevos que le son desconocidos. Así, si para un algoritmo obtenemos una precisión del 99 % sobre los datos de aprendizaje y un valor del 20 % sobre los datos de pruebas, hay muchas posibilidades de que estemos ante un sobreajuste. Por eso se recomienda medir la precisión a la vez sobre los datos de aprendizaje y los datos de validación:

predicciones = algoritmo.predict(X_VALIDACION)  
precision_aprendizaje =  
algoritmo.score(X_APRENDIZAJE,Y_APRENDIZAJE)  
precision = r2_score(Y_VALIDACION, predicciones) 

En cuanto al fenómeno del subajuste, este último se produce cuando el algoritmo no llega a encontrar una relación entre los datos de aprendizaje y, por lo tanto, no consigue hacer buenas predicciones....

Utilizar el modelo de aprendizaje en una aplicación

Disponemos de un modelo de aprendizaje capaz de predecir el porcentaje de victoria de cada Pokémon. Ahora vamos a crear una aplicación utilizando este modelo de aprendizaje con el objetivo de predecir el vencedor de un combate en el que se enfrentarán dos Pokémon elegidos en el Pokédex.

El primer paso consiste en crear un archivo nuevo de Phyton en nuestro proyecto, al que llamaremos quienSeraElVencedor.py.

En este archivo, primero vamos a importar los módulos que necesitamos.

#Módulo de lectura de archivos CSV  
import csv  
  
#Módulo de carga del modelo de aprendizaje  
from sklearn.externals import joblib 

A continuación, vamos a escribir una primera función que se encargará de buscar información sobre un Pokémon en el Pokédex a partir de su número y que será útil para nuestro modelo de predicción.

def busquedaInformacionPokemon(numPokemon,Pokedex):  
   infoPokemon = []  
   for pokemon in Pokedex:  
       if (int(pokemon[0])==numPokemon):  
           infoPokemon =  
[pokemon[0],pokemon[1],pokemon[4],pokemon[5],pokemon[6],pokemon[7], 
pokemon[8],pokemon[9],pokemon[10]]  
           break  
   return infoPokemon 

Primero se crea una lista (infoPokemon) que permite almacenar toda la información...

Fin del caso de estudio

Ahora ya estamos al final del caso de estudio dedicado a los Pokémon. La primera parte nos permitió descubrir las etapas de preparación de los datos para la resolución de un problema relacionado con Machine Learning supervisado.

En la segunda parte hemos estudiado detalladamente el análisis más fino de los datos para poder determinar los que tienen una incidencia alta (relación) sobre la resolución de nuestro problema. Una vez realizada esta etapa, hemos formulado hipótesis sobre la predicción de la victoria de un Pokémon en relación con su adversario y las hemos verificado

A continuación, hemos probado varios algoritmos de predicción relacionados con la regresión (porque buscábamos predecir un valor) para determinar el que nos permitirá obtener un modelo de predicción fiable. Después hemos utilizado este modelo en una aplicación.

Lo que hay que recordar de esta experiencia es que la preparación y el análisis de los datos es una fase, quizás la más importante de un proyecto de Machine Learning. Los datos bien preparados y de buena calidad permitirán hacer buenas predicciones.

Recuerde también los conceptos de sobreajuste y subajuste, ya que nos serán útiles en nuestras búsquedas de algoritmos que puedan responder a los problemas de Machine Learning....