Aprendeml
Aprendeml
Aprendeml
Éste es un libro de Leanpub. Leanpub anima a los autores y publicadoras con el proceso de
publicación. Lean Publishing es el acto de publicar un libro en progreso usando herramientas
sencillas y muchas iteraciones para obtener retroalimentación del lector hasta conseguir el libro
adecuado.
Nota Inicial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Version 3.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Extras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Repositorio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Tu opinión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Un Ejercicio Práctico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Predecir cuántas veces será compartido un artículo de Machine Learning. . . . . . . . . . . 28
Regresión Lineal con Python y SKLearn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Visualicemos la Recta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Predicción en regresión lineal simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Regresión Lineal Múltiple en Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Visualizar un plano en 3 Dimensiones en Python . . . . . . . . . . . . . . . . . . . . . . . . . 35
Predicción con el modelo de Mútiples Variables . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Regresión Logística . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Ejercicio de Regresión Logística en Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Regresión Logística con SKLearn: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Visualización de Datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Creamos el Modelo de Regresión Logística . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Validación de nuestro modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Reporte de Resultados del Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Clasificación de nuevos valores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Arbol de Decisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
¿Qué es un árbol de decisión? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
¿Cómo funciona un árbol de decisión? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Arbol de Decisión con Scikit-Learn paso a paso . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Predicción del “Billboard 100”: ¿Qué artista llegará al número uno del ranking? . . . . . . . 51
Obtención de los datos de entrada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Análisis Exploratorio Inicial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Balanceo de Datos: Pocos artistas llegan al número uno . . . . . . . . . . . . . . . . . . . . . 56
Preparamos los datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Mapeo de Datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Buscamos la profundidad para el árbol de decisión . . . . . . . . . . . . . . . . . . . . . . . . 65
Visualización del árbol de decisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Análisis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Predicción de Canciones al Billboard 100 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Datos desbalanceados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Problemas de clasificación con Clases desequilibradas . . . . . . . . . . . . . . . . . . . . . . 76
¿Cómo nos afectan los datos desbalanceados? . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Métricas y Confusion Matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Vamos al Ejercicio con Python! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Análisis exploratorio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Estrategias para el manejo de Datos Desbalanceados: . . . . . . . . . . . . . . . . . . . . . . . 83
Probando el Modelo sin estrategias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Estrategia: Penalización para compensar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Estrategia: Subsampling en la clase mayoritaria . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Estrategia: Oversampling de la clase minoritaria . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Estrategia: Combinamos resampling con Smote-Tomek . . . . . . . . . . . . . . . . . . . . . . 90
Estrategia: Ensamble de Modelos con Balanceo . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Resultados de las Estrategias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
K-Means . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Cómo funciona K-Means . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Casos de Uso de K-Means . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Datos de Entrada para K-Means . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
ÍNDICE GENERAL
K-Nearest-Neighbor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
¿Qué es el algoritmo k-Nearest Neighbor ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
¿Dónde se aplica k-Nearest Neighbor? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Pros y contras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
¿Cómo funciona kNN? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Un ejemplo k-Nearest Neighbor en Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
El Ejercicio: App Reviews . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Un poco de Visualización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Preparamos las entradas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Usemos k-Nearest Neighbor con Scikit Learn . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Precisión del modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Y ahora, la gráfica que queríamos ver! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
Elegir el mejor valor de k . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Clasificar ó Predecir nuevas muestras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Requerimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Conocimientos básicos de HTML y CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
Inspección Manual de la web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
Código webscraping Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
Guardar CSV y ver en Excel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
Otros ejemplos útiles de Webscaping: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
Version 3.0
En esta versión:
• Anexo I: WebScraping
• Anexo II: ML en la nube
• Anexo III: PCA
Extras
No olvides descargar los extras que iré subiendo.
Tienes a disposición el “Lego-dataset” para el ejercicio de detección de Objetos en un archivo zip de
170 MB con más de 300 imágenes y sus anotaciones.
Repositorio
El código completo y las Jupyter Notebooks las podrás ver y descargar desde mi repositorio Github²
¹https://www.aprendemachinelearning.com/
²https://github.com/jbagnato/machine-learning/
Nota Inicial 2
Tu opinión
Todos los comentarios para mejorar el libro son bienvenidos, por lo que eres libre de enviarme
sugerencias, correcciones ó lo que sea por las vías que ofrece LeanPub³ ó por Twitter en @jbagnato⁴
ó por el formulario de contacto del blog⁵
³https://leanpub.com/aprendeml/email_author/new
⁴https://twitter.com/jbagnato
⁵https://www.aprendemachinelearning.com/contacto/
¿Qué es el Machine Learning?
Veamos algunas definiciones existentes sobre Machine Learning para intentar dar comprensión a
esta revolucionaria materia.
A computer program is said to learn from experience E with respect to some class of tasks
T and performance measure P, if its performance at tasks in T, as measured by P, improves
with experience E.
La experiencia E hace referencia a grandes volúmenes de datos recolectados (muchas veces el Big
Data) para la toma de decisiones T y la forma de medir su desempeño P para comprobar que mejoran
con la adquisición de más experiencia.
Diagrama de Venn
Drew Conway creó un simpático diagrama de Venn en el que inerrelaciona diversos campos. Aquí
copio su versión al Español:
¿Qué es el Machine Learning? 4
Diagrama de Venn
En esta aproximación al ML, podemos ver que es una intersección entre conocimientos de Matemá-
ticas y Estadística con Habilidades de Hackeo del programador.
Los algoritmos de ML intentan utilizar menos recursos para «entrenar» grandes volúmenes de
datos e ir aprendiendo por sí mismos. Podemos dividir el ML en 2 grandes categorías: Aprendizaje
Supervisado o Aprendizaje No Supervisado.
Entre los Algoritmos más utilizados en Inteligencia Artificial encontramos:
• Arboles de Decisión
• Regresión Lineal
• Regresión Logística
• k Nearest Neighbor
• PCA / Principal Component Analysis
• SVM
• Gaussian Naive Bayes
• K-Means
• Redes Neuronales Artificiales
• Aprendizaje Profundo ó Deep Learning
Resumen
El Machine Learning es una nueva herramienta clave que posibilitará el desarrollo de un futuro
mejor para la humanidad brindando inteligencia a robots, coches y hogares. Las Smart Cities, el
IOT (Internet of things) ya se están volviendo una realidad y también las aplicaciones de Machine
Learning en Asistentes como Siri, las recomendaciones de Netflix o Sistemas de Navegación en
Drones. Para los ingenieros o informáticos es una disciplina fundamental para ayudar a crear y
transitar este nuevo futuro.
Instalar el Ambiente de Desarrollo
Python
Para programar tu propia Máquina de Inteligencia Artificial necesitarás tener listo tu ambiente de
desarrollo local, en tu computadora de escritorio o portatil. En este capitulo explicaremos una manera
sencilla de obtener Python y las librerías necesarias para programar como un Científico de Datos y
poder utilizar los algoritmos más conocidos de Machine Learning.
Agenda
Nuestra agenda de hoy incluye:
1. Descargar Anaconda
2. Instalar Anaconda
3. Iniciar y Actualizar Anaconda
4. Actualizar paquete scikit-learn
5. Instalar Librerías para Deep Learning
Comencemos!
1. Descargar Anaconda
Veamos como descargar Anaconda a nuestro disco y obtener esta suite científica de Python
Instalar el Ambiente de Desarrollo Python 7
Con esto guardaremos en nuestro disco duro unos 460MB (según sistema operativo) y obtendremos
un archivo con el nombre similar a Anaconda3-5.1.10-MacOSX-x86_64.pkg
2. Instalar Anaconda
En este paso instalaremos la app en nuestro sistema. (Deberá tener permisos de Administrador si
instala para todos los usuarios).
Ejecutamos el archivo que descargamos haciendo doble click.
Se abrirá un Típico Wizard de instalación.
Seguiremos los pasos, podemos seleccionar instalación sólo para nuestro usuario, seleccionar la ruta
en disco donde instalaremos y listo.
Al instalarse el tamaño total podrá superar 1Gb en disco.
Anaconda viene con una suite de herramientas gráficas llamada Anaconda Navigator. Iniciemos la
aplicación y veremos una pantalla como esta:
1 $ conda -V
y obtenemos la versión
1 conda 4.3.30
luego tipeamos
1 $ python -V
Para confirmar que todo funciona bien, crearemos un archivo de texto para escribir un breve script
de python. Nombra al archivo versiones.py y su contenido será:
1 # scipy
2 import scipy
3 print('scipy: %s' % scipy.__version__)
4 # numpy
5 import numpy
6 print('numpy: %s' % numpy.__version__)
7 # matplotlib
8 import matplotlib
9 print('matplotlib: %s' % matplotlib.__version__)
10 # pandas
11 import pandas
12 print('pandas: %s' % pandas.__version__)
13 # statsmodels
14 import statsmodels
15 print('statsmodels: %s' % statsmodels.__version__)
16 # scikit-learn
17 import sklearn
18 print('sklearn: %s' % sklearn.__version__)
1 $ python versiones.py
1 scipy: 0.18.1
2 numpy: 1.12.1
3 matplotlib: 1.5.3
4 pandas: 0.19.2
5 statsmodels: 0.8.0
6 sklearn: 0.18.1
1 $ python versiones.py
Y crearemos un nuevo script para probar que se instalaron correctamente. Le llamaremos versiones_-
deep.py y tendrá las siguientes lineas:
1 # tensorflow
2 import tensorflow
3 print('tensorflow: %s' % tensorflow.__version__)
4 # keras
5 import keras
6 print('keras: %s' % keras.__version__)
1 $ python versiones_deep.py
1 tensorflow: 1.0.1
2 Using TensorFlow backend.
3 keras: 2.0.2
Resumen
Para nuestra carrera en Machine Learning, el enfrentamiento con Big Data y el perfeccionamiento
como Data Scientist necesitamos un buen entorno en el que programar y cacharrear -lease, probar
cosas y divertirse-. Para ello contamos con la suite de herramientas gratuitas de Anaconda que nos
ofrece un entorno amable y sencillo en el que crear nuestras máquinas en código Python.
Instalar el Ambiente de Desarrollo Python 12
¿Qué es el EDA?
EDA es la sigla en inglés para Exploratory Data Analysis y consiste en una de las primeras tareas que
tiene que desempeñar el Científico de Datos. Es cuando revisamos por primera vez los datos que nos
llegan, por ejemplo un archivo CSV y deberemos intentar comprender “¿de qué se trata?”, vislumbrar
posibles patrones y reconocer distribuciones estadísticas que puedan ser útiles en el futuro.
Lo ideal es que tengamos un objetivo que nos hayan “adjuntado” con los datos, que indique lo
que se quiere conseguir a partir de ellos. Por ejemplo, nos pasan un excel y nos dicen “Queremos
predecir ventas¹¹ a 30 días”, ó “Clasificar¹² casos malignos/benignos de una enfermedad”, “Queremos
identificar audiencias¹³ que van a realizar re-compra de un producto”, “queremos hacer pronóstico¹⁴
de fidelización de clientes/abandonos”, “Quiero detectar casos de fraude¹⁵ en mi sistema en tiempo
real”.
EDA deconstruido
Al llegar un archivo, lo primero que deberíamos hacer es intentar responder:
Puede ocurrir que tengamos set de datos incompletos y debamos pedir a nuestro cliente/proveedor
ó interesado que nos brinde mayor información de los campos, que aporte más conocimiento ó que
corrija campos.
También puede que nos pasen múltiples fuentes de datos, por ejemplo un csv, un excel y el acceso a
una base de datos. Entonces tendremos que hacer un paso previo de unificación de datos.
• Esto que quiere hacer el cliente CON ESTOS DATOS es una locura imposible!
• No tenemos datos suficientes ó son de muy mala calidad, pedir más al cliente.
¹⁶https://www.aprendemachinelearning.com/procesamiento-del-lenguaje-natural-nlp/
¹⁷https://www.aprendemachinelearning.com/pronostico-de-series-temporales-con-redes-neuronales-en-python/
¹⁸https://www.aprendemachinelearning.com/como-funcionan-las-convolutional-neural-networks-vision-por-ordenador/
¹⁹https://www.aprendemachinelearning.com/deteccion-de-outliers-en-python-anomalia/
²⁰https://www.aprendemachinelearning.com/clasificacion-con-datos-desbalanceados/
²¹https://www.aprendemachinelearning.com/sets-de-entrenamiento-test-validacion-cruzada/
Análisis Exploratorio de Datos 15
A estas alturas podemos saber si nos están pidiendo algo viable ó si necesitamos más datos para
comenzar.
Repito: el EDA debe tomar horas, ó puede que un día, pero la idea es poder sacar algunas conclusiones
rápidas para contestar al cliente si podemos seguir o no con su propuesta.
Luego del EDA, suponiendo que seguimos adelante podemos tomarnos más tiempo y analizar en
mayor detalle los datos y avanzar a nuevas etapas para aplicar modelos de Machine Learning²³.
1 import pandas as pd
2 import numpy as np
3 import matplotlib.pyplot as plt
4 import statsmodels.api as sm
5
6 url = 'https://raw.githubusercontent.com/lorey/list-of-countries/master/csv/countrie\
7 s.csv'
8 df = pd.read_csv(url, sep=";")
9 print(df.head(5))
1 df.info()
En esta salida vemos las columnas, el total de filas y la cantidad de filas sin nulos. También los tipos
de datos.
descripción estadística de los datos numéricos
1 df.describe()
Análisis Exploratorio de Datos 18
Pandas filtra las features numéricas y calcula datos estadísticos que pueden ser útiles: cantidad,
media, desvío estándar, valores máximo y mínimo.
Verifiquemos si hay correlación entre los datos
1 corr = df.set_index('alpha_3').corr()
2 sm.graphics.plot_corr(corr, xnames=list(corr.columns))
3 plt.show()
Análisis Exploratorio de Datos 19
En este caso vemos baja correlación entre las variables. Dependiendo del algoritmo que utilicemos
podría ser una buena decisión eliminar features que tuvieran alta correlación
Cargamos un segundo archivo csv para ahondar en el crecimiento de la población en los últimos
años, filtramos a España y visualizamos
1 url = 'https://raw.githubusercontent.com/DrueStaples/Population_Growth/master/countr\
2 ies.csv'
3 df_pop = pd.read_csv(url)
4 print(df_pop.head(5))
5 df_pop_es = df_pop[df_pop["country"] == 'Spain' ]
6 print(df_pop_es.head())
7 df_pop_es.drop(['country'],axis=1)['population'].plot(kind='bar')
Análisis Exploratorio de Datos 20
Gráfica comparativa de crecimiento poblacional entre España y Argentina entre los años 1952 al
2007
Ahora filtremos todos los paises hispano-hablantes
Visualizamos…
1 df_espanol.set_index('alpha_3')[['population','area']].plot(kind='bar',rot=65,figsiz\
2 e=(20,10))
Vamos a hacer detección de Outliers²⁴, (con fines educativos) en este caso definimos como limite
superior (e inferior) la media más (menos) “2 veces la desviación estándar” que muchas veces es
tomada como máximos de tolerancia.
²⁴https://www.aprendemachinelearning.com/deteccion-de-outliers-en-python-anomalia/
Análisis Exploratorio de Datos 23
1 anomalies = []
2
3 # Funcion ejemplo para detección de outliers
4 def find_anomalies(data):
5 # Set upper and lower limit to 2 standard deviation
6 data_std = data.std()
7 data_mean = data.mean()
8 anomaly_cut_off = data_std * 2
9 lower_limit = data_mean - anomaly_cut_off
10 upper_limit = data_mean + anomaly_cut_off
11 print(lower_limit.iloc[0])
12 print(upper_limit.iloc[0])
13
14 # Generate outliers
15 for index, row in data.iterrows():
16 outlier = row # # obtener primer columna
17 # print(outlier)
18 if (outlier.iloc[0] > upper_limit.iloc[0]) or (outlier.iloc[0] < lower_limit\
19 .iloc[0]):
20 anomalies.append(index)
21 return anomalies
22
23 find_anomalies(df_espanol.set_index('alpha_3')[['population']])
Detectamos como outliers a Brasil y a USA. Los eliminamos y graficamos ordenado por población
de menor a mayor.
• Si hay datos categóricos, agruparlos, contabilizarlos y ver su relación con las clases de salida
• gráficas de distribución en el tiempo, por ejemplo si tuviéramos ventas, para tener una primera
impresión sobre su estacionalidad.
• Rankings del tipo “10 productos más vendidos” ó “10 ítems con más referencias por usuario”.
• Calcular importancia de Features y descartar las menos útiles.
Resumen
Vimos un repaso sobre qué es y cómo lograr hacer un Análisis Exploratorio de Datos en pocos
minutos. Su importancia es sobre todo la de darnos un vistazo sobre la calidad de datos que tenemos
y hasta puede determinar la continuidad o no de un proyecto.
Análisis Exploratorio de Datos 25
Siempre dependerá de los datos que tengamos, en cantidad y calidad y por supuesto nunca debe-
remos dejar de tener en vista EL OBJETIVO, el propósito que buscamos lograr. Siempre debemos
apuntar a lograr eso con nuestras acciones.
Como resultado del EDA si determinamos continuar, pasaremos a una etapa en la que ya preproce-
saremos los datos pensando en la entrada a un modelo (ó modelos!) de Machine Learning.
Recursos
Puedes descargar la notebook relacionada con este artículo desde aquí:
Más Recursos
Estos son otros artículos relacionados que pueden ser de tu interés:
²⁵https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_EDA.ipynb
²⁶https://github.com/jbagnato/machine-learning/blob/master/Manipulacion_datos_pandas.ipynb
²⁷https://www.hackerearth.com/practice/machine-learning/machine-learning-projects/python-project/tutorial/
²⁸https://machinelearningmastery.com/machine-learning-in-python-step-by-step/
²⁹https://www.activestate.com/blog/exploratory-data-analysis-using-python/?utm_campaign=exploratory-data-analysis-blog&utm_
medium=referral&utm_source=kdnuggets&utm_content=2019-08-07-kdnuggets-article
³⁰https://www.datacamp.com/community/tutorials/exploratory-data-analysis-python
Regresión Lineal con Python
¿Qué es la regresión lineal?
La regresión lineal³¹ es un algoritmo³² de aprendizaje supervisado³³ que se utiliza en Machine
Learning y en estadística. En su versión más sencilla, lo que haremos es “dibujar una recta” que nos
indicará la tendencia de un conjunto de datos continuos (si fueran discretos, utilizaríamos Regresión
Logística³⁴). En estadísticas, regresión lineal es una aproximación para modelar la relación entre una
variable escalar dependiente “y” y una o mas variables explicativas nombradas con “X”.
Recordemos rápidamente la fórmula de la recta:
Y = mX + b
Aqui vemos un ejemplo donde vemos datos recabados sobre los precios de las pizzas en Dinamarca
(los puntos en rojo) y la linea negra es la tendencia. Esa es la línea de regresión que buscamos que
el algoritmo aprenda y calcule sólo.
³¹https://es.wikipedia.org/wiki/Regresi%C3%B3n_lineal
³²http://www.aprendemachinelearning.com/principales-algoritmos-usados-en-machine-learning/
³³http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/#supervisado
³⁴http://www.aprendemachinelearning.com/regresion-logistica-con-python-paso-a-paso/
Regresión Lineal con Python 27
Un Ejercicio Práctico
En este ejemplo cargaremos un archivo .csv de entrada³⁸ obtenido por webscraping³⁹ que contiene
diversas URLs a artículos sobre Machine Learning de algunos sitios muy importantes como Tech-
crunch⁴⁰ o KDnuggets⁴¹ y como características de entrada -las columnas- tendremos:
1 # Imports necesarios
2 import numpy as np
3 import pandas as pd
4 import seaborn as sb
5 import matplotlib.pyplot as plt
6 %matplotlib inline
7 from mpl_toolkits.mplot3d import Axes3D
8 from matplotlib import cm
9 plt.rcParams['figure.figsize'] = (16, 9)
10 plt.style.use('ggplot')
11 from sklearn import linear_model
12 from sklearn.metrics import mean_squared_error, r2_score
⁴³http://data-speaks.luca-d3.com/2018/03/python-para-todos-2-jupyternotebook.html
⁴⁴https://www.anaconda.com/download/
⁴⁵http://www.aprendemachinelearning.com/articulos_ml/
⁴⁶https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_Regresion_Lineal.ipynb
Regresión Lineal con Python 29
⁴⁷
Se ven algunos campos con valores NaN (nulos) por ejemplo algunas urls o en comentarios. Veamos
algunas estadísticas básicas de nuestros datos de entrada:
⁴⁸
Aqui vemos que la media de palabras en los artículos es de 1808. El artículo más corto tiene 250
palabras y el más extenso 8401. Intentaremos ver con nuestra relación lineal, si hay una correlación
entre la cantidad de palabras del texto y la cantidad de Shares obtenidos. Hacemos una visualización
en general de los datos de entrada:
⁴⁹
En estas gráficas vemos entre qué valores se concentran la mayoría de registros. Vamos a filtrar los
datos de cantidad de palabras para quedarnos con los registros con menos de 3500 palabras y también
con los que tengan Cantidad de compartidos menos a 80.000. Lo gratificaremos pintando en azul los
puntos con menos de 1808 palabras (la media) y en naranja los que tengan más.
1 # Vamos a RECORTAR los datos en la zona donde se concentran más los puntos
2 # esto es en el eje X: entre 0 y 3.500
3 # y en el eje Y: entre 0 y 80.000
4 filtered_data = data[(data['Word count'] <= 3500) & (data['# Shares'] <= 80000)]
5
6 colores=['orange','blue']
7 tamanios=[30,60]
8
9 f1 = filtered_data['Word count'].values
10 f2 = filtered_data['# Shares'].values
11
12 # Vamos a pintar en colores los puntos por debajo y por encima de la media de Cantid\
13 ad de Palabras
14 asignar=[]
15 for index, row in filtered_data.iterrows():
16 if(row['Word count']>1808):
17 asignar.append(colores[0])
18 else:
⁴⁹http://www.aprendemachinelearning.com/wp-content/uploads/2018/05/reg_lin_visualiza_entradas.png
Regresión Lineal con Python 31
19 asignar.append(colores[1])
20
21 plt.scatter(f1, f2, c=asignar, s=tamanios[0])
22 plt.show()
⁵⁰
11
12 # Hacemos las predicciones que en definitiva una línea (en este caso, al ser 2D)
13 y_pred = regr.predict(X_train)
14
15 # Veamos los coeficienetes obtenidos, En nuestro caso, serán la Tangente
16 print('Coefficients: \n', regr.coef_)
17 # Este es el valor donde corta el eje Y (en X=0)
18 print('Independent term: \n', regr.intercept_)
19 # Error Cuadrado Medio
20 print("Mean squared error: %.2f" % mean_squared_error(y_train, y_pred))
21 # Puntaje de Varianza. El mejor puntaje es un 1.0
22 print('Variance score: %.2f' % r2_score(y_train, y_pred))
1 Coefficients: [5.69765366]
2 Independent term: 11200.303223074163
3 Mean squared error: 372888728.34
4 Variance score: 0.06
Visualicemos la Recta
Veamos la recta que obtuvimos:
⁵¹
1 #Vamos a comprobar:
2 # Quiero predecir cuántos "Shares" voy a obtener por un artículo con 2.000 palabras,
3 # según nuestro modelo, hacemos:
4 y_Dosmil = regr.predict([[2000]])
5 print(int(y_Dosmil))
Nos devuelve una predicción de 22595 “Shares” para un artículo de 2000 palabras.
⁵¹http://www.aprendemachinelearning.com/wp-content/uploads/2018/05/reg_lineal_recta_1_variable.png
Regresión Lineal con Python 34
Y = b + m1 X1 + m2 X2 + … + m(n) X(n)
y deja de ser una recta) En nuestro caso, utilizaremos 2 “variables predictivas” para poder
graficar en 3D, pero recordar que para mejores predicciones podemos utilizar más de 2 entradas y
prescindir del grafico. Nuestra primer variable seguirá siendo la cantidad de palabras y la segunda
variable será la suma de 3 columnas de entrada: la cantidad de enlaces, comentarios y cantidad de
imágenes. Vamos a programar!
Nota: hubiera sido mejor aplicar PCA para reducción de dimensiones⁵², manteniendo la
información más importante de todas
Ya tenemos nuestras 2 variables de entrada en XY_train y nuestra variable de salida pasa de ser
“Y” a ser el eje “Z”. Creamos un nuevo objeto de Regresión lineal con SKLearn pero esta vez tendrá
las dos dimensiones que entrenar: las que contiene XY_train. Al igual que antes, imprimimos los
coeficientes y puntajes obtenidos:
⁵²http://www.aprendemachinelearning.com/comprende-principal-component-analysis/
Regresión Lineal con Python 35
Como vemos, obtenemos 2 coeficientes (cada uno correspondiente a nuestras 2 variables predictivas),
pues ahora lo que graficamos no será una linea si no, un plano en 3 Dimensiones. El error obtenido
sigue siendo grande, aunque algo mejor que el anterior y el puntaje de Varianza mejora casi el doble
del anterior (aunque sigue siendo muy malo, muy lejos del 1).
1 fig = plt.figure()
2 ax = Axes3D(fig)
3
4 # Creamos una malla, sobre la cual graficaremos el plano
5 xx, yy = np.meshgrid(np.linspace(0, 3500, num=10), np.linspace(0, 60, num=10))
6
7 # calculamos los valores del plano para los puntos x e y
8 nuevoX = (regr2.coef_[0] * xx)
9 nuevoY = (regr2.coef_[1] * yy)
10
11 # calculamos los correspondientes valores para z. Debemos sumar el punto de intercep\
12 ción
13 z = (nuevoX + nuevoY + regr2.intercept_)
14
15 # Graficamos el plano
16 ax.plot_surface(xx, yy, z, alpha=0.2, cmap='hot')
17
18 # Graficamos en azul los puntos en 3D
19 ax.scatter(XY_train[:, 0], XY_train[:, 1], z_train, c='blue',s=30)
20
21 # Graficamos en rojo, los puntos que
22 ax.scatter(XY_train[:, 0], XY_train[:, 1], z_pred, c='red',s=40)
23
24 # con esto situamos la "camara" con la que visualizamos
25 ax.view_init(elev=30., azim=65)
26
27 ax.set_xlabel('Cantidad de Palabras')
28 ax.set_ylabel('Cantidad de Enlaces,Comentarios e Imagenes')
29 ax.set_zlabel('Compartido en Redes')
30 ax.set_title('Regresión Lineal con Múltiples Variables')
Regresión Lineal con Python 37
⁵³
Podemos rotar el gráfico para apreciar el plano desde diversos ángulos modificando el valor del
parámetro azim en view_init con números de 0 a 360.
Esta predicción nos da 20518 y probablemente sea un poco mejor que nuestra predicción anterior
con 1 variables.
Resumen
Hemos visto cómo utilizar SKLearn en Python para crear modelos de Regresión Lineal con 1 o
múltiples variables. En nuestro ejercicio no tuvimos una gran confianza en las predicciónes. Por
⁵³http://www.aprendemachinelearning.com/wp-content/uploads/2018/05/regresion_lineal_3d_plano.png
Regresión Lineal con Python 38
ejemplo en nuestro primer modelo, con 2000 palabras nos predice que podemos tener 22595 pero el
margen de error haciendo raíz del error cuartico medio es más menos 19310. Es decir que escribiendo
un artículo de 2000 palabras lo mismo tenemos 3285 Shares que 41905. En este caso usamos este
modelo para aprender a usarlo y habrá que ver en otros casos en los que sí nos brinde predicciones
acertadas. Para mejorar nuestro modelo, deberíamos utilizar más dimensiones y encontrar datos de
entrada mejores.
Atención: también es posible, que no exista ninguna relación fuerte entre nuestras variables de
entrada y el éxito en Shares del artículo… Esto fue un experimento!
Recursos y enlaces
• Descarga la Jupyter Notebook⁵⁴ y el archivo de entrada csv⁵⁵
• ó puedes visualizar online⁵⁶
• o ver y descargar desde mi cuenta github⁵⁷
⁵⁴http://www.aprendemachinelearning.com/ejercicio_regresion_lineal/
⁵⁵http://www.aprendemachinelearning.com/articulos_ml/
⁵⁶https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_Regresion_Lineal.ipynb
⁵⁷https://github.com/jbagnato/machine-learning
⁵⁸https://aktechthoughts.wordpress.com/2018/03/26/introduction-to-linear-regression-using-python/
⁵⁹https://dzone.com/articles/linear-regression-using-python-scikit-learn
⁶⁰https://towardsdatascience.com/linear-regression-detailed-view-ea73175f6e86
⁶¹http://lineardata.net/how-do-you-solve-a-linear-regression-machine-learning-problem-in-python/
⁶²http://ozzieliu.com/2016/02/09/gradient-descent-tutorial/
Regresión Logística
Introducción
Utilizaremos algoritmos de Machine Learning en Python para resolver un problema de Regresión
Logística⁶³. A partir de un conjunto de datos de entrada (características), nuestra salida será discreta
(y no continua) por eso utilizamos Regresión Logística (y no Regresión Lineal⁶⁴). La Regresión
Logística es un Algoritmo Supervisado⁶⁵ y se utiliza para clasificación⁶⁶.
Vamos a clasificar problemas con dos posibles estados “SI/NO”: binario o un número finito de
“etiquetas” o “clases”: múltiple.
Algunos Ejemplos de Regresión Logística son:
Requerimientos técnicos
Para ejecutar el código necesitas tener instalado Python 3.6+ y varios paquetes usados comúnmente
en Data Science, en este caso scikit-learn, pandas, seaborn y numpy.
Para este ejemplo he creado un block de notas Jupyter donde se muestra paso a paso el ejercicio. Se
puede descargar desde aqui⁶⁹ o se puede seguir online desde el Jupyter Notebook Viewer⁷⁰.
1 import pandas as pd
2 import numpy as np
3 from sklearn import linear_model
4 from sklearn import model_selection
5 from sklearn.metrics import classification_report
6 from sklearn.metrics import confusion_matrix
7 from sklearn.metrics import accuracy_score
8 import matplotlib.pyplot as plt
9 import seaborn as sb
10 %matplotlib inline
Leemos el archivo csv (por sencillez, se considera que estará en el mismo directorio que el archivo
de notebook .ipynb) y lo asignamos mediante Pandas a la variable dataframe. Mediante el método
dataframe.head() vemos en pantalla los 5 primeros registros.
⁶⁸http://www.aprendemachinelearning.com/que-es-overfitting-y-underfitting-y-como-solucionarlo/
⁶⁹http://www.aprendemachinelearning.com/wp-content/uploads/2017/11/Regresion_logistica.ipynb
⁷⁰http://nbviewer.jupyter.org/github/jbagnato/machine-learning/blob/master/Regresion_logistica.ipynb
Regresión Logística 41
1 dataframe = pd.read_csv(r"usuarios_win_mac_lin.csv")
2 dataframe.head()
A continuación llamamos al método dataframe.describe() que nos dará algo de información estadís-
tica básica de nuestro set de datos. La Media, el desvío estándar, valores mínimo y máximo de cada
característica.
1 dataframe.describe()
Regresión Logística 42
Luego analizaremos cuantos resultados tenemos de cada tipo usando la función groupby y vemos
que tenemos 86 usuarios “Clase 0”, es decir Windows, 40 usuarios Mac y 44 de Linux.
1 print(dataframe.groupby('clase').size())
Visualización de Datos
Antes de empezar a procesar el conjunto de datos, vamos a hacer unas visualizaciones que muchas
veces nos pueden ayudar a comprender mejor las características de la información con la que
trabajamos y su correlación. Primero visualizamos en formato de historial los cuatro Features de
entrada con nombres “duración”, “páginas”,”acciones” y “valor” podemos ver gráficamente entre qué
valores se comprenden sus mínimos y máximos y en qué intervalos concentran la mayor densidad
de registros.
1 dataframe.drop(['clase'],1).hist()
2 plt.show()
Regresión Logística 43
Y también podemos interrelacionar las entradas de a pares, para ver como se concentran linealmente
las salidas de usuarios por colores: Sistema Operativo Windows en azul, Macintosh en verde y Linux
en rojo.
1 X = np.array(dataframe.drop(['clase'],1))
2 y = np.array(dataframe['clase'])
3 X.shape
(170, 4) Y creamos nuestro modelo y hacemos que se ajuste (fit) a nuestro conjunto de entradas X y
salidas ‘y’.
1 model = linear_model.LogisticRegression()
2 model.fit(X,y)
Una vez compilado nuestro modelo, le hacemos clasificar todo nuestro conjunto de entradas X
utilizando el método “predict(X)” y revisamos algunas de sus salidas y vemos que coincide con
las salidas reales de nuestro archivo csv.
1 predictions = model.predict(X)
2 print(predictions)[0:5]
1 [2 2 2 2 2]
Y confirmamos cuan bueno fue nuestro modelo utilizando model.score() que nos devuelve la preci-
sión media de las predicciones, en nuestro caso del 77%.
1 model.score(X,y)
1 0.77647058823529413
⁷¹http://www.aprendemachinelearning.com/que-es-overfitting-y-underfitting-y-como-solucionarlo/
Regresión Logística 46
1 validation_size = 0.20
2 seed = 7
3 X_train, X_validation, Y_train, Y_validation = model_selection.train_test_split(X, y\
4 , test_size=validation_size, random_state=seed)
Volvemos a compilar nuestro modelo de Regresión Logística pero esta vez sólo con 80% de los datos
de entrada y calculamos el nuevo scoring que ahora nos da 74%.
1 name='Logistic Regression'
2 kfold = model_selection.KFold(n_splits=10, random_state=seed)
3 cv_results = model_selection.cross_val_score(model, X_train, Y_train, cv=kfold, scor\
4 ing='accuracy')
5 msg = "%s: %f (%f)" % (name, cv_results.mean(), cv_results.std())
6 print(msg)
Y ahora hacemos las predicciones -en realidad clasificación- utilizando nuestro “cross validation set”,
es decir del subconjunto que habíamos apartado. En este caso vemos que los aciertos fueron del 85%
pero hay que tener en cuenta que el tamaño de datos era pequeño.
1 predictions = model.predict(X_validation)
2 print(accuracy_score(Y_validation, predictions))
1 0.852941176471
Finalmente vemos en pantalla la “matriz de confusión” donde muestra cuantos resultados equivo-
cados tuvo de cada clase (los que no están en la diagonal), por ejemplo predijo 3 usuarios que eran
Mac como usuarios de Windows y predijo a 2 usuarios Linux que realmente eran de Windows.
También podemos ver el reporte de clasificación con nuestro conjunto de Validación. En nuestro
caso vemos que se utilizaron como “soporte” 18 registros windows, 6 de mac y 10 de Linux (total de
34 registros). Podemos ver la precisión con que se acertaron cada una de las clases y vemos que por
ejemplo de Macintosh tuvo 3 aciertos y 3 fallos (0.5 recall). La valoración que de aqui nos conviene
tener en cuenta es la de F1-score⁷², que tiene en cuenta la precisión y recall. El promedio de F1 es de
84% lo cual no está nada mal.
1 print(classification_report(Y_validation, predictions))
• Tiempo Duración: 10
• Paginas visitadas: 3
• Acciones al navegar: 5
• Valoración: 9
Lo probamos en nuestro modelo y vemos que lo clasifica como un usuario tipo 2, es decir, de Linux.
⁷²https://en.wikipedia.org/wiki/F1_score
Regresión Logística 48
1 array([2])
Los invito a jugar y variar estos valores para obtener usuarios de tipo Windows o Macintosh.
Resumen
Durante este artículo vimos cómo crear un modelo de Regresión Logística en Python para poder
clasificar el Sistema Operativo de usuarios a partir de sus características de navegación en un sitio
web. A partir de este ejemplo, se podrá extender a otro tipos de tareas que pueden surgir durante
nuestro trabajo en el que deberemos clasificar resultados en valores discretos. Si tuviéramos que
predecir valores continuos, deberemos aplicar Regresión Lineal⁷³.
Recuerda descargar los archivos para realizar el Ejercicio:
⁷³http://www.aprendemachinelearning.com/regresion-lineal-en-espanol-con-python/
⁷⁴http://www.aprendemachinelearning.com/wp-content/uploads/2017/11/usuarios_win_mac_lin.csv
⁷⁵http://www.aprendemachinelearning.com/wp-content/uploads/2017/11/Regresion_logistica.ipynb
⁷⁶http://nbviewer.jupyter.org/github/jbagnato/machine-learning/blob/master/Regresion_logistica.ipynb
⁷⁷https://github.com/jbagnato/machine-learning/blob/master/Regresion_logistica.ipynb
⁷⁸https://github.com/jbagnato/machine-learning/blob/master/usuarios_win_mac_lin.csv
⁷⁹https://github.com/jbagnato/machine-learning
Arbol de Decisión
En este capítulo describiremos en qué consisten y cómo funcionan los árboles de decisión utilizados
en Aprendizaje Automático⁸⁰ y nos centraremos en un divertido ejemplo en Python en el que
analizaremos a los cantantes y bandas que lograron un puesto número uno en las listas de Billboard
Hot 100⁸¹ e intentaremos predecir quién será el próximo Ed Sheeran⁸² a fuerza de Inteligencia
Artificial.
Realizaremos Gráficas que nos ayudarán a visualizar los datos de entrada y un grafo para interpretar
el árbol que crearemos con el paquete Scikit-Learn. Comencemos!
Indice Gini:
Se utiliza para atributos con valores continuos (precio de una casa). Esta función de coste mide el
“grado de impureza” de los nodos, es decir, cuán desordenados o mezclados quedan los nodos
una vez divididos. Deberemos minimizar ese GINI index.
Ganancia de información:
Se utiliza para atributos categóricos (como en hombre/mujer). Este criterio intenta estimar la
información que aporta cada atributo basado en la “teoría de la información⁸⁹”. Para medir la
aleatoriedad de incertidumbre de un valor aleatorio de una variable “X” se define la Entropia⁹⁰.
Al obtener la medida de entropía de cada atributo, podemos calcular la ganancia de información del
árbol. Deberemos maximizar esa ganancia.
⁸⁶https://en.wikipedia.org/wiki/Decision_tree_learning#Gini_impurity
⁸⁷https://en.wikipedia.org/wiki/Information_gain_in_decision_trees
⁸⁸https://es.wikipedia.org/wiki/Entrop%C3%ADa_(informaci%C3%B3n)
⁸⁹https://es.wikipedia.org/wiki/Teor%C3%ADa_de_la_informaci%C3%B3n
⁹⁰https://es.wikipedia.org/wiki/Entrop%C3%ADa_(informaci%C3%B3n)
Arbol de Decisión 51
⁹¹http://data-speaks.luca-d3.com/2018/03/python-para-todos-2-jupyternotebook.html
⁹²https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_Arbol_de_Decision.ipynb
⁹³http://www.aprendemachinelearning.com/ejemplo-web-scraping-python-ibex35-bolsa-valores/
⁹⁴http://mikekling.com/analyzing-the-billboard-hot-100/
⁹⁵https://developers.deezer.com/api
⁹⁶https://developer.gracenote.com/web-api
Arbol de Decisión 52
Si te falta alguna de ellas, recuerda que puedes instalarla con el entorno Anaconda o con la
herramienta Pip.
1 artists_billboard.shape
Esto nos devuelve (635,11) es decir que tenemos 11 columnas (features) y 635 filas de datos. Vamos
a echar un ojo a los primeros registros para tener una mejor idea del contenido:
1 artists_billboard.head()
⁹⁷
Vemos que tenemos: Titulo de la canción, artista, “mood” ó estado de ánimo de esa canción, tempo,
⁹⁷http://www.aprendemachinelearning.com/wp-content/uploads/2018/04/billboard_dataset_head.png
Arbol de Decisión 53
género, Tipo de artista, fecha en que apareció en el billboard (por ejemplo 20140628 equivale al 28
de junio de 2014), la columna TOP será nuestra etiqueta, en la que aparece 1 si llegó al número
uno de Billboard ó 0 si no lo alcanzó y el anio de Nacimiento del artista. Vemos que muchas de
las columnas contienen información categórica. La columna durationSeg contiene la duración en
segundos de la canción, siendo un valor continuo pero que nos convendrá pasar a categórico más
adelante. Vamos a realizar algunas visualizaciones para comprender mejor nuestros datos. Primero,
agrupemos registros para ver cuántos alcanzaron el número uno y cuantos no:
1 artists_billboard.groupby('top').size()
nos devuelve: top 0 494 1 141 Es decir que tenemos 494 canciones que no alcanzaron la cima y a 141
que alcanzaron el número uno. Esto quiere decir que tenemos una cantidad DESBALANCEADA⁹⁸
de etiquetas con 1 y 0. Lo tendremos en cuenta al momento de crear el árbol.
Visualizamos esta diferencia:
Nuestras etiquetas que indican 0-No llego al Top y 1-Llego al número uno Billboard están desbalan-
ceadas.
Deberemos resolver este inconveniente[/caption]
Veamos cuántos registros hay de tipo de artista, “mood”, tempo y género de las canciones:
⁹⁸http://www.aprendemachinelearning.com/clasificacion-con-datos-desbalanceados/
Arbol de Decisión 54
1 sb.factorplot('artist_type',data=artists_billboard,kind="count")
Aqui vemos que tenemos más del doble de artistas masculinos que femeninos y unos 100 registros
de canciones mixtas
1 sb.factorplot('mood',data=artists_billboard,kind="count", aspect=3)
Vemos que de 23 tipos de Mood, destacan 7 con picos altos. Además notamos que algunos estados
de ánimo son similares.
Arbol de Decisión 55
1 sb.factorplot('tempo',data=artists_billboard,hue='top',kind="count")
En esta gráfica vemos que hay 3 tipos de Tempo: Medium, Slow y Fast. Evidentemente predominan
los tiempos Medium y también es donde encontramos más canciones que hayan alcanzado el Top 1
(en azul)
1 sb.factorplot('genre',data=artists_billboard,kind="count", aspect=3)
1 sb.factorplot('anioNacimiento',data=artists_billboard,kind="count", aspect=3)
Aqui notamos algo raro: en el año “cero” tenemos cerca de 140 registros…
Como se ve en la gráfica tenemos cerca de 140 canciones de las cuales desconocemos el año de
nacimiento del artista. El resto de años parecen concentrarse entre 1979 y 1994 (a ojo). Más adelante
trataremos estos registros.
⁹⁹http://www.aprendemachinelearning.com/clasificacion-con-datos-desbalanceados/
Arbol de Decisión 57
1 f1 = artists_billboard['chart_date'].values
2 f2 = artists_billboard['durationSeg'].values
3
4 colores=['orange','blue'] # si no estaban declarados previamente
5 tamanios=[60,40] # si no estaban declarados previamente
6
7 asignar=[]
8 asignar2=[]
9 for index, row in artists_billboard.iterrows():
10 asignar.append(colores[row['top']])
11 asignar2.append(tamanios[row['top']])
12
13 plt.scatter(f1, f2, c=asignar, s=asignar2)
14 plt.axis([20030101,20160101,0,600])
15 plt.show()
En nuestro conjunto de Datos, se agregaron canciones que llegaron al top (en azul) de años 2004 al
2013 para sumar a los apenas 11 que lo habían logrado en 2014-2015.
Arbol de Decisión 58
1 def edad_fix(anio):
2 if anio==0:
3 return None
4 return anio
5
6 artists_billboard['anioNacimiento']=artists_billboard.apply(lambda x: edad_fix(x['an\
7 ioNacimiento']), axis=1);
Luego vamos a calcular las edades en una nueva columna “edad_en_billboard” restando el año de
aparición (los 4 primeros caracteres de chart_date) al año de nacimiento. En las filas que estaba el
año en None, tendremos como resultado edad None.
1 def calcula_edad(anio,cuando):
2 cad = str(cuando)
3 momento = cad[:4]
4 if anio==0.0:
5 return None
6 return int(momento) - anio
7
8 artists_billboard['edad_en_billboard']=artists_billboard.apply(lambda x: calcula_eda\
9 d(x['anioNacimiento'],x['chart_date']), axis=1);
Y finalmente asignaremos edades aleatorias a los registros faltantes: para ello, obtenemos el promedio
de edad de nuestro conjunto (avg) y su desvío estándar (std) -por eso necesitábamos las edades en
None- y pedimos valores random a la función que van desde avg - std hasta avg + std. En nuestro
caso son edades de entre 21 a 37 años.
Arbol de Decisión 59
1 age_avg = artists_billboard['edad_en_billboard'].mean()
2 age_std = artists_billboard['edad_en_billboard'].std()
3 age_null_count = artists_billboard['edad_en_billboard'].isnull().sum()
4 age_null_random_list = np.random.randint(age_avg - age_std, age_avg + age_std, size=\
5 age_null_count)
6
7 conValoresNulos = np.isnan(artists_billboard['edad_en_billboard'])
8
9 artists_billboard.loc[np.isnan(artists_billboard['edad_en_billboard']), 'edad_en_bil\
10 lboard'] = age_null_random_list
11 artists_billboard['edad_en_billboard'] = artists_billboard['edad_en_billboard'].asty\
12 pe(int)
13 print("Edad Promedio: " + str(age_avg))
14 print("Desvió Std Edad: " + str(age_std))
15 print("Intervalo para asignar edad aleatoria: " + str(int(age_avg - age_std)) + " a \
16 " + str(int(age_avg + age_std)))
Si bien lo ideal es contar con la información real, y de hecho la podemos obtener buscando en
Wikipedia (o en otras webs de música), quise mostrar otra vía para poder completar datos faltantes
manteniendo los promedios de edades que teníamos en nuestro conjunto de datos. Podemos visua-
lizar los valores que agregamos (en color verde) en el siguiente gráfico:
1 f1 = artists_billboard['edad_en_billboard'].values
2 f2 = artists_billboard.index
3
4 colores = ['orange','blue','green']
5
6 asignar=[]
7 for index, row in artists_billboard.iterrows():
8 if (conValoresNulos[index]):
9 asignar.append(colores[2]) # verde
10 else:
11 asignar.append(colores[row['top']])
12
13 plt.scatter(f1, f2, c=asignar, s=30)
14 plt.axis([15,50,0,650])
15 plt.show()
Arbol de Decisión 60
Mapeo de Datos
Vamos a transformar varios de los datos de entrada en valores categóricos. Las edades, las separamos
en: menor de 21 años, entre 21 y 26, etc. las duraciones de canciones también, por ej. entre 150 y 180
segundos, etc. Para los estados de ánimo (mood) agrupé los que eran similares. El Tempo que puede
ser lento, medio o rápido queda mapeado: 0-Rapido, 1-Lento, 2-Medio (por cantidad de canciones
en cada tempo: el Medio es el que más tiene)
1 # Mood Mapping
2 artists_billboard['moodEncoded'] = artists_billboard['mood'].map( {'Energizing': 6,
3 'Empowering': 6,
4 'Cool': 5,
5 'Yearning': 4, # anhelo, deseo, ansia
6 'Excited': 5, #emocionado
7 'Defiant': 3,
8 'Sensual': 2,
9 'Gritty': 3, #coraje
10 'Sophisticated': 4,
11 'Aggressive': 4, # provocativo
12 'Fiery': 4, #caracter fuerte
13 'Urgent': 3,
14 'Rowdy': 4, #ruidoso alboroto
Arbol de Decisión 61
15 'Sentimental': 4,
16 'Easygoing': 1, # sencillo
17 'Melancholy': 4,
18 'Romantic': 2,
19 'Peaceful': 1,
20 'Brooding': 4, # melancolico
21 'Upbeat': 5, #optimista alegre
22 'Stirring': 5, #emocionante
23 'Lively': 5, #animado
24 'Other': 0,'':0} ).astype(int)
25 # Tempo Mapping
26 artists_billboard['tempoEncoded'] = artists_billboard['tempo'].map( {'Fast Tempo': 0\
27 , 'Medium Tempo': 2, 'Slow Tempo': 1, '': 0} ).astype(int)
28 # Genre Mapping
29 artists_billboard['genreEncoded'] = artists_billboard['genre'].map( {'Urban': 4,
30 'Pop': 3,
31 'Traditional': 2,
32 'Alternative & Punk': 1,
33 'Electronica': 1,
34 'Rock': 1,
35 'Soundtrack': 0,
36 'Jazz': 0,
37 'Other':0,'':0}
38 ).astype(int)
39 # artist_type Mapping
40 artists_billboard['artist_typeEncoded'] = artists_billboard['artist_type'].map( {'Fe\
41 male': 2, 'Male': 3, 'Mixed': 1, '': 0} ).astype(int)
42
43 # Mapping edad en la que llegaron al billboard
44 artists_billboard.loc[ artists_billboard['edad_en_billboard'] <= 21, 'edadEncoded'] \
45 = 0
46 artists_billboard.loc[(artists_billboard['edad_en_billboard'] > 21) & (artists_billb\
47 oard['edad_en_billboard'] <= 26), 'edadEncoded'] = 1
48 artists_billboard.loc[(artists_billboard['edad_en_billboard'] > 26) & (artists_billb\
49 oard['edad_en_billboard'] <= 30), 'edadEncoded'] = 2
50 artists_billboard.loc[(artists_billboard['edad_en_billboard'] > 30) & (artists_billb\
51 oard['edad_en_billboard'] <= 40), 'edadEncoded'] = 3
52 artists_billboard.loc[ artists_billboard['edad_en_billboard'] > 40, 'edadEncoded'] =\
53 4
54
55 # Mapping Song Duration
56 artists_billboard.loc[ artists_billboard['durationSeg'] <= 150, 'durationEncoded'] =\
57 0
Arbol de Decisión 62
Finalmente obtenemos un nuevo conjunto de datos llamado artists_encoded con el que tenemos
los atributos definitivos para crear nuestro árbol. Para ello, quitamos todas las columnas que no
necesitamos con “drop”:
1 drop_elements = ['id','title','artist','mood','tempo','genre','artist_type','chart_d\
2 ate','anioNacimiento','durationSeg','edad_en_billboard']
3 artists_encoded = artists_billboard.drop(drop_elements, axis = 1)
Aqui están bastante repartidos, pero hay mayoría en tipo 3: artistas masculinos.
Los géneros con mayoría son evidentemente los géneros 3 y 4 que corresponden con Urbano y Pop
NOTA: estos valores asignados a los parámetros fueron puestos luego de prueba y error (muchas
veces visualizando el árbol, en el siguiente paso y retrocediendo a este).
¹⁰⁰http://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html
¹⁰¹http://www.aprendemachinelearning.com/clasificacion-con-datos-desbalanceados/
Arbol de Decisión 66
Podmeos ver que en 4 niveles de splits tenemos el score más alto, con casi 65%. Ahora ya sólo nos
queda crear y visualizar nuestro árbol de 4 niveles de profundidad.
Arbol de Decisión 67
Al fin nuestro preciado árbol aparece en pantalla!. Ahora tendremos que mirar y ver si lo podemos
mejorar (por ejemplo tuneando los parámetros de entrada).
Análisis
En la gráfica vemos, un nodo raíz que hace una primer subdivisión por género y las salidas van
a izquierda por True que sea menor a 2.5, es decir los géneros 0, 1 y 2 (eran los que menos top=1
tenían) y a derecha en False van los géneros 3 y 4 que eran Pop y Urban con gran cantidad de usuarios
top Billboard. En el segundo nivel vemos que la cantidad de muestras (samples) queda repartida en
232 y 403 respectivamente. A medida que bajamos de nivel veremos que los valores de entropía se
aproximan más a 1 cuando el nodo tiene más muestras top=1 (azul) y se acercan a 0 cuando hay
mayoría de muestras Top=0 (naranja). En los diversos niveles veremos divisiones por tipo de artista
, edad, duración y mood. También vemos algunas hojas naranjas que finalizan antes de llegar al
último nivel: esto es porque alcanzan un nivel de entropía cero, o porque quedan con una cantidad
de muestras menor a nuestro mínimo permitido para hacer split (20). Veamos cuál fue la precisión
alcanzada por nuestro árbol:
Nos da un valor de 64.88%. Notamos en que casi todas las hojas finales del árbol tienen samples
mezclados sobre todo en los de salida para clasificar los top=1. Esto hace que se reduzca el score.
Pongamos a prueba nuestro algoritmo
Arbol de Decisión 69
Nos da que Havana llegará al top 1 con una probabilidad del 83%. Nada mal…
Nos da que la canción de Imagine Dragons NO llegará con una certeza del 88%. Otro acierto. Veamos
los caminos tomados por cada una de las canciones:
¹⁰²https://www.billboard.com/music/camila-cabello
¹⁰³https://www.youtube.com/watch?v=BQ0mxQXmLsk
¹⁰⁴https://www.billboard.com/music/imagine-dragons
¹⁰⁵https://www.youtube.com/watch?v=7wtfhZwyrcc
Arbol de Decisión 70
Aqui vemos los caminos tomados por Havana en Rojo, que alcanzó el número 1 y el camino por
Believer (en rosa) que no llegó.
Resumen
Pues hemos tenido un largo camino, para poder crear y generar nuestro árbol. Hemos revisado
los datos de entrada, los hemos procesado, los pasamos a valores categóricos y generamos el árbol.
Lo hemos puesto a prueba para validarlo. Obtener un score de menos de 65% en el árbol no es
un valor muy alto, pero tengamos en cuenta que nos pusimos una tarea bastante difícil de lograr:
poder predecir al número 1 del Billboard y con un tamaño de muestras tan pequeño (635 registros) y
desbalanceado¹⁰⁶. Ya quisieran las discográficas poder hacerlo :) Espero que hayan disfrutado de este
artículo y si encuentran errores, comentarios, o sugerencias para mejorarlo, siempre son bienvenidas.
Además pueden escribirme si tienen problemas en intentaré responder a la brevedad. Como siempre
los invito a suscribirse al blog para seguir creciendo como comunidad de desarrolladores que estamos
aprendiendo mediante ejemplos a crear algoritmos inteligentes.
Recursos y enlaces
• Descarga la Jupyter Notebook¹⁰⁷ y el archivo de entrada csv¹⁰⁸
• ó puedes visualizar online¹⁰⁹
• o ver y descargar desde github¹¹⁰
• Artículo Ejemplo Webscraping en Python¹¹¹
• Cómo balancear tus set de datos¹¹²
¹⁰⁶http://www.aprendemachinelearning.com/clasificacion-con-datos-desbalanceados/
¹⁰⁷http://www.aprendemachinelearning.com/wp-content/uploads/2018/04/Ejercicio_Arbol_de_Decision.ipynb
¹⁰⁸http://www.aprendemachinelearning.com/wp-content/uploads/2018/04/artists_billboard_fix3.csv
¹⁰⁹https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_Arbol_de_Decision.ipynb
¹¹⁰https://github.com/jbagnato/machine-learning
¹¹¹http://www.aprendemachinelearning.com/ejemplo-web-scraping-python-ibex35-bolsa-valores/
¹¹²http://www.aprendemachinelearning.com/clasificacion-con-datos-desbalanceados/
Arbol de Decisión 71
• introduction-to-decision-trees-titanic-dataset¹¹³
• Decision Trees in Python¹¹⁴
• Decision Trees with Scikit learn¹¹⁵
• Building decision tree algorithm¹¹⁶
¹¹³https://www.kaggle.com/dmilla/introduction-to-decision-trees-titanic-dataset/notebook
¹¹⁴http://stackabuse.com/decision-trees-in-python-with-scikit-learn/
¹¹⁵https://napitupulu-jon.appspot.com/posts/decision-tree-ud.html
¹¹⁶http://dataaspirant.com/2017/02/01/decision-tree-algorithm-python-with-scikit-learn/
Qué es overfitting y cómo
solucionarlo
Las principales causas al obtener malos resultados en Machine Learning¹¹⁷ son el overfitting o el
underfitting de los datos. Cuando entrenamos nuestro modelo intentamos “hacer encajar¹¹⁸” -fit
en inglés- los datos de entrada entre ellos y con la salida. Tal vez se pueda traducir overfitting
como “sobreajuste” y underfitting como “subajuste” y hacen referencia al fallo de nuestro modelo al
generalizar el conocimiento que pretendemos que adquieran. Lo explicaré a continuación con un
ejemplo.
exactamente con las características que aprendió (el color forzosamente debía ser marrón). Aquí se
trata de un problema de overfitting. Tanto el problema del ajuste “por debajo” como “por encima”
de los datos son malos porque no permiten que nuestra máquina generalice el conocimiento y no
nos darán buenas predicciones (o clasificación, o agrupación, etc.)
Cuando entrenamos nuestro modelo solemos parametrizar y limitar el algoritmo, por ejemplo la
cantidad de iteraciones que tendrá o un valor de “taza de aprendizaje” (learning-rate) por iteración y
muchos otros. Para lograr que nuestro modelo dé buenos resultados iremos revisando y contrastando
nuestro entrenamiento con el conjunto de Test y su taza de errores, utilizando más o menos
iteraciones, etc. hasta dar con buenas predicciones y sin tener los problemas de over-under-fitting.
• Cantidad mínima de muestras tanto para entrenar el modelo como para validarlo.
• Clases variadas y equilibradas en cantidad: En caso de aprendizaje supervisado¹¹⁹ y suponien-
do que tenemos que clasificar¹²⁰ diversas clases o ¹²¹categorías, es importante que los datos de
entrenamiento estén balanceados¹²². Supongamos que tenemos que diferenciar entre manzanas,
peras y bananas, debemos tener muchas fotos de las 3 frutas y en cantidades similares. Si
tenemos muy pocas fotos de peras, esto afectará en el aprendizaje de nuestro algoritmo para
identificar esa fruta.
• Conjunto de Test de datos. Siempre subdividir nuestro conjunto de datos y mantener una
porción del mismo “oculto” a nuestra máquina entrenada. Esto nos permitirá obtener una
valoración de aciertos/fallos real del modelo y también nos permitirá detectar fácilmente
efectos del overfitting /underfitting.
• Parameter Tunning¹²³ o Ajuste de Parámetros: deberemos experimentar sobre todo dando
más/menos “tiempo/iteraciones” al entrenamiento y su aprendizaje hasta encontrar el equili-
brio.
¹¹⁹http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/#supervisado
¹²⁰http://www.aprendemachinelearning.com/principales-algoritmos-usados-en-machine-learning/
¹²¹http://www.aprendemachinelearning.com/regresion-logistica-con-python-paso-a-paso/
¹²²http://www.aprendemachinelearning.com/clasificacion-con-datos-desbalanceados/
¹²³http://www.aprendemachinelearning.com/7-pasos-machine-learning-construir-maquina/#parameter_tuning
Qué es overfitting y cómo solucionarlo 75
• Cantidad excesiva de Dimensiones (features), con muchas variantes distintas, sin suficientes
muestras. A veces conviene eliminar o reducir la cantidad de características que utilizaremos
para entrenar el modelo. Una herramienta útil para hacerlo es PCA¹²⁴.
• Quiero notar que si nuestro modelo es una red neuronal artificial¹²⁵ -deep learning¹²⁶-, podemos
caer en overfitting si usamos capas ocultas en exceso, ya que haríamos que el modelo
memorice las posibles salidas, en vez de ser flexible y adecuar las activaciones a las entradas
nuevas.
Si el modelo entrenado con el conjunto de train tiene un 90% de aciertos y con el conjunto de test
tiene un porcentaje muy bajo, esto señala claramente un problema de overfitting. Si en el conjunto
de Test sólo se acierta un tipo de clase (por ejemplo “peras”) o el único resultado que se obtiene es
siempre el mismo valor será que se produjo un problema de underfitting.
Resumen
Siempre que creamos una máquina de aprendizaje deberemos tener en cuenta que pueden caer en
uno de estos problemas por no poder generalizar correctamente el conocimiento. Underfitting
indicará la imposibilidad de identificar o de obtener resultados correctos por carecer de suficientes
muestras de entrenamiento o un entrenamiento muy pobre. Overfitting indicará un aprendizaje
“excesivo” del conjunto de datos de entrenamiento haciendo que nuestro modelo únicamente pueda
producir unos resultados singulares y con la imposibilidad de comprender nuevos datos de entrada.
¹²⁴http://www.aprendemachinelearning.com/comprende-principal-component-analysis/
¹²⁵http://www.aprendemachinelearning.com/breve-historia-de-las-redes-neuronales-artificiales/
¹²⁶http://www.aprendemachinelearning.com/aprendizaje-profundo-una-guia-rapida/
Datos desbalanceados
Veremos qué son y cómo contrarrestar problemas con clases desbalanceadas.
Estrategias para resolver desequilibrio de datos en Python con la librería imbalanced-learn¹²⁷.
Agenda:
1. ¿Qué son las clases desequilibradas en un dataset?
2. Métricas y Confusión Matrix
3. Ejercicio con Python
4. Estrategias
5. Modelo sin modificar
6. Penalización para compensar / Métricas
7. Resampling y Muestras sintéticas
1. subsampling
2. oversamplig
3. combinación
8. Balanced Ensemble
Empecemos!
¹²⁹
Y de aqui salen nuevas métricas: precisión y recall
Veamos la Confusion matrix con el ejemplo de las predicciones de perro y gato.
¹²⁹http://www.aprendemachinelearning.com/wp-content/uploads/2019/05/confusion_matix_example.png
Datos desbalanceados 79
Cuando tenemos un dataset con desequilibrio, suele ocurrir que obtenemos un alto valor de
precisión en la clase Mayoritaria y un bajo recall en la clase Minoritaria
Veamos el dataset
Análisis exploratorio
Haremos EDA para comprobar el desequilibrio entre las clases:
¹³⁰https://www.kaggle.com/mlg-ulb/creditcardfraud/data
¹³¹https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_imbalanced_data.ipynb
¹³²http://www.aprendemachinelearning.com/principales-algoritmos-usados-en-machine-learning/
¹³³http://www.aprendemachinelearning.com/7-pasos-machine-learning-construir-maquina/
¹³⁴http://www.aprendemachinelearning.com/12-consejos-utiles-para-aplicar-machine-learning/
¹³⁵https://imbalanced-learn.readthedocs.io/en/stable/
Datos desbalanceados 81
1 import pandas as pd
2 import numpy as np
3 import matplotlib.pyplot as plt
4 import seaborn as sns
5
6 from sklearn.metrics import confusion_matrix
7 from sklearn.metrics import classification_report
8 from sklearn.model_selection import train_test_split
9 from sklearn.linear_model import LogisticRegression
10 from sklearn.decomposition import PCA
11 from sklearn.tree import DecisionTreeClassifier
12
13 from pylab import rcParams
14
15 from imblearn.under_sampling import NearMiss
16 from imblearn.over_sampling import RandomOverSampler
17 from imblearn.combine import SMOTETomek
18 from imblearn.ensemble import BalancedBaggingClassifier
19
20 from collections import Counter
Luego de importar las librerías que usaremos, cargamos con pandas el dataframe y vemos las
primeras filas:
¹³⁶
Veamos de cuantas filas tenemos y cuantas hay de cada clase:
1 print(df.shape)
2 print(pd.value_counts(df['Class'], sort = True))
¹³⁶http://www.aprendemachinelearning.com/wp-content/uploads/2019/05/imbalance_dataframe.png
Datos desbalanceados 82
1 (284807, 31)
2
3 0 284315
4 1 492
5 Name: Class, dtype: int64
Vemos que son 284.807 filas y solamente 492 son la clase minoritaria con los casos de fraude.
Representan el 0,17% de las muestras.
¹³⁷
¿Llegas a ver la mínima linea roja que representa los casos de Fraude? son muy pocas muestras!
¹³⁷http://www.aprendemachinelearning.com/wp-content/uploads/2019/05/imbalance_card_visualization.png
Datos desbalanceados 83
1. Ajuste de Parámetros del modelo: Consiste en ajustar parametros ó metricas del propio
algoritmo para intentar equilibrar a la clase minoritaria penalizando a la clase mayoritaria
durante el entrenamiento. Ejemplos on ajuste de peso en árboles, también en logisticregression
tenemos el parámetro class_weight= “balanced” que utilizaremos en este ejemplo. No todos los
algoritmos tienen estas posibilidades. En redes neuronales por ejemplo podríamos ajustar la
métrica de Loss para que penalice a las clases mayoritarias.
2. Modificar el Dataset: podemos eliminar muestras de la clase mayoritaria para reducirlo e
intentar equilibrar la situación. Tiene como “peligroso” que podemos prescindir de muestras
importantes, que brindan información y por lo tanto empeorar el modelo. Entonces para selec-
cionar qué muestras eliminar, deberíamos seguir algún criterio. También podríamos agregar
nuevas filas con los mismos valores de las clases minoritarias, por ejemplo cuadriplicar nuestras
492 filas. Pero esto no sirve demasiado y podemos llevar al modelo a caer en overfitting.
3. Muestras artificiales: podemos intentar crear muestras sintéticas (no idénticas) utilizando
diversos algoritmos que intentan seguir la tendencia del grupo minoritario. Según el método,
podemos mejorar los resultados. Lo peligroso de crear muestras sintéticas es que podemos
alterar la distribución “natural” de esa clase y confundir al modelo en su clasificación.
4. Balanced Ensemble Methods: Utiliza las ventajas de hacer ensamble de métodos, es decir,
entrenar diversos modelos y entre todos obtener el resultado final (por ejemplo “votando”)
pero se asegura de tomar muestras de entrenamiento equilibradas.
¹³⁸http://www.aprendemachinelearning.com/regresion-logistica-con-python-paso-a-paso/
Datos desbalanceados 84
¹³⁹
Aqui vemos la confusion matrix y en la clase 2 (es lo que nos interesa detectar) vemos 51 fallos y 97
aciertos dando un** recall de 0.66** y es el valor que queremos mejorar. También es interesante
notar que en la columna de f1-score obtenemos muy buenos resultados PERO que realmente no nos
deben engañar… pues están reflejando una realidad parcial. Lo cierto es que nuestro modelo no es
capaz de detectar correctamente los casos de Fraude.
¹³⁹http://www.aprendemachinelearning.com/wp-content/uploads/2019/05/confus_normal.png
Datos desbalanceados 86
¹⁴⁰
Ahora vemos una NOTABLE MEJORA! en la clase 2 -que indica si hubo fraude-, se han acertado
137 muestras y fallado en 11, dando un recall de 0.93 !! y sólo con agregar un parámetro al
modelo ;) También notemos que en la columna de f1-score parecería que hubieran “empeorado”
los resultados… cuando realmente estamos mejorando la detección de casos fraudulentos. Es cierto
que aumentan los Falsos Positivos y se han etiquetado 1890 muestras como Fraudulentas cuando no
lo eran… pero ustedes piensen… ¿qué prefiere la compañía bancaria? ¿tener que revisar esos casos
manualmente ó fallar en detectar los verdaderos casos de fraude?
¹⁴⁰http://www.aprendemachinelearning.com/wp-content/uploads/2019/05/confus_balanced.png
Datos desbalanceados 87
¹⁴¹
También vemos que obtenemos muy buen resultado con recall de 0.93 aunque a costa de que
aumentaran los falsos positivos.
¹⁴¹http://www.aprendemachinelearning.com/wp-content/uploads/2019/05/confus_subsampling.png
Datos desbalanceados 89
1 os = RandomOverSampler(ratio=0.5)
2 X_train_res, y_train_res = os.fit_sample(X_train, y_train)
3
4 print ("Distribution before resampling {}".format(Counter(y_train)))
5 print ("Distribution labels after resampling {}".format(Counter(y_train_res)))
6
7 model = run_model(X_train_res, X_test, y_train_res, y_test)
8 pred_y = model.predict(X_test)
9 mostrar_resultados(y_test, pred_y)
¹⁴²
Tenemos un 0.89 de recall para la clase 2 y los Falsos positivos son 838. Nada mal.
¹⁴²http://www.aprendemachinelearning.com/wp-content/uploads/2019/05/confus_oversampling.png
Datos desbalanceados 90
1 os_us = SMOTETomek(ratio=0.5)
2 X_train_res, y_train_res = os_us.fit_sample(X_train, y_train)
3
4 print ("Distribution before resampling {}".format(Counter(y_train)))
5 print ("Distribution after resampling {}".format(Counter(y_train_res)))
6
7 model = run_model(X_train_res, X_test, y_train_res, y_test)
8 pred_y = model.predict(X_test)
9 mostrar_resultados(y_test, pred_y)
¹⁴³
En este caso seguimos teniendo bastante buen recall 0.85 de la clase 2 y vemos que los Falsos positivos
de la clase 1 son bastante pocos, 325 (de 85295 muestras).
¹⁴³http://www.aprendemachinelearning.com/wp-content/uploads/2019/05/smote-tomek.png
Datos desbalanceados 92
1 bbc = BalancedBaggingClassifier(base_estimator=DecisionTreeClassifier(),
2 sampling_strategy='auto',
3 replacement=False,
4 random_state=0)
5
6 #Train the classifier.
7 bbc.fit(X_train, y_train)
8 pred_y = bbc.predict(X_test)
9 mostrar_resultados(y_test, pred_y)
¹⁴⁴
Tampoco está mal. Vemos siempre mejora con respecto al modelo inicial con un recall de 0.88 para
los casos de fraude.
¹⁴⁵
Vemos que en nuestro caso las estrategias de Penalización y Subsampling nos dan el mejor
resultado, cada una con un recall de 0.93.
Pero quedémonos con esto: Con cualquiera de las técnicas que aplicamos MEJORAMOS el
modelo inicial de Regresión logística, que lograba un 0.66 de recall para la clase de Fraude. Y
no olvidemos que hay un tremendo desbalance de clases en el dataset!
IMPORTANTE: esto no quiere decir que siempre hay que aplicar Penalización ó NearMiss Subsam-
pling!, dependerá del caso, del desbalanceo y del modelo (en este caso usamos regresión logística,
pero podría ser otro!).
Resumen
Es muy frecuente encontrarnos con datasets con clases desbalanceadas, de hecho… lo más raro sería
encontrar datasets bien equilibrados.
Siempre que puedas “Sal a la calle y consigue más muestras!” pero la realidad es que a veces no
es posible conseguir más datos de las clases minoritarias (como por ejemplo en Casos de Salud).
Vimos diversas estrategias a seguir para combatir esta problemática: eliminar muestras del set
mayoritario, crear muestras sintéticas con algún criterio, ensamble y penalización.
Además revisamos la Matriz de Confusión y comprendimos que las métricas pueden ser enga-
ñosas… si miramos a nuestros aciertos únicamente, puede que pensemos que tenemos un buen
clasificador, cuando realmente está fallando.
Recursos
• Notebook con todo el ejercicio y más cositas¹⁴⁶
¹⁴⁵http://www.aprendemachinelearning.com/wp-content/uploads/2019/05/imbalance_result.png
¹⁴⁶https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_imbalanced_data.ipynb
Datos desbalanceados 94
Enlaces de interés
• 8 tactics to combat imbalanced classes¹⁴⁹
• How to fix unbalanced dataset¹⁵⁰
¹⁴⁷https://www.kaggle.com/mlg-ulb/creditcardfraud/data
¹⁴⁸https://imbalanced-learn.readthedocs.io/en/stable/
¹⁴⁹https://machinelearningmastery.com/tactics-to-combat-imbalanced-classes-in-your-machine-learning-dataset/
¹⁵⁰https://www.kdnuggets.com/2019/05/fix-unbalanced-dataset.html
Random Forest, el poder del
Ensamble
Luego del algoritmo de árbol de Decisión¹⁵¹, tu próximo paso es el de estudiar Random Forest.
Comprende qué és y cómo funciona con un ejemplo práctico en Python.
Random Forest es un tipo de Ensamble en Machine Learning en donde combinaremos diversos
árboles -ya veremos cómo y con qué características- y la salida de cada uno se contará como “un
voto” y la opción más votada será la respuesta del Bosque Aleatorio.
Random Forest, al igual que el árbol e decisión,¹⁵² es un modelo de aprendizaje supervisado¹⁵³ para
clasificación¹⁵⁴ (aunque también puede usarse para problemas de regresión).
Y sus desventajas:
• en algunos datos de entrada “particulares” random forest también puede caer en overfitting
• es mucho más “costo” de crear y ejecutar que “un sólo árbol” de decisión.
• Puede requerir muchísimo tiempo de entrenamiento
• OJO! Random Forest no funciona bien con datasets pequeños.
• Es muy difícil poder interpretar¹⁵⁸ los ¿cientos? de árboles creados en el bosque, si quisiéramos
comprender y explicar a un cliente su comportamiento.
¿Llegas a ver la mínima linea roja que representa los casos de Fraude? son apenas 492 frente a más
de 250.000 casos de uso normal.
Retomaremos el mejor caso que obtuvimos en el ejercicio anterior utilizando Regresión Logística¹⁶⁰
y logrando un 98% de aciertos, pero recuerda también las métricas de F1, precisión y recall que eran
las que realmente nos ayudaban a validar el modelo.
¹⁶⁰https://en.wikipedia.org/wiki/Logistic_regression
Random Forest, el poder del Ensamble 98
Luego de unos minutos obtendremos el modelo entrenado (en mi caso 1 minuto 30 segundos)
Evaluamos resultados
Veamos la matriz de confusión y las métricas sobre el conjunto de test!!! (no confundir con el de
training!!!)
Random Forest, el poder del Ensamble 99
Aquí podemos destacar que para la clase “minoritaria”, es decir la que detecta los casos de fraude
tenemos un buen valor de recall (de 0.80) lo cual es un buen indicador! y el F1-score macro avg es de
0.93. Logramos construir un modelo de Bosque aleatorio que a pesar de tener un conjunto de datos
de entrada muy desigual, logra buenos resultados.
Resumen
Avanzando en nuestro aprendizaje sobre diversos modelos que podemos aplicar a las problemáticas
que nos enfrentamos, hoy sumamos a nuestro kit de herramientas¹⁶³ el Random Forest, vemos que
es un modelo sencillo, bastante rápido y si bien perdemos la interpretabilidad¹⁶⁴ maravillosa que nos
brindaba 1 sólo árbol de decisión, es el precio a pagar para evitar el overfitting¹⁶⁵ y para ganar un
clasificador más robusto.
Los algoritmos Tree-Based¹⁶⁶ -en inglés- son muchos, todos parten de la idea principal de árbol
de decisión¹⁶⁷ y la mejoran con diferentes tipos de ensambles y técnicas. Tenemos que destacar a
2 modelos que según el caso logran superar a las mismísimas redes neuronales¹⁶⁸! son XGboost y
LightGBM. Si te parecen interesantes puede que en el futuro escribamos sobre ellos.
Recursos y Adicionales
Puedes descargar la notebook para este ejercicio desde mi cuenta de GitHub:
Un nuevo Mundo
Al principio de los tiempos, sólo tenemos un conjunto Pangea que contiene todo nuestro dato
disponible. Digamos que tenemos un archivo csv con 10.000 registros.
Para entrenar nuestro modelo¹⁷⁴ de Machine Learning y poder saber si está funcionando bien, alguien
dijo: Separemos el conjunto de datos inicial en 2: conjunto de entrenamiento (train) y conjunto de
Pruebas (test). Por lo general se divide haciendo “80-20”. Y se toman muestras aleatorias -no en
secuencia, si no, mezclado-.
Para hacer el ejemplo sencillo, supongamos que queremos hacer clasificación¹⁷⁵ usando un algoritmo
supervisado¹⁷⁶, con lo cual tendremos:
Lo interesante de esto es que una vez los separamos en 8.000 registros para entrenar y 2.000 para
probar, usaremos sólo esos 8.000 registros para alimentar el modelo al entrenar haciendo:
1 modelo.fit(X_train, y_train)
Luego de entrenar nuestro modelo y habiendo decidido como métrica de negocio el Accuracy (el %
de aciertos) obtenemos un 75% sobre el set de entrenamiento (y asumimos que ese porcentaje nos
sirve para nuestro objetivo de negocio).
Los 2.000 registros que separamos en X_test aún nunca han pasado por el modelo de ML. ¿Se
entiende esto? porque eso es muy importante!!! Cuando usemos el set de test, haremos:
1 modelo.predict(X_test)
Como verás, no estamos usando fit()!!! sólo pasaremos los datos sin la columna de “y_test” que
contiene las etiquetas. Además remarco que estamos haciendo predicción; me refiero a que el modelo
NO se está entrenando ni <<incorporando conocimiento>>. El modelo se limita a “ver la entrada y
escupir una salida”.
Cuando hacemos el predict() sobre el conjunto de test y obtenemos las predicciones, las podemos
comprobar y contrastar con los valores reales almacenados en y_test y hallar así la métrica que
usamos. Los resultados que nos puede dar serán:
Conjunto de Entrenamiento, Test y Validación 103
Si el conjunto de Train y Test nos está dando métricas muy distintas esto es que el modelo no nos
sirve.
Para mejorar el modelo, podemos pensar en Tunear sus parámetros y volver a entrenar y probar,
podemos intentar obtener más registros, cambiar el preprocesado de datos, limpieza, balanceo de
¹⁷⁷https://www.aprendemachinelearning.com/que-es-overfitting-y-underfitting-y-como-solucionarlo/
Conjunto de Entrenamiento, Test y Validación 104
clases¹⁷⁸, selección de features, generación de features… De hecho, podemos pensar que seleccio-
namos un mal modelo, y podemos intentar con distintos modelos: de árbol de decisión¹⁷⁹, redes
neuronales¹⁸⁰, ensambles¹⁸¹…
La técnica de* Validación Cruzada* nos ayudará a medir el comportamiento el/los mode-
los que creamos y nos ayudará a encontrar un mejor modelo rápidamente.
Aclaremos antes de empezar: hasta ahora contamos con 2 conjuntos: el de Train y Test. El “set de
validación” no es realmente un tercer set si no que “vive” dentro del conjunto de Train. Reitero: el set
de validación no es un conjunto que apartemos de nuestro archivo csv original. El set de validación
se utilizará durante iteraciones que haremos con el conjunto de entrenamiento.
Entonces volvamos a tener las cosas claras: SOLO tenemos conjunto de Train y Test, ok?. El de Test
seguirá tratándose como antes: lo apartamos y lo usaremos al final, una vez entrenemos el modelo.
¹⁷⁸https://www.aprendemachinelearning.com/clasificacion-con-datos-desbalanceados/
¹⁷⁹https://www.aprendemachinelearning.com/arbol-de-decision-en-python-clasificacion-y-prediccion/
¹⁸⁰https://www.aprendemachinelearning.com/una-sencilla-red-neuronal-en-python-con-keras-y-tensorflow/
¹⁸¹https://www.aprendemachinelearning.com/random-forest-el-poder-del-ensamble/
Conjunto de Entrenamiento, Test y Validación 105
Dentro del conjunto de Train, y siguiendo nuestro ejemplo inicial, tenemos 8.000 registros. La
validación más común utilizada y que nos sirve para entender el concepto es “K-folds”, vamos a
comentarla:
• Iterar 5 veces:
1. Apartaremos 1/5 de muestras, es decir 1600.
2. Entrenamos al modelo con el restante 4/5 de muestras = 6400.
3. Mediremos el accuracy obtenido sobre las 1600 que habíamos apartado.
• Esto quiere decir que hacemos 5 entrenamientos independientes.
• El Accuracy final será el promedio de las 5 accuracies anteriores.
En
amarillo las muestras para entrenar y en verde el conjunto de Validación.
Entonces fijémonos que estamos “ocultando” una quinta parte del conjunto de train durante cada
iteración. Esto es similar a lo que explique antes, pero esta vez aplicado al momento de entrenamiento.
Al cabo de esas 5 iteraciones, obtenemos 5 accuracies que deberían ser “similares” entre sí, esto sería
un indicador de que el modelo está funcionando bien.
¹⁸²https://scikit-learn.org/stable/modules/cross_validation.html#k-fold
Conjunto de Entrenamiento, Test y Validación 106
• Cargar el dataset
• Dividir en Train y Test (en 80/20)
• Creamos un modelo de Regresión Logística (podría ser otro) y lo entrenamos con los datos de
Train
• Hacemos Cross-Validation usando K-folds con 5 splits
• Comparamos los resultados obtenidos en el modelo inicial, en el cross validation y vemos que
son similares.
Conjunto de Entrenamiento, Test y Validación 107
• Finalmente hacemos predict sobre el Conjunto de Test y veremos que también obtenemos buen
Accuracy
Stratified K-Fold
Statified K-fold es una variante mejorada de K-fold, que cuando hace los splits (las divisiones) del
conjunto de train tiene en cuenta mantener equilibradas las clases¹⁸³. Esto es muy útil, porque
imaginen que tenemos que clasificar en “SI/NO” y si una de las iteraciones del K-fold normal
tuviera muestras con etiquetas sólo “SI” el modelo no podría aprender a generalizar y aprenderá
para cualquier input a responder “SI”. Esto lo soluciona el Stratified K-fold¹⁸⁴.
Leave P Out
Leave P Out¹⁸⁵ selecciona una cantidad P por ejemplo 100. Entonces se separarán de a 100 muestras
contra las cuales validar y se iterará como se explico anteriormente. Si el valor P es pequeño,
esto resultará en muchísimas iteraciones de entrenamiento con un alto coste computacional (y
seguramente en tiempo). Si el valor P es muy grande, podría contener más muestras que las
usadas para entrenamiento, lo cual sería absurdo. Usar esta técnica con algo de sentido común y
manteniendo un equilibrio entre los scores y el tiempo de entreno.
ShuffleSplit
ShuffleSplit¹⁸⁶ primero mezcla los datos y nos deja indicar la cantidad de splits (divisiones) es decir
las iteraciones independientes que haremos y también indicar el tamaño del set de validación.
Para problemas de Series temporales¹⁸⁸ tenemos que prestar especial cuidado con los datos. Pues si
pasamos al modelo “dato futuro” antes de tiempo estaríamos haciendo Data Leakage, esto es como
si le hiciéramos spoiler al modelo y le contaremos el final de la película antes de que la vea. Esto
causaría overfitting¹⁸⁹.
Para empezar al hacer el split inicial de datos estos deberán estar ordenados por fecha y no
podemos mezclarlos.
Para ayudarnos con el cross-validation sklearn¹⁹⁰ nos provee de TimeSeriesSplit.
TimeSeriesSplit
TimeSeriesSplit¹⁹¹ es una variante adaptada de K-folds que evita “la fuga” de datos. Para hacerlo va
¹⁸⁸https://www.aprendemachinelearning.com/pronostico-de-series-temporales-con-redes-neuronales-en-python/
¹⁸⁹https://www.aprendemachinelearning.com/que-es-overfitting-y-underfitting-y-como-solucionarlo/
¹⁹⁰https://scikit-learn.org/stable/modules/cross_validation.html
¹⁹¹https://scikit-learn.org/stable/modules/cross_validation.html#time-series-split
Conjunto de Entrenamiento, Test y Validación 109
iterando los “folds” de a uno (usando una ventana de tiempo que se desplaza) y usando el “fold más
reciente” cómo el set de validación. Se puede entender mejor viendo una animación:
En
Amarillo las muestras para entrenar y en verde el conjunto de Validación.
Supongamos que el entrenamiento haciendo Cross Validation y el predict() en Test nos están dando
buenos accuracy (y similares) y estamos conformes con nuestro modelo. PUES si lo queremos usar
en un entorno REAL y productivo¹⁹³, ANTES de publicarlo es recomendado que agreguemos el
conjunto de test al modelo!!!, pues así estaremos aprovechando el 100% de nuestros datos. Espero que
esto último también se entienda porque es super importante: lo que estoy diciendo es que si al final
de todas nuestras iteraciones, pre procesado de dato, mejoras de modelo, ajuste de hiper-parámetros
y comparando con el conjunto de test, estamos seguros que el modelo funciona correctamente, es
entonces ahora, que usaremos las 10.000 muestras para entrenar al modelo, y ese modelo final, será
el que publicamos en producción.
Es una última iteración que debería mejorar el modelo final aunque este no lo podemos contrastar
contra nada… excepto con su comportamiento en el entorno real.
Si esta última iteración te causara dudas, no la hagas, excepto que tu problema sea de tipo Serie
¹⁹³https://www.aprendemachinelearning.com/tu-propio-servicio-de-machine-learning/
Conjunto de Entrenamiento, Test y Validación 111
Temporal¹⁹⁴. En ese caso sí que es muy importante hacerlo o quedaremos con un modelo que no “es
el más actual”.
Resumen
Lo más importante que quisiera que quede claro es que entonces tenemos 2 conjuntos: uno de Train
y otro de Test. El “conjunto de validación” no existe como tal, si no, que “vive temporalmente” al
momento de entrenar y nos ayuda a obtener al mejor modelo de entre los distintos que probaremos
para conseguir nuestro objetivo. Esa técnica es lo que se llama Validación Cruzada ó en inglés cross-
validation.
NOTA: en los ejemplos de la documentación de sklearn podremos ver que usan las
palabras train y test. Pero conceptualmente se está refiriendo al conjunto de validación y
no al de Test que usaremos al final. Esto es en parte el causante de tanta confusión con
este tema.
Tener en cuenta el tamaño de split 80/20 es el usual pero puede ser distinto, y esta proporción puede
cambiar sustancialmente las métricas obtenidas del modelo entrenado! Ojo con eso. El tamaño ideal
dependerá del dominio de nuestro problema, deberemos pensar en una cantidad de muestras para
test que nos aseguren que estamos el modelo creado está funcionando correctamente. Teniendo
10.000 registros puede que con testear 1000 filas ya estemos conformes ó que necesitemos 4000 para
estar mega-seguros. Por supuesto debemos recordar que las filas que estemos “quitando” para testear,
no las estamos usando al entrenar.
Otro factor: al hacer el experimento y tomar las muestras mezcladas, mantener la “semilla” ó no
podremos reproducir el mismo experimento para comparar y ver si mejora o no. Este suele ser un
parámetro llamado “random_state” y está bien que lo usemos para fijarlo.
Recomendaciones finales:
• En principio separar Train y Test en una proporción de 80/20
• Hacer Cross Validation siempre que podamos:
– No usar K-folds. Usar Stratified-K-folds en su lugar.
– La cantidad de “folds” dependerá del tamaño del dataset que tengamos, pero la cantidad
usual es 5 (pues es similar al 80-20 que hacemos con train/test).
– Para problemas de tipo time-series usar TimeSeriesSplit
• Si el Accuracy (ó métrica que usamos) es similar en los conjuntos de Train (donde hicimos
Cross Validation) y Test, podemos dar por bueno al modelo.
¹⁹⁴https://www.aprendemachinelearning.com/pronostico-de-ventas-redes-neuronales-python-embeddings/
Conjunto de Entrenamiento, Test y Validación 112
Recursos Adicionales
Otros artículos interesantes en inglés:
¹⁹⁵https://scikit-learn.org/stable/modules/cross_validation.html
¹⁹⁶https://towardsdatascience.com/5-reasons-why-you-should-use-cross-validation-in-your-data-science-project-8163311a1e79
¹⁹⁷https://www.kaggle.com/ynouri/random-forest-k-fold-cross-validation
K-Means
K-Means es un algoritmo no supervisado¹⁹⁸ de Clustering¹⁹⁹. Se utiliza cuando tenemos un montón
de datos sin etiquetar. El objetivo de este algoritmo es el de encontrar “K” grupos (clusters) entre
los datos crudos. En este artículo repasaremos sus conceptos básicos y veremos un ejemplo paso a
paso en python que podemos descargar.
• Los “centroids” de cada grupo que serán unas “coordenadas” de cada uno de los K conjuntos
que se utilizarán para poder etiquetar nuevas muestras.
• Etiquetas para el conjunto de datos de entrenamiento. Cada etiqueta perteneciente a uno de
los K grupos formados.
Los grupos se van definiendo de manera “orgánica”, es decir que se va ajustando su posición en cada
iteración del proceso, hasta que converge el algoritmo. Una vez hallados los centroids deberemos
analizarlos para ver cuales son sus características únicas, frente a la de los otros grupos. Estos grupos
son las etiquetas que genera el algoritmo.
El Algoritmo K-means
El algoritmo utiliza una proceso iterativo en el que se van ajustando los grupos para producir el
resultado final. Para ejecutar el algoritmo deberemos pasar como entrada el conjunto de datos y un
valor de K. El conjunto de datos serán las características o features para cada punto. Las posiciones
iniciales de los K centroids serán asignadas de manera aleatoria de cualquier punto del conjunto de
datos de entrada. Luego se itera en dos pasos:
1- Paso de Asignación de datos En este paso, cada “fila” de nuestro conjunto de datos se asigna al
centroide más cercano basado en la distancia cuadrada Euclideana. Se utiliza la siguiente fórmula
(donde dist() es la distancia Euclideana standard):
2-Paso de actualización de Centroid En este paso los centroid de cada grupo son recalculados. Esto
se hace tomando una media de todos los puntos asignados en el paso anterior.
El algoritmo converge a un resultado que puede ser el óptimo local, por lo que será conveniente
volver a ejecutar más de una vez con puntos iniciales aleatorios para confirmar si hay una salida
mejor. Recuerden siempre seguir los 7 pasos para construir IA²⁰²
Elegir el valor de K
Este algoritmo funciona pre-seleccionando un valor de K. Para encontrar el número de clusters en
los datos, deberemos ejecutar el algoritmo para un rango de valores K, ver los resultados y comparar
características de los grupos obtenidos. En general no hay un modo exacto de determinar el valor
K, pero se puede estimar con aceptable precisión siguiendo la siguiente técnica: Una de las métricas
usada para comparar resultados es la distancia media entre los puntos de datos y su centroid.
Como el valor de la media diminuirá a medida de aumentemos el valor de K, deberemos utilizar la
distancia media al centroide en función de K y entontrar el “punto codo”, donde la tasa de descenso
se “afila”. Aquí vemos una gráfica a modo de ejemplo:
mundo en diferentes areas: deporte, cantantes, actores, etc. Basado en una metodología de psicología
conocida como “Ocean: The Big Five” tendemos como características de entrada:
Utilizaremos el algoritmo K-means para que agrupe estos usuarios -no por su actividad laboral- si no,
por sus similitudes en la personalidad. Si bien tenemos 8 columnas de entrada, sólo utilizaremos 3
en este ejemplo, de modo que podamos ver en un gráfico tridimensional -y sus proyecciones a 2D- los
grupos resultantes. Pero para casos reales, podemos utilizar todas las dimensiones que necesitemos.
Una de las hipótesis que podríamos tener es: “Todos los cantantes tendrán personalidad parecida”
(y así con cada rubro laboral). Pues veremos si lo probamos, o por el contrario, los grupos no están
relacionados necesariamente con la actividad de estas Celebridades.
²⁰³https://www.anaconda.com/download/
²⁰⁴https://store.enthought.com/downloads/
²⁰⁵http://www.aprendemachinelearning.com/instalar-ambiente-de-desarrollo-python-anaconda-para-aprendizaje-automatico/
²⁰⁶http://www.aprendemachinelearning.com/wp-content/uploads/2018/03/Ejercicio_K_Means.ipynb
²⁰⁷http://www.aprendemachinelearning.com/wp-content/uploads/2018/03/analisis.csv
K-Means 117
1 import pandas as pd
2 import numpy as np
3 import matplotlib.pyplot as plt
4 import seaborn as sb
5 from sklearn.cluster import KMeans
6 from sklearn.metrics import pairwise_distances_argmin_min
7
8 %matplotlib inline
9 from mpl_toolkits.mplot3d import Axes3D
10 plt.rcParams['figure.figsize'] = (16, 9)
11 plt.style.use('ggplot')
Importamos el archivo csv²⁰⁸ -para simplificar, suponemos que el archivo se encuentra en el mismo
directorio que el notebook- y vemos los primeros 5 registros del archivo tabulados.
1 dataframe = pd.read_csv(r"analisis.csv")
2 dataframe.head()
También podemos ver una tabla de información estadística que nos provee Pandas dataframe:
1 dataframe.describe()
²⁰⁸http://www.aprendemachinelearning.com/wp-content/uploads/2018/03/analisis.csv
K-Means 118
1. Actor/actriz
2. Cantante
3. Modelo
4. Tv, series
5. Radio
6. Tecnología
7. Deportes
8. Politica
9. Escritor
1 print(dataframe.groupby('categoria').size())
Visualización de Datos
Veremos graficamente nuestros datos para tener una idea de la dispersión de los mismos:
1 dataframe.drop(['categoria'],1).hist()
2 plt.show()
En este caso seleccionamos 3 dimensiones: op, ex y ag y las cruzamos para ver si nos dan alguna
pista de su agrupación y la relación con sus categorías.
1 sb.pairplot(dataframe.dropna(), hue='categoria',size=4,vars=["op","ex","ag"],kind='s\
2 catter')
K-Means 120
Revisando la gráfica no pareciera que haa algún tipo de agrupación o correlación entre los usuarios
y sus categorías.
Definimos la entrada
Concretamos la estructura de datos que utilizaremos para alimentar el algoritmo. Como se ve, sólo
cargamos las columnas op, ex y ag en nuestra variable X.
K-Means 121
1 X = np.array(dataframe[["op","ex","ag"]])
2 y = np.array(dataframe['categoria'])
3 X.shape
4 ```python
5
6 ~~~
7 (140,3)
8 ~~~
9
10 Ahora veremos una gráfica en 3D con 9 colores representando las categorías.
11 ```python
12 fig = plt.figure()
13 ax = Axes3D(fig)
14 colores=['blue','red','green','blue','cyan','yellow','orange','black','pink','brown'\
15 ,'purple']
16 asignar=[]
17 for row in y:
18 asignar.append(colores[row])
19 ax.scatter(X[:, 0], X[:, 1], X[:, 2], c=asignar,s=60)
Veremos si con K-means, podemos “pintar” esta misma gráfica de otra manera, con clusters diferen-
ciados.
K-Means 122
Obtener el valor K
Vamos a hallar el valor de K haciendo una gráfica e intentando hallar el “punto de codo” que
comentábamos antes. Este es nuestro resultado:
1 Nc = range(1, 20)
2 kmeans = [KMeans(n_clusters=i) for i in Nc]
3 kmeans
4 score = [kmeans[i].fit(X).score(X) for i in range(len(kmeans))]
5 score
6 plt.plot(Nc,score)
7 plt.xlabel('Number of Clusters')
8 plt.ylabel('Score')
9 plt.title('Elbow Curve')
10 plt.show()
Realmente la curva es bastante “suave”. Considero a 5 como un buen número para K. Según vuestro
criterio podría ser otro.
Ejecutamos K-Means
Ejecutamos el algoritmo para 5 clusters y obtenemos las etiquetas y los centroids.
K-Means 123
1 kmeans = KMeans(n_clusters=5).fit(X)
2 centroids = kmeans.cluster_centers_
3 print(centroids)
Ahora veremos esto en una gráfica 3D con colores para los grupos y veremos si se diferencian: (las
estrellas marcan el centro de cada cluster)
]
Aqui podemos ver que el Algoritmo de K-Means con K=5 ha agrupado a los 140 usuarios Twitter
por su personalidad, teniendo en cuenta las 3 dimensiones que utilizamos: Openess, Extraversion y
Agreeablenes. Pareciera que no hay necesariamente una relación en los grupos con sus actividades
de Celebrity. Haremos 3 gráficas en 2 dimensiones con las proyecciones a partir de nuestra gráfica
3D para que nos ayude a visualizar los grupos y su clasificación:
1 f1 = dataframe['ex'].values
2 f2 = dataframe['ag'].values
3
4 plt.scatter(f1, f2, c=asignar, s=70)
5 plt.scatter(C[:, 1], C[:, 2], marker='*', c=colores, s=1000)
6 plt.show()
K-Means 127
En estas gráficas vemos que están bastante bien diferenciados los grupos. Podemos ver cada uno de
los clusters cuantos usuarios tiene:
1 copy = pd.DataFrame()
2 copy['usuario']=dataframe['usuario'].values
3 copy['categoria']=dataframe['categoria'].values
4 copy['label'] = labels;
5 cantidadGrupo = pd.DataFrame()
6 cantidadGrupo['color']=colores
7 cantidadGrupo['cantidad']=copy.groupby('label').size()
8 cantidadGrupo
K-Means 128
Y podemos ver la diversidad en rubros laborales de cada uno. Por ejemplo en el grupo 0 (rojo), vemos
que hay de todas las actividades laborales aunque predominan de actividad 1 y 2 correspondiente a
Actores y Cantantes con 11 y 15 famosos.
De categoría 3 “modelos” hay 6 sobre un total de 9. Buscaremos los usuarios que están más cerca a los
centroids de cada grupo que podríamos decir que tienen los rasgos de personalidad característicos
que representan a cada cluster:
1 users=dataframe['usuario'].values
2 for row in closest:
3 print(users[row])
En los centros vemos que tenemos una modelo, un político, presentadora de Tv, locutor de Radio y
un deportista.
1 [1]
Resumen
El algoritmo de K-means nos ayudará a crear clusters cuando tengamos grandes grupos de datos
sin etiquetar, cuando queramos intentar descubrir nuevas relaciones entre features o para probar
o declinar hipótesis que tengamos de nuestro negocio. Atención: Puede haber casos en los que
no existan grupos naturales, o clusters que contengan una verdadera razón de ser. Si bien K-
means siempre nos brindará “k clusters”, quedará en nuestro criterio reconocer la utilidad de los
mismos o bien revisar nuestras features y descartar las que no sirven o conseguir nuevas. También
tener en cuenta que en este ejemplo estamos utilizando como medida de similitud entre features la
distancia Euclideana²⁰⁹ pero podemos utilizar otras diversas funciones que podrían arrojar mejores
resultados (como Manhattan²¹⁰, Lavenshtein²¹¹, Mahalanobis²¹², etc). Hemos visto una descripción
del algoritmo, aplicaciones y un ejemplo python paso a paso, que podrán descargar también desde
los siguientes enlaces:
²⁰⁹https://es.wikipedia.org/wiki/Distancia_euclidiana
²¹⁰https://es.wikipedia.org/wiki/Geometr%C3%ADa_del_taxista
²¹¹https://en.wikipedia.org/wiki/Levenshtein_distance
²¹²https://en.wikipedia.org/wiki/Mahalanobis_distance
K-Means 130
²¹³http://nbviewer.jupyter.org/github/jbagnato/machine-learning/blob/master/Ejercicio_K_Means.ipynb
²¹⁴http://www.aprendemachinelearning.com/wp-content/uploads/2018/03/analisis.csv
²¹⁵http://www.aprendemachinelearning.com/wp-content/uploads/2018/03/Ejercicio_K_Means.ipynb
²¹⁶https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_K_Means.ipynb
²¹⁷https://github.com/jbagnato/machine-learning
K-Nearest-Neighbor
K-Nearest-Neighbor es un algoritmo basado en instancia²¹⁸ de tipo supervisado²¹⁹ de Machine
Learning. Puede usarse para clasificar nuevas muestras (valores discretos) o para predecir (regresión,
valores continuos). Al ser un método sencillo, es ideal para introducirse en el mundo del Aprendizaje
Automático. Sirve esencialmente para clasificar valores buscando los puntos de datos “más similares”
(por cercanía) aprendidos en la etapa de entrenamiento (ver 7 pasos para crear tu ML²²⁰) y haciendo
conjeturas de nuevos puntos basado en esa clasificación.
A diferencia de K-means²²¹, que es un algoritmo no supervisado²²² y donde la “K” significa la cantidad
de “grupos” (clusters²²³) que deseamos clasificar, en K-Nearest Neighbor la “K” significa la cantidad
de “puntos vecinos” que tenemos en cuenta en las cercanías para clasificar los “n” grupos -que ya se
conocen de antemano, pues es un algoritmo supervisado-.
• Supervisado: esto -brevemente- quiere decir que tenemos etiquetado nuestro conjunto de datos
de entrenamiento, con la clase o resultado esperado dada “una fila” de datos.
• Basado en Instancia: Esto quiere decir que nuestro algoritmo no aprende explícitamente un
modelo (como por ejemplo en Regresión Logística o árboles de decisión). En cambio memoriza
las instancias de entrenamiento que son usadas como “base de conocimiento” para la fase de
predicción.
Pros y contras
Como pros tiene sobre todo que es sencillo de aprender e implementar. Tiene como contras que
utiliza todo el dataset para entrenar “cada punto” y por eso requiere de uso de mucha memoria
y recursos de procesamiento (CPU). Por estas razones kNN tiende a funcionar mejor en datasets
pequeños y sin una cantidad enorme de features (las columnas).
Teniendo en cuenta el punto 3, veremos que para decidir la clase de un punto es muy importante
el valor de k, pues este terminará casi por definir a qué grupo pertenecerán los puntos, sobre
todo en las “fronteras” entre grupos. Por ejemplo -y a priori- yo elegiría valores impares de k para
desempatar (si las features que utilizamos son pares). No será lo mismo tomar para decidir 3 valores
que 13. Esto no quiere decir que necesariamente tomar más puntos implique mejorar la precisión.
Lo que es seguro es que cuantos más “puntos k”, más tardará nuestro algoritmo en procesar y
darnos respuesta ;) Las formas más populares de “medir la cercanía” entre puntos son la distancia
Euclidiana (la “de siempre”) o la **Cosine Similarity **(mide el ángulo de los vectores, cuanto
menores, serán similares). Recordemos que este algoritmo -y prácticamente todos en ML- funcionan
mejor con varias características de las que tomemos datos (las columnas de nuestro dataset). Lo
que entendemos como “distancia” en la vida real, quedará abstracto a muchas dimensiones que no
podemos “visualizar” fácilmente (como por ejemplo en un mapa).
Requerimientos
Para realizar este ejercicio, crearemos una Jupyter notebook²²⁵ con código Python y la librería
SkLearn muy utilizada en Data Science. Recomendamos utilizar la suite para python de Anaconda²²⁶.
Puedes leer este artículo²²⁷ donde muestro paso a paso como instalar el ambiente de desarrollo²²⁸.
Podrás descargar los archivos de entrada csv o visualizar la notebook online (al final de este artículo
los enlaces).
1 import pandas as pd
2 import numpy as np
3 import matplotlib.pyplot as plt
4 from matplotlib.colors import ListedColormap
5 import matplotlib.patches as mpatches
6 import seaborn as sb
7
8 %matplotlib inline
9 plt.rcParams['figure.figsize'] = (16, 9)
10 plt.style.use('ggplot')
11
12 from sklearn.model_selection import train_test_split
13 from sklearn.preprocessing import MinMaxScaler
²²⁵http://data-speaks.luca-d3.com/2018/03/python-para-todos-2-jupyternotebook.html
²²⁶https://www.anaconda.com/download/
²²⁷http://www.aprendemachinelearning.com/instalar-ambiente-de-desarrollo-python-anaconda-para-aprendizaje-automatico/
²²⁸http://www.aprendemachinelearning.com/instalar-ambiente-de-desarrollo-python-anaconda-para-aprendizaje-automatico/
K-Nearest-Neighbor 134
Cargamos el archivo entrada csv con pandas, usando separador de punto y coma, pues en las reviews
hay textos que usan coma. Con head(10) vemos los 10 primeros registros.
1 dataframe = pd.read_csv(r"reviews_sentiment.csv",sep=';')
2 dataframe.head(10)
1 dataframe.describe()
Son 257 registros. Las estrellas lógicamente vemos que van del 1 al 5. La cantidad de palabras van
de 1 sóla hasta 103. y las valoraciones de sentimiento están entre -2.27 y 3.26 con una media de 0,38
y a partir del desvío estándar podemos ver que la mayoría están entre 0,38-0,89 y 0,38+0,89.
K-Nearest-Neighbor 135
Un poco de Visualización
Veamos unas gráficas simples y qué información nos aportan:
1 dataframe.hist()
2 plt.show()
Vemos que la distribución de “estrellas” no está balanceada… esto no es bueno. Convendría tener
las mismas cantidades en las salidas, para no tener resultados “tendenciosos”. Para este ejercicio lo
dejaremos así, pero en la vida real, debemos equilibrarlos. La gráfica de Valores de Sentimientos
parece bastante una campana movida levemente hacia la derecha del cero y la cantidad de palabras
se centra sobre todo de 0 a 10. Veamos realmente cuantas Valoraciones de Estrellas tenemos:
1 print(dataframe.groupby('Star Rating').size())
K-Nearest-Neighbor 136
Con eso confirmamos que hay sobre todo de 3 y 5 estrellas. Y aqui una gráfica más bonita:
Graficamos mejor la cantidad de palabras y confirmamos que la mayoría están entre 1 y 10 palabras.
1 sb.factorplot('wordcount',data=dataframe,kind="count", aspect=3)
K-Nearest-Neighbor 137
1 X = dataframe[['wordcount','sentimentValue']].values
2 y = dataframe['Star Rating'].values
3
4 X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
5 scaler = MinMaxScaler()
6 X_train = scaler.fit_transform(X_train)
7 X_test = scaler.transform(X_test)
1 n_neighbors = 7
2
3 knn = KNeighborsClassifier(n_neighbors)
4 knn.fit(X_train, y_train)
5 print('Accuracy of K-NN classifier on training set: {:.2f}'
6 .format(knn.score(X_train, y_train)))
7 print('Accuracy of K-NN classifier on test set: {:.2f}'
8 .format(knn.score(X_test, y_test)))
Vemos que la precisión que nos da es de 90% en el set de entrenamiento y del 86% para el de test.
1 pred = knn.predict(X_test)
2 print(confusion_matrix(y_test, pred))
3 print(classification_report(y_test, pred))
Cómo se ve la puntuación F1 es del 87%, bastante buena. NOTA: recuerden que este es sólo un
ejercicio para aprender y tenemos MUY pocos registros totales y en nuestro conjunto de test. Por
ejemplo de 2 estrellas sólo tiene 1 valoración y esto es evidentemente insuficiente.
Vemos las 5 zonas en las que se relacionan cantidad de palabras con el valor de sentimiento de la
Review que deja el usuario. Se distinguen 5 regiones que podríamos dividir así:
Es decir que “a ojo” una review de 20 palabras y Sentimiento 1, nos daría una valoración de 4 (zona
K-Nearest-Neighbor 141
celeste). Con estas zonas podemos intuir ciertas características de los usuarios que usan y valoran la
app:
• Los usuarios que ponen 1 estrella tienen sentimiento negativo y hasta 25 palabras.
• Los usuarios que ponen 2 estrellas dan muchas explicaciones (hasta 100 palabras) y su senti-
miento puede variar entre negativo y algo positivo.
• Los usuarios que ponen 3 estrellas son bastante neutrales en sentimientos, puesto que están en
torno al cero y hasta unas 25 palabras.
• Los usuarios que dan 5 estrellas son bastante positivos (de 0,5 en adelante, aproximadamente)
y ponen pocas palabras (hasta 10).
En la gráfica vemos que con valores k=7 a k=14 es donde mayor precisión se logra.
1 print(clf.predict([[5, 1.0]]))
1 [5]
Este resultado nos indica que para 5 palabras y sentimiento 1, nos valorarán la app con 5 estrellas.
Pero también podríamos obtener las probabilidades que de nos den 1, 2,3,4 o 5 estrellas con predict_-
proba():
1 print(clf.predict_proba([[20, 0.0]]))
Aquí vemos que para las coordenadas 20, 0.0 hay 97% probabilidades que nos den 3 estrellas. Puedes
comprobar en el gráfico anterior, que encajan en las zonas que delimitamos anteriormente.
K-Nearest-Neighbor 143
Resumen
En este ejercicio creamos un modelo con Python para procesar y clasificar puntos de un conjunto de
entrada con el algoritmo k-Nearest Neighbor. Cómo su nombre en inglés lo dice, se evaluán los “k
vecinos más cercanos” para poder clasificar nuevos puntos. Al ser un algoritmo supervisado debemos
contar con suficientes muestras etiquetadas para poder entrenar el modelo con buenos resultados.
Este algoritmo es bastante simple y -como vimos antes- necesitamos muchos recursos de memoria
y cpu para mantener el dataset “vivo” y evaluar nuevos puntos. Esto no lo hace recomendable para
conjuntos de datos muy grandes. En el ejemplo, sólo utilizamos 2 dimensiones de entrada para poder
graficar y ver en dos dimensiones cómo se obtienen y delimitan los grupos. Finalmente pudimos
hacer nuevas predicciones y a raíz de los resultados, comprender mejor la problemática planteada.
Recursos y enlaces
• Descarga la Jupyter Notebook²³² y el archivo de entrada csv²³³
• ó puedes visualizar online²³⁴
• o ver y descargar desde mi cuenta github²³⁵
²³²http://www.aprendemachinelearning.com/wp-content/uploads/2018/07/Ejercicio_k-NearestNeighbor.ipynb
²³³http://www.aprendemachinelearning.com/wp-content/uploads/2018/07/reviews_sentiment.csv
²³⁴http://nbviewer.jupyter.org/github/jbagnato/machine-learning/blob/master/Ejercicio_k-NearestNeighbor.ipynb
²³⁵https://github.com/jbagnato/machine-learning
²³⁶https://towardsdatascience.com/implementing-k-nearest-neighbors-with-scikit-learn-9e4858e231ea
²³⁷https://towardsdatascience.com/introduction-to-k-nearest-neighbors-3b534bb11d26
²³⁸https://kevinzakka.github.io/2016/07/13/k-nearest-neighbor/
²³⁹https://towardsdatascience.com/solving-a-simple-classification-problem-with-python-fruits-lovers-edition-d20ab6b071d2
Naive Bayes: ¿Comprar casa o
Alquilar?
Veremos un ejercicio práctico intentando llevar los algoritmos de Machine Learning a un ejemplo de
la vida real. Repasaremos la teoría del Teorema de Bayes (video)²⁴⁰ de estadística para poder tomar
una decisión muy importante: ¿me conviene comprar casa ó alquilar?
Veamos si la Ciencia de Datos nos puede ayudar a resolver el misterio: ¿Si alquilo estoy
tirando el dinero a la basura? ó ¿Es realmente conveniente pagar una hipoteca durante el
resto de mi vida?
Si bien tocaremos el tema superficialmente -sin meternos en detalles como taza de interés de
hipotecas variable/fija, comisiones de bancos, etc- haremos un planteo genérico para obtener re-
sultados y tomar la mejor decisión dada nuestra condición actual. En otros capítulos vimos diversos
algoritmos Supervisados²⁴¹ del Aprendizaje Automático²⁴² que nos dejan clasificar datos y/o obtener
predicciones o asistencia a la toma de decisiones (árbol de decisión²⁴³, regresión logística²⁴⁴ y lineal²⁴⁵,
red neuronal²⁴⁶). Por lo general esos algoritmos intentan minimizar algún tipo de coste iterando las
entradas y las salidas y ajustando internamente las “pendientes” ó “pesos” para hallar una salida.
Esta vez, el algoritmo que usaremos se basa completamente en teoría de probabilidades y obteniendo
resultados estadísticos. ¿Será suficiente el Teorema de Bayes²⁴⁷ para obtener buenas decisiones?
Veamos!
²⁴⁰https://www.youtube.com/watch?v=vI0XwOu_c0o
²⁴¹http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/#supervisado
²⁴²http://www.aprendemachinelearning.com/que-es-machine-learning/
²⁴³http://www.aprendemachinelearning.com/arbol-de-decision-en-python-clasificacion-y-prediccion/
²⁴⁴http://www.aprendemachinelearning.com/regresion-logistica-con-python-paso-a-paso/
²⁴⁵http://www.aprendemachinelearning.com/regresion-lineal-en-espanol-con-python/
²⁴⁶http://www.aprendemachinelearning.com/una-sencilla-red-neuronal-en-python-con-keras-y-tensorflow/
²⁴⁷https://es.wikipedia.org/wiki/Teorema_de_Bayes
Naive Bayes: ¿Comprar casa o Alquilar? 145
1 import pandas as pd
2 import numpy as np
3 import matplotlib.pyplot as plt
4 from matplotlib import colors
5 import seaborn as sb
6
7 %matplotlib inline
8 plt.rcParams['figure.figsize'] = (16, 9)
9 plt.style.use('ggplot')
10
11 from sklearn.model_selection import train_test_split
12 from sklearn.metrics import classification_report
13 from sklearn.metrics import confusion_matrix
14 from sklearn.naive_bayes import GaussianNB
15 from sklearn.feature_selection import SelectKBest
1 dataframe = pd.read_csv(r"comprar_alquilar.csv")
2 dataframe.head(10)
²⁴⁹
Las columnas que tenemos son:
Con esta información, queremos que el algoritmo aprenda y que como resultado podamos consultar
nueva información y nos dé una decisión sobre comprar (1) o alquilar (0) casa.
El teorema de Bayes
El teorema de Bayes²⁵⁰ es una ecuación que describe la relación de probabilidades condicionales
de cantidades estadísticas. En clasificación bayesiana²⁵¹ estamos interesados en encontrar la proba-
bilidad de que ocurra una “clase” dadas unas características observadas (datos). Lo podemos escribir
como P( Clase | Datos). El teorema de Bayes nos dice cómo lo podemos expresar en términos de
cantidades que podemos calcular directamente:
²⁵⁰https://es.wikipedia.org/wiki/Teorema_de_Bayes
²⁵¹https://es.wikipedia.org/wiki/Clasificador_bayesiano_ingenuo
Naive Bayes: ¿Comprar casa o Alquilar? 147
²⁵²
Si estamos tratando de elegir entre dos clases como “comprar” ó “alquilar”, entonces una manera de
tomar la decisión es calcular la tasa de probabilidades a posterior:
²⁵²http://www.aprendemachinelearning.com/wp-content/uploads/2018/08/teorema_bayes01.png
Naive Bayes: ¿Comprar casa o Alquilar? 148
²⁵³
con esta maniobra, nos deshacemos del denominador de la ecuación anterior P(Datos) el llamado
“probabilidad marginal”.
Veamos cómo es su fórmula para comprender este curioso nombre: aplicaremos 2 clases (comprar,
alquilar) y tres características: ingresos, ahorros e hijos.
²⁵³http://www.aprendemachinelearning.com/wp-content/uploads/2018/08/teorema_bayes03.png
²⁵⁴https://es.wikipedia.org/wiki/Clasificador_bayesiano_ingenuo
Naive Bayes: ¿Comprar casa o Alquilar? 149
²⁵⁵
Posterior de comprar es lo que queremos hallar: P(comprar|datos). Explicaremos los demás:
Fin de la teoría, sigamos con el ejercicio! Ahora toca visualizar nuestras entradas y programar un
poquito.
Visualización de Datos
Veamos qué cantidad de muestras de comprar o alquilar tenemos:
²⁵⁵http://www.aprendemachinelearning.com/wp-content/uploads/2018/08/bayes_posteriori.png
²⁵⁶https://es.wikipedia.org/wiki/Distribuci%C3%B3n_normal
²⁵⁷https://es.wikipedia.org/wiki/Funci%C3%B3n_de_densidad_de_probabilidad
Naive Bayes: ¿Comprar casa o Alquilar? 150
1 print(dataframe.groupby('comprar').size())
Esto son 67 que entradas en las que se recomienda comprar y 135 en las que no. Hagamos un
histograma de las características quitando la columna de resultados (comprar):
1 dataframe.drop(['comprar'], axis=1).hist()
2 plt.show()
²⁵⁸
Pareciera a grandes rasgos que la distribución de hijos e ingresos se parece un poco a una distribución
normal.
²⁵⁸http://www.aprendemachinelearning.com/wp-content/uploads/2018/08/bayes_histogram.png
Naive Bayes: ¿Comprar casa o Alquilar? 151
1 dataframe['gastos']=(dataframe['gastos_comunes']+dataframe['gastos_otros']+dataframe\
2 ['pago_coche'])
3 dataframe['financiar']=dataframe['vivienda']-dataframe['ahorros']
4 dataframe.drop(['gastos_comunes','gastos_otros','pago_coche'], axis=1).head(10)
²⁵⁹
Y ahora veamos un resumen estadístico que nos brinda la librería Pandas con describe():
²⁶⁰
²⁵⁹http://www.aprendemachinelearning.com/wp-content/uploads/2018/08/bayes_preprocesa.png
²⁶⁰http://www.aprendemachinelearning.com/wp-content/uploads/2018/08/bayes_stats.png
Naive Bayes: ¿Comprar casa o Alquilar? 152
1 X=dataframe.drop(['comprar'], axis=1)
2 y=dataframe['comprar']
3
4 best=SelectKBest(k=5)
5 X_new = best.fit_transform(X, y)
6 X_new.shape
7 selected = best.get_support(indices=True)
8 print(X.columns[selected])
Bien, entonces usaremos 5 de las 11 características que teníamos. Las que “más aportan” al momento
de clasificar. Veamos qué grado de correlación tienen:
1 used_features =X.columns[selected]
2
3 colormap = plt.cm.viridis
4 plt.figure(figsize=(12,12))
5 plt.title('Pearson Correlation of Features', y=1.05, size=15)
6 sb.heatmap(dataframe[used_features].astype(float).corr(),linewidths=0.1,vmax=1.0, sq\
7 uare=True, cmap=colormap, linecolor='white', annot=True)
²⁶¹http://scikit-learn.org/stable/modules/feature_selection.html
Naive Bayes: ¿Comprar casa o Alquilar? 153
²⁶²
Con esto comprobamos que en general están poco correlacionadas, sin embargo también tenemos 2
valores de 0,7. Esperemos que el algoritmo sea lo suficientemente “naive” para dar buenos resultados
;)
Otra alternativa para Feture Selection es utilizar Principal Component Analysis (PCA) y
hacer reducción de Dimensión²⁶³
²⁶²http://www.aprendemachinelearning.com/wp-content/uploads/2018/08/bayes_correlation.png
²⁶³http://www.aprendemachinelearning.com/comprende-principal-component-analysis/
Naive Bayes: ¿Comprar casa o Alquilar? 154
Y creamos el modelo, lo ponemos a aprender con fit() y obtenemos predicciones sobre nuestro
conjunto de test.
Pues hemos obtenido un bonito 90% de aciertos en el conjunto de Test con nuestro querido clasifica-
dor bayesiano. También puedes ver los resultados obtenidos aplicando PCA en este otro capítulo²⁶⁴
• En un caso será una familia sin hijos con 2.000€ de ingresos que quiere comprar una casa de
200.000€ y tiene sólo 5.000€ ahorrados.
• El otro será una familia con 2 hijos con ingresos por 6.000€ al mes, 34.000 en ahorros y consultan
si comprar una casa de 320.000€.
²⁶⁴http://www.aprendemachinelearning.com/comprende-principal-component-analysis/
Naive Bayes: ¿Comprar casa o Alquilar? 155
1 [0 1]
Los resultados son los esperados, en el primer caso, recomienda Alquilar (0) y en el segundo comprar
la casa (1).
Resumen
A lo largo del artículo repasamos el teorema de Bayes²⁶⁵ y vimos un ejemplo para aplicarlo en
una toma de decisiones. Pero no olvidemos que en el proceso también hicimos pre procesamiento
de los datos, visualizaciones y Selección de Características. Durante diversas charlas que tuve con
profesionales del Data Science en mi camino de aprendizaje sale un mismo mensaje que dice: “No
es tan importante el algoritmo a aplicar si no la obtención y preprocesado de los datos que se van a
utilizar”. Naive Bayes como clasificador se utiliza mucho en NLP (Natural Language Processing)²⁶⁶
tanto en el típico ejemplo de detectar “Spam” o no, en tareas más complejas como reconocer
un idioma o detectar la categoría apropiada de un artículo de texto. También puede usarse para
detección de intrusiones o anomalías en redes informáticas y para diagnósticos médicos dados unos
síntomas observados. Por último veamos los pros y contras de utilizar Gaussian Naive Bayes:
• Pros: Es rápido, simple de implementar, funciona bien con conjunto de datos pequeños, va bien
con muchas dimensiones (features) y llega a dar buenos resultados aún siendo “ingenuo” sin
que se cumplan todas las condiciones de distribución necesarias en los datos.
• Contras: Requiere quitar las dimensiones con correlación y para buenos resultados las entradas
deberían cumplir las 2 suposiciones de distribución normal e independencia entre sí (muy difícil
que sea así ó deberíamos hacer transformaciones en lo datos de entrada).
Recursos Adicionales
• El código lo puedes ver en mi cuenta de Github²⁶⁷ ó …
• lo puedes descargar desde aquí Jupyter Notebook Ejercicio Bayes Python Code²⁶⁸
• Descarga el archivo csv de entrada comprar_alquilar.csv²⁶⁹
²⁷¹https://blog.sicara.com/naive-bayes-classifier-sklearn-python-example-tips-42d100429e44
²⁷²https://jakevdp.github.io/PythonDataScienceHandbook/05.05-naive-bayes.html
²⁷³https://towardsdatascience.com/bayesian-statistics-for-data-science-45397ec79c94
²⁷⁴http://scikit-learn.org/stable/modules/feature_selection.html
²⁷⁵http://www.aprendemachinelearning.com/comprende-principal-component-analysis/
Sistemas de Recomendación
Crea en Python un motor de recomendación con Collaborative
Filtering
Una de las herramientas más conocidas y utilizadas que aportó el Machine Learning²⁷⁶ fueron
los sistemas de Recomendación. Son tan efectivas que estamos invadidos todos los días por
recomendaciones, sugerencias y “productos relacionados” aconsejados por distintas apps y webs.
Sin dudas, los casos más conocidos de uso de esta tecnología son Netflix acertando en recomendar
series y películas, Spotify sugiriendo canciones y artistas ó Amazon ofreciendo productos de
venta cruzada <<sospechosamente>> muy tentadores para cada usuario.
Pero también Google nos sugiere búsquedas relacionadas, Android aplicaciones en su tienda y
Facebook amistades. O las típicas “lecturas relacionadas” en los blogs y periódicos.
Todo E-Comerce que se precie de serlo debe utilizar esta herramienta y si no lo hace… estará
perdiendo una ventaja competitiva para potenciar sus ventas.
Antes del Machine Learning, lo más común era usar “rankings” ó listas con lo más votado, ó más
popular de entre todos los productos. Entonces a todos los usuarios se les recomendaba lo mismo.
Es una técnica que aún se usa y en muchos casos funciona bien, por ejemplo, en librerías ponen
apartados con los libros más vendidos, best sellers. Pero… ¿y si pudiéramos mejorar eso?… ¿si hubiera
usuarios que no se guían como un rebaño y no los estamos reteniendo?…
Los Sistemas de Recomendación intentan personalizar al máximo lo que ofrecerán a cada
usuario. Esto es ahora posible por la cantidad de información individual que podemos recabar de
las personas y nos da la posibilidad de tener una mejor tasa de aciertos, mejorando la experiencia
del internauta sin ofrecer productos a ciegas.
²⁷⁶https://www.aprendemachinelearning.com/que-es-machine-learning/
Sistemas de Recomendación 158
Tipos de motores
Entre las estrategias más usadas para crear sistemas de recomendación encontramos:
• Popularity: Aconseja por la “popularidad” de los productos. Por ejemplo, “los más vendidos”
globalmente, se ofrecerán a todos los usuarios por igual sin aprovechar la personalización. Es
fácil de implementar y en algunos casos es efectiva.
• Content-based: A partir de productos visitados por el usuario, se intenta “adivinar” qué busca
el usuario y ofrecer mercancías similares.
• Colaborative: Es el más novedoso, pues utiliza la información de “masas” para identificar
perfiles similares y aprender de los datos para recomendar productos de manera individual.
Ejemplo de Dataset
Necesitaremos, “ítems” y las valoraciones de los usuarios. Los ítems pueden ser, canciones, películas,
productos, ó lo que sea que queremos recomendar.
Entonces nos quedará una matriz de este tipo, donde la intersección entre fila y columna es una
valoración del usuario:
Sistemas de Recomendación 159
En esta “gráfica educativa” tenemos una matriz con productos (a la izquierda) y los ítems (arriba).
En este ejemplo los ítems serán frutas y cada celda contiene la valoración hecha por cada usuario
de ese ítem. Las casillas vacías significa que el usuario aún no ha probado esa fruta.
Entonces veremos que tenemos “huecos” en la tabla pues evidentemente no todos los usuarios tienen
o “valoraron” todos los ítems. Por ejemplo si los ítems fueran “películas”, es evidente que un usuario
no habrá visto <<todas las películas del mundo>>… entonces esos huecos son justamente los que con
nuestro algoritmo “rellenaremos” para recomendar ítems al usuario.
Una matriz con muchas celdas vacías se dice -en inglés- que es sparce²⁷⁷ (y suele ser normal) en
cambio si tuviéramos la mayoría de las celdas cubiertas con valoraciones, se llamará dense.
²⁸⁰
FORMULA para calcular los ratings faltantes: sería algo así como “Matriz de similitud PROD.VECTORIAL
ratings / (sumatoria de cada fila de ratings) Transpuesta
Lo haremos es: cada rating se multiplica por el factor de similitud de usuario que dio el rating.
La predicción final por usuario será igual a la suma del peso de los ratings dividido por la “suma
ponderada”.
Bueno, no te preocupes que este cálculo luego lo verás en código y no tiene tanto truco…
²⁷⁸http://blog.christianperone.com/2013/09/machine-learning-cosine-similarity-for-vector-space-models-part-iii/
²⁷⁹https://realpython.com/build-recommendation-engine-collaborative-filtering/
²⁸⁰https://www.aprendemachinelearning.com/wp-content/uploads/2019/08/rating_ponderado.png
Sistemas de Recomendación 161
Vamos al código!
Cargamos las librerías que utilizaremos
1 import pandas as pd
2 import numpy as np
3 from sklearn.metrics import mean_squared_error
4 from sklearn.model_selection import train_test_split
5 from sklearn.neighbors import NearestNeighbors
6 import matplotlib.pyplot as plt
7 import sklearn
1 df_users = pd.read_csv("users.csv")
2 df_repos = pd.read_csv("repos.csv")
3 df_ratings = pd.read_csv("ratings.csv")
4 print(df_users.head())
5 print(df_repos.head())
6 print(df_ratings.head())
²⁸¹
²⁸¹https://www.aprendemachinelearning.com/wp-content/uploads/2019/08/recommend_df_users.png
Sistemas de Recomendación 162
²⁸²
²⁸³
Vemos que tenemos un archivo con la información de los usuarios y sus identificadores, un archivo
con la información de los repositorios y finalmente el archivo “ratings” que contiene la valoración
por usuario de los repositorios. Como no tenemos REALMENTE una valoración del 1 al 5 -como
podríamos tener por ejemplo al valorar películas-, la columna rating es el número de usuarios que
tienen ese mismo repositorio dentro de nuestra base de datos. Sigamos explorando para comprende
un poco mejor:
1 n_users = df_ratings.userId.unique().shape[0]
2 n_items = df_ratings.repoId.unique().shape[0]
3 print (str(n_users) + ' users')
4 print (str(n_items) + ' items')
1 30 users
2 167 items
Vemos que es un dataset reducido, pequeño. Tenemos 30 usuarios y 167 repositorios valorados.
1 plt.hist(df_ratings.rating,bins=8)
²⁸²https://www.aprendemachinelearning.com/wp-content/uploads/2019/08/recommend_df_repos.png
²⁸³https://www.aprendemachinelearning.com/wp-content/uploads/2019/08/recommend_df_ratings.png
Sistemas de Recomendación 163
²⁸⁴
Tenemos más de 80 valoraciones con una puntuación de 1 y unas 40 con puntuación en 5. Veamos
las cantidades exactas:
1 df_ratings.groupby(["rating"])["userId"].count()
1 rating
2 1 94
3 2 62
4 3 66
5 4 28
6 5 40
7 6 12
8 7 14
9 8 8
10 Name: userId, dtype: int64
1 plt.hist(df_ratings.groupby(["repoId"])["repoId"].count(),bins=8)
²⁸⁴https://www.aprendemachinelearning.com/wp-content/uploads/2019/08/recommend_ratings_hist.png
Sistemas de Recomendación 164
²⁸⁵
Aquí vemos la cantidad de repositorios y cuantos usuarios “los tienen”. La mayoría de repos los
tiene 1 sólo usuario, y no los demás. Hay unos 30 que los tienen 2 usuarios y unos 20 que coinciden
3 usuarios. La suma total debe dar 167.
²⁸⁶
Vemos que rellenamos los “huecos” de la matriz con ceros. Y esos ceros serán los que deberemos
reemplazar con las recomendaciones.
Sparcity
Veamos el porcentaje de sparcity²⁸⁷ que tenemos:
1 ratings = df_matrix.values
2 sparsity = float(len(ratings.nonzero()[0]))
3 sparsity /= (ratings.shape[0] * ratings.shape[1])
4 sparsity *= 100
5 print('Sparsity: {:4.2f}%'.format(sparsity))
1 Sparsity: 6.43%
1 (24, 167)
2 (6, 167)
1 sim_matrix = 1 - sklearn.metrics.pairwise.cosine_distances(ratings)
2 print(sim_matrix.shape)
1 (30, 30)
1 plt.imshow(sim_matrix);
2 plt.colorbar()
3 plt.show()
²⁸⁸https://www.aprendemachinelearning.com/clasificacion-con-datos-desbalanceados/
²⁸⁹https://www.aprendemachinelearning.com/sets-de-entrenamiento-test-validacion-cruzada/
Sistemas de Recomendación 167
²⁹⁰
Cuanto más cercano a 1, mayor similitud entre esos usuarios.
²⁹¹
Vemos pocas recomendaciones que logren puntuar alto. La mayoría estará entre 1 y 2 puntos. Esto
tiene que ver con nuestro dataset pequeño.
Vamos a tomar de ejemplo mi usuario de Github que es jbagnato²⁹².
1 USUARIO_EJEMPLO = 'jbagnato'
2 data = df_users[df_users['username'] == USUARIO_EJEMPLO]
3 usuario_ver = data.iloc[0]['userId'] - 1 # resta 1 para obtener el index de pandas.
4
5 user0=users_predictions.argsort()[usuario_ver]
6
7 # Veamos los tres recomendados con mayor puntaje en la predic para este usuario
8 for i, aRepo in enumerate(user0[-3:]):
9 selRepo = df_repos[df_repos['repoId']==(aRepo+1)]
10 print(selRepo['title'] , 'puntaje:', users_predictions[usuario_ver][aRepo])
1 4 ytdl-org / youtube-dl
2 Name: title, dtype: object puntaje: 2.06
3 84 dipanjanS / practical-machine-learning-with-py...
4 Name: title, dtype: object puntaje: 2.44
5 99 abhat222 / Data-Science--Cheat-Sheet
6 Name: title, dtype: object puntaje: 3.36
Vemos que los tres repositorios con mayor puntaje para sugerir a mi usuario son el de Data-
Science–Cheat-Sheet con una puntuación de 3.36, practical-machine-learning-with-py con 2.44
y youtube-dl con 2.06. Lo cierto es que no son puntuaciones muy altas, pero tiene que ver con que
la base de datos (nuestro csv) tiene muy pocos repositorios y usuarios cargados.
Validemos el error
Sobre el test set comparemos el mean squared error²⁹³ con el conjunto de entrenamiento:
²⁹¹https://www.aprendemachinelearning.com/wp-content/uploads/2019/08/recommend_train_predictions.png
²⁹²https://github.com/jbagnato/machine-learning
²⁹³https://www.statisticshowto.datasciencecentral.com/mean-squared-error/
Sistemas de Recomendación 169
1 3.39
2 4.72
Vemos que para el conjunto de train y test el MAE es bastante cercano. Un indicador de que no tiene
buenas predicciones sería si el MAE en test fuera 2 veces más (ó la mitad) del valor del de train.
Hay más…
En la notebook completa -en Github-²⁹⁴, encontrarás más opciones de crear el Recomendador,
utilizando K-Nearest Neighbors²⁹⁵ como estimador, y también usando la similitud entre ítems (ítem-
based). Sin embargo para los fines de este artículo espero haber mostrado el funcionamiento básico
del Collaborative Filtering. Te invito a que luego lo explores por completo.
Resumen
Vimos que es relativamente sencillo crear un sistema de recomendación en Python y con Machine
Learning. Como muchas veces en Data-Science una de las partes centrales para que el modelo
funcione se centra en tener los datos correctos y un volumen alto. También es central el valor que
utilizaremos como “rating” -siendo una valoración real de cada usuario ó un valor artificial que
creemos adecuado-. Recuerda que me refiero a rating como ese puntaje que surge de la intersección
entre usuario e ítems en nuestro dataset. Luego será cuestión de evaluar entre las opciones de motores
user-based, ítem-based y seleccionar la que menor error tenga. Y no descartes probar en el “mundo
real” y ver qué porcentaje de aciertos (o feedback) te dan los usuarios reales de tu aplicación!
²⁹⁴https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_Sistemas_Recomendacion.ipynb
²⁹⁵https://www.aprendemachinelearning.com/clasificar-con-k-nearest-neighbor-ejemplo-en-python/
Sistemas de Recomendación 170
Existen algunas librerías que se utilizan para crear motores de recomendación como “surprise”.
También te sugiero que las explores.
Por último, decir que -como en casi todo el Machine Learning- tenemos la opción de crear Redes
Neuronales con Embeddings²⁹⁶ como recomendados y hasta puede que sean las que mejor funcionan
para resolver esta tarea!… pero queda fuera del alcance de este tutorial. Dejaré algún enlace por ahí
abajo ;)
• users.csv²⁹⁷
• repos.csv²⁹⁸
• ratings.csv²⁹⁹
• Ejercicio-Sistemas-de-Recomendación³⁰⁰ - Jupyter Notebook
²⁹⁶https://www.aprendemachinelearning.com/pronostico-de-ventas-redes-neuronales-python-embeddings/
²⁹⁷https://github.com/jbagnato/machine-learning/blob/master/users.csv
²⁹⁸https://github.com/jbagnato/machine-learning/blob/master/repos.csv
²⁹⁹https://github.com/jbagnato/machine-learning/blob/master/ratings.csv
³⁰⁰https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_Sistemas_Recomendacion.ipynb
³⁰¹https://realpython.com/build-recommendation-engine-collaborative-filtering/
³⁰²https://towardsdatascience.com/collaborative-filtering-and-embeddings-part-1-63b00b9739ce
³⁰³https://towardsdatascience.com/how-to-build-a-simple-song-recommender-296fcbc8c85
³⁰⁴http://www.salemmarafi.com/code/collaborative-filtering-with-python/
³⁰⁵https://medium.com/recombee-blog/machine-learning-for-recommender-systems-part-1-algorithms-evaluation-and-cold-start-
6f696683d0ed
Breve Historia de las Redes
Neuronales Artificiales
Arquitecturas y Aplicaciones de las Redes Neuronales
más usadas.
Vamos a hacer un repaso por las diversas estructuras inventadas, mejoradas y utilizadas a lo largo de
la historia para crear redes neuronales y sacar el mayor potencial al Deep Learning³⁰⁶ para resolver
toda clase de problemas³⁰⁷ de regresión y clasificación.
• 1958 - Perceptron
• 1965 - Multilayer Perceptron
• 1980’s
– Neuronas Sigmoidales
– Redes Feedforward
– Backpropagation
• 1989 - Convolutional neural networks (CNN) / Recurent neural networks (RNN)
• 1997 - Long short term memory (LSTM)
• 2006 - Deep Belief Networks (DBN): Nace deep learning
– Restricted Boltzmann Machine
– Encoder / Decoder = Auto-encoder
• 2014 - Generative Adversarial Networks (GAN)
Si bien esta lista no es exhaustiva y no se abarcan todos los modelos creados desde los años 50, he
recopilado las que fueron -a mi parecer- las redes y tecnologías más importantes desarrolladas
para llegar al punto en que estamos hoy: el Aprendizaje Profundo.
³⁰⁶http://www.aprendemachinelearning.com/aprendizaje-profundo-una-guia-rapida/
³⁰⁷http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/
Breve Historia de las Redes Neuronales Artificiales 172
1958 - Perceptron
³⁰⁸
Entre las décadas de 1950 y 1960 el científico Frank Rosenblatt³⁰⁹, inspirado en el trabajo de Warren
McCulloch y Walter Pitts creó el Perceptron, la unidad desde donde nacería y se potenciarían las
redes neuronales artificiales. Un perceptron toma varias entradas binarias x1, x2, etc y produce una
sóla salida binaria. Para calcular la salida, Rosenblatt introduce el concepto de “pesos” w1, w2, etc,
un número real que expresa la importancia de la respectiva entrada con la salida. La salida de la
neurona será 1 o 0 si la suma de la multiplicación de pesos por entradas es mayor o menor a un
determinado umbral. Sus principales usos son decisiones binarias sencillas, o para crear funciones
lógicas como OR, AND.
³⁰⁸http://www.aprendemachinelearning.com/wp-content/uploads/2018/09/net_perceptron.png
³⁰⁹https://es.wikipedia.org/wiki/Frank_Rosenblatt
Breve Historia de las Redes Neuronales Artificiales 173
³¹⁰
Como se imaginarán, el multilayer perceptron es una “amplicación” del percepción de una única
neurona a más de una. Además aparece el concepto de capas de entrada, oculta y salida. Pero con
valores de entrada y salida binarios. No olvidemos que tanto el valor de los pesos como el de umbral
de cada neurona lo asignaba manualmente el científico. Cuantos más perceptrones en las capas,
mucho más difícil conseguir los pesos para obtener salidas deseadas.
Neuronas Sigmoides
Para poder lograr que las redes de neuronas aprendieran solas fue necesario introducir un nuevo
tipo de neuronas. Las llamadas Neuronas Sigmoides son similares al perceptron, pero permiten que
las entradas, en vez de ser ceros o unos, puedan tener valores reales como 0,5 ó 0,377 ó lo que sea.
También aparecen las neuronas “bias” que siempre suman 1 en las diversas capas para resolver ciertas
situaciones. Ahora las salidas en vez de ser 0 ó 1, será d(w . x + b) donde d será la función sigmoide
definida como d(z) = 1/( 1 +e-z). Esta es la primer función de activación!
³¹⁰http://www.aprendemachinelearning.com/wp-content/uploads/2018/09/net_multilayer.png
Breve Historia de las Redes Neuronales Artificiales 174
³¹¹
Imagen de la Curva Logística Normalizada de Wikipedia
Con esta nueva fórmula, se puede lograr que pequeñas alteraciones en valores de los pesos
(deltas) produzcan pequeñas alteraciones en la salida. Por lo tanto, podemos ir ajustando muy
de a poco los pesos de las conexiones e ir obteniendo las salidas deseadas.
Redes Feedforward
Se les llama así a las redes en que las salidas de una capa son utilizadas como entradas en la próxima
capa. Esto quiere decir que no hay loops “hacia atrás”. Siempre se “alimenta” de valores hacia
adelante. Hay redes que veremos más adelante en las que sí que existen esos loops (Recurrent Neural
Networks). Además existe el concepto de “fully connected Feedforward Networks” y se refiere a que
todas las neuronas de entrada, están conectadas con todas las neuronas de la siguiente capa.
1986 - Backpropagation
Gracias al algoritmo de backpropagation³¹² se hizo posible entrenar redes neuronales de multiples
capas de manera supervisada. Al calcular el error obtenido en la salida e ir propagando hacia las capas
anteriores se van haciendo ajustes pequeños (minimizando costo) en cada iteración para lograr que
la red aprenda consiguiendo que la red pueda -por ejemplo- clasificar las entradas correctamente.
³¹¹http://www.aprendemachinelearning.com/wp-content/uploads/2018/07/Logistic-curve.png
³¹²https://es.wikipedia.org/wiki/Propagaci%C3%B3n_hacia_atr%C3%A1s
Breve Historia de las Redes Neuronales Artificiales 175
³¹³
Las Convolutional Neural Networks³¹⁴ son redes multilayered que toman su inspiración del cortex vi-
sual de los animales. Esta arquitectura es útil en varias aplicaciones, principalmente procesamiento
de imágenes. La primera CNN fue creada por Yann LeCun³¹⁵ y estaba enfocada en el reconocimiento
de letras manuscritas. La arquitectura constaba de varias capas que implementaban la extracción
de características y luego clasificar. La imagen se divide en campos receptivos que alimentan
una capa convolutional que extrae features de la imagen de entrada (Por ejemplo, detectar lineas
verticales, vértices, etc). El siguiente paso es pooling que reduce la dimensionalidad de las features
extraídas manteniendo la información más importante. Luego se hace una nueva convolución y
otro pooling que alimenta una red feedforward multicapa. La salida final de la red es un grupo de
nodos que clasifican el resultado, por ejemplo un nodo para cada número del 0 al 9 (es decir, 10
nodos, se “activan” de a uno).
Esta arquitectura usando capas profundas y la clasificación de salida abrieron un mundo nuevo de
posibilidades en las redes neuronales. Las CNN se usan también en reconocimiento de video y tareas
de Procesamiento del Lenguaje natural. ¿Quieres hacer tu propia CNN en Python?³¹⁶
³¹³http://www.aprendemachinelearning.com/wp-content/uploads/2018/09/net_convolutional.png
³¹⁴http://www.aprendemachinelearning.com/como-funcionan-las-convolutional-neural-networks-vision-por-ordenador/
³¹⁵https://en.wikipedia.org/wiki/Yann_LeCun
³¹⁶http://www.aprendemachinelearning.com/clasificacion-de-imagenes-en-python/
Breve Historia de las Redes Neuronales Artificiales 176
³¹⁷
Aqui vemos que la red LSTM tiene neuronas ocultas con loops hacia atrás (en azul). Esto permite
que almacene información en celdas de memoria.
Las Long short term memory son un tipo de Recurrent neural network. Esta arquitectura permite
conexiones “hacia atrás” entre las capas. Esto las hace buenas para procesar datos de tipo “time
series” (datos históricos). En 1997 se crearon las LSTM que consisten en unas celdas de memoria
que permiten a la red recordar valores por períodos cortos o largos. Una celda de memoria contiene
compuertas que administran como la información fluye dentro o fuera. La puerta de entrada
controla cuando puede entran nueva información en la memoria. La puerta de “olvido” controla
cuanto tiempo existe y se retiene esa información. La puerta de salida controla cuando la información
en la celda es usada como salida de la celda. La celda contiene pesos que controlan cada compuerta. El
algoritmo de entrenamiento -conocido como backpropagation-through-time optimiza estos pesos
basado en el error de resultado. Las LSTM se han aplicado en reconocimiento de voz, de escritura,
text-to-speech y otras tareas.
³¹⁷http://www.aprendemachinelearning.com/wp-content/uploads/2018/09/net_lstm.png
Breve Historia de las Redes Neuronales Artificiales 177
³¹⁸
La Deep Belief Network utiliza un Autoencoder con Restricted Boltzmann Machines para preentre-
nar a las neuronas de la red y obtener un mejor resultado final.
Antes de las DBN en 2006 los modelos con “profundidad” (decenas o cientos de capas) eran
considerados demasiado difíciles de entrenar (incluso con backpropagation) y el uso de las redes
neuronales artificiales quedó estancado. Con la creación de una DBN que logro obtener un mejor
resultado en el MNIST³¹⁹, se devolvió el entusiasmo en poder lograr el aprendizaje profundo en
redes neuronales. Hoy en día las DBN no se utilizan demasiado, pero fueron un gran hito en la
historia en el desarrollo del deep learning y permitieron seguir la exploración para mejorar las redes
existentes CNN, LSTM, etc. Las Deep Belief Networks, demostraron que utilizar pesos aleatorios
al inicializar las redes son una mala idea: por ejemplo al utilizar Backpropagation con Descenso
por gradiente muchas veces se caía en mínimos locales, sin lograr optimizar los pesos. Mejor será
utilizar una asignación de pesos inteligente mediante un preentrenamiento de las capas de la red
-en inglés “pretrain”-. Se basa en el uso de la utilización de Restricted Boltzmann Machines³²⁰ y
Autoencoders³²¹ para pre-entrenar la red de manera no supervisada³²². Ojo! luego de pre-entrenar
y asignar esos pesos iniciales, deberemos entrenar la red por de forma habitual, supervisada³²³ (por
ejemplo con backpropagation). Se cree que ese preentrenamiento es una de las causas de la gran
³¹⁸http://www.aprendemachinelearning.com/wp-content/uploads/2018/09/deep_beleif.png
³¹⁹https://tensorflow.rstudio.com/tensorflow/articles/tutorial_mnist_beginners.html
³²⁰https://towardsdatascience.com/deep-learning-meets-physics-restricted-boltzmann-machines-part-i-6df5c4918c15
³²¹https://towardsdatascience.com/the-variational-autoencoder-as-a-two-player-game-part-i-4c3737f0987b
³²²http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/#no_supervisado
³²³http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/#supervisado
Breve Historia de las Redes Neuronales Artificiales 178
mejora en las redes neuronales y permitir el deep learning: pues para asignar los valores se evalúa
capa a capa, de a una, y no “sufre” de cierto sesgo que causa el backpropagation, al entrenar a todas
las capas en simultáneo.
](http://www.aprendemachinelearning.com/wp-content/uploads/2018/09/gan.png)
Las GAN, entrenan dos redes neuronales en simultáneo. La red de Generación y la red de Discrimi-
nación. A medida que la máquina aprende, comienza a crear muestras que son indistinguibles de
los datos reales.
Estas redes pueden aprender a crear muestras, de manera similar a los datos con las que las
alimentamos. La idea detrás de GAN es la de tener dos modelos de redes neuronales compitiendo.
Uno, llamado Generador, toma inicialmente “datos basura” como entrada y genera muestras. El
otro modelo, llamado Discriminador, recibe a la vez muestras del Generador y del conjunto de
entrenamiento (real) y deberá ser capaz de diferenciar entre las dos fuentes. Estas dos redes juegan
una partida continua donde el Generador aprende a producir muestras más realistas y el
Discriminador aprende a distinguir entre datos reales y muestras artificiales. Estas redes son
entrenadas simultáneamente para finalmente lograr que los datos generados no puedan detectarse de
datos reales. Sus aplicaciones principales son la de generación de imágenes realistas, pero también
la de mejorar imágenes ya existentes, o generar textos (captions) en imágenes, o generar textos
siguiendo un estilo determinado y hasta desarrollo de moléculas para industria farmacéutica.
Breve Historia de las Redes Neuronales Artificiales 179
Resumen
Hemos recorrido estos primeros -casi- 80 años de avances en las redes neuronales en la historia de
la inteligencia artificial. Se suele dividir en 3 etapas, del 40 al 70 en donde se pasó del asombro
de estos nuevos modelos hasta el escepticismo, el retorno de un invierno de 10 años cuando en los
ochentas surgen mejoras en mecanismos y maneras de entrenar las redes (backpropagation³²⁴) y se
alcanza una meseta en la que no se puede alcanzar la “profundidad” de aprendizaje seguramente
también por falta de poder de cómputo. Y una tercer etapa a partir de 2006 en la que se logra
superar esa barrera y aprovechando el poder de las GPU y nuevas ideas se logra entrenar cientos de
capas jerárquicas que conforman y potencian el Deep Learning y dan una capacidad casi ilimitada a
estas redes. Como último comentario, me gustaría decir que recientemente (feb 2018³²⁵) hay nuevos
estudios de las neuronas humanas biológicas en las que se está redescubriendo su funcionamiento
y se está produciendo una nueva revolución, pues parece que es totalmente distinto a lo que hasta
hoy conocíamos. Esto puede ser el principio de una nueva etapa totalmente nueva y seguramente
mejor del Aprendizaje Profundo, el Machine Learning³²⁶ y la Inteligencia Artificial.
Más recursos
* Cheat Sheets for AI³²⁷
* Neural Networks and Deep Learning³²⁸
* From Perceptrons to deep networks³²⁹
* Neural Networks Architectures³³⁰
* A beginners guide to Machine Learning³³¹
* A guide on Time Series Prediction using LSTM³³²
* Convolutional Neural Networks in Python with Keras³³³
* History of Neural Network³³⁴
³²⁴http://www.aprendemachinelearning.com/crear-una-red-neuronal-en-python-desde-cero/
³²⁵https://medium.com/intuitionmachine/neurons-are-more-complex-than-what-we-have-imagined-b3dd00a1dcd3
³²⁶http://www.aprendemachinelearning.com/que-es-machine-learning/
³²⁷https://becominghuman.ai/cheat-sheets-for-ai-neural-networks-machine-learning-deep-learning-big-data-678c51b4b463
³²⁸http://neuralnetworksanddeeplearning.com/chap1.html#perceptrons
³²⁹https://www.toptal.com/machine-learning/an-introduction-to-deep-learning-from-perceptrons-to-deep-networks
³³⁰https://ml-cheatsheet.readthedocs.io/en/latest/architectures.html
³³¹https://www.ibm.com/developerworks/library/cc-beginner-guide-machine-learning-ai-cognitive/index.html
³³²https://blog.statsbot.co/time-series-prediction-using-recurrent-neural-networks-lstms-807fa6ca7f
³³³https://www.datacamp.com/community/tutorials/convolutional-neural-networks-python
³³⁴https://medium.com/@karthikeyana97/history-of-neural-network-d1333760f0c5
Aprendizaje Profundo: una Guía
rápida
Deep Learning y Redes Neuronales -sin código-
Explicaré brevemente en qué consiste el Deep Learning ó Aprendizaje Profundo utilizado en
Machine Learning describiendo sus componentes básicos.
Nos centraremos en Aprendizaje Profundo aplicando Redes Neuronales Artificiales³³⁵.
Explicaré cómo funciona el Deep Learning mediante un ejemplo hipotético de predicción sobre quién
ganará el próximo mundial de futbol. Utilizaremos aprendizaje supervisado mediante algoritmos de
Redes Neuronales Artificiales³³⁸. Para lograr las predicciones de los partidos de fútbol usaremos
como ejemplo las siguientes entradas:
Y podríamos tener muchísimas entradas más, como la puntuación media de los jugadores del equipo,
o el score que da la FIFA al equipo. Como en cada partido tenemos a 2 rivales, deberemos incluir
estos 6 datos de entrada por cada equipo, es decir, 6 entradas del equipo 1 y otras 6 del equipo 2
dando un total de 12 entradas. La predicción de salida será el resultado del partido: Local, Empate o
Visitante.
³³⁵http://www.aprendemachinelearning.com/breve-historia-de-las-redes-neuronales-artificiales/
³³⁶http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/#supervisado
³³⁷http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/#no_supervisado
³³⁸http://www.aprendemachinelearning.com/principales-algoritmos-usados-en-machine-learning/#red_neuronal
Aprendizaje Profundo: una Guía rápida 181
• La capa de entrada recibe los datos de entrada y los pasa a la primer capa oculta.
Aprendizaje Profundo: una Guía rápida 182
• Las capas ocultas realizarán cálculos matemáticos con nuestras entradas. Uno de los desafíos
al crear la Red Neuronal es decidir el número de capas ocultas y la cantidad de neuronas de
cada capa.
• La capa de Salida devuelve la predicción realizada. En nuestro caso de 3 resultados discretos
las salidas podrán ser “1 0 0” para Local, “0 1 0” para Empate y “0 0 1” para Visitante.
Imitando a las neuronas biológicas. cada Neurona tiene una Función de Activación³³⁹. Esta función
determinará si la suma de sus valores recibidos (previamente multiplicados por el peso de la
conexión) supera un umbral que hace que la neurona se active y dispare un valor hacia la siguiente
capa conectada. Hay diversas Funciones de Activación conocidas que se suelen utilizar en estas
redes. Cuando todas las capas finalizan de realizar sus cómputos, se llegará a la capa final con una
predicción. Por Ejemplo si nuestro modelo nos devuelve 0.6 0.25 0.15 está prediciendo que ganará
Local con 60% probabilidades, será Empate 25% o que gane Visitante 15%.
En nuestro ejemplo de “predicción de Partidos de Futbol para el próximo Mundial” deberemos crear
una base de datos con todos los resultados históricos de los Equipos de Fútbol en mundiales, en
partidos amistosos, en clasificatorios, los goles, las rachas a lo largo de los años, etc.
Para entrenar nuestra máquina, deberemos alimentarla con nuestro conjunto de datos de entrada y
comparar el resultado (local, empate, visitante) contra la predicción obtenida. Como nuestro modelo
fue inicializado con pesos aleatorios, y aún está sin entrenar, las salidas obtenidas seguramente
serán erróneas. Una vez que tenemos nuestro conjunto de datos, comenzaremos un proceso iterativo:
usaremos una función para comparar cuan bueno/malo fue nuestro resultado contra el resultado real.
Esta función es llamada “Función Coste³⁴⁰”. Idealmente queremos que nuestro coste sea cero, es
decir sin error (cuando el valor de la predicción es igual al resultado real del partido). A medida
que entrena el modelo irá ajustando los pesos de inter-conexiones de las neuronas de manera
automática hasta obtener buenas predicciones. A ese proceso de “ir y venir” por las capas de neuronas
se le conoce como BackPropagation. Más detalle a continuación.
Para minimizar la función de coste necesitaremos iterar por el conjunto de datos cientos de miles
de veces (ó más), por eso es tan importante contar con una gran capacidad de cómputo en
el ordenador en la que entrenamos la red. La actualización del valor de los pesos se realizará
automáticamente usando el Descenso de Gradiente.
Esta es parte de la magia del Aprendizaje Profundo “Automático”. Una vez que finalizamos de
entrenar nuestro Predictor de Partidos de Futbol del Mundial, sólo tendremos que alimentarlo con
los partidos que se disputarán y podremos saber quién ganará el Mundial.
Resumen
• El Aprendizaje Profundo utiliza Algoritmos de Redes Neuronales Artificiales que imitan el
comportamiento biológico del cerebro.
• Hay 3 tipos de Capas de Neuronas: de Entrada, Ocultas y de Salida.
• Las conexiones entre neuronas llevan asociadas un peso, que denota la importancia del valor
de entrada en esa relación.
• Las neuronas aplican una Función de Activación para Estandarizar su valor de salida a la
próxima capa de neuronas.
Aprendizaje Profundo: una Guía rápida 186
El proyecto
[
coche robot
](http://www.aprendemachinelearning.com/programa-un-coche-arduino-con-inteligencia-artificial/)
Este amigable coche robot Arduino³⁴⁵, será a quien le implantaremos nuestra red neuronal, para que
pueda conducir sólo, evitando los obstáculos!
³⁴²http://www.aprendemachinelearning.com/breve-historia-de-las-redes-neuronales-artificiales/
³⁴³http://www.aprendemachinelearning.com/programa-un-coche-arduino-con-inteligencia-artificial/
³⁴⁴http://neuralnetworksanddeeplearning.com/chap2.html
³⁴⁵http://www.aprendemachinelearning.com/programa-un-coche-arduino-con-inteligencia-artificial/
Crear una Red Neuronal en Python desde cero 188
Vamos a crear una red neuronal que conduzca un coche de juguete Arduino³⁴⁶ que más adelante
construiremos y veremos en el “mundo real”. Nuestros datos de entrada serán:
• Girar
– derecha 1 / izquierda -1
• Dirección
– avanzar 1 / retroceder -1
La velocidad del vehículo podría ser una salida más (por ejemplo disminuir la velocidad si nos
aproximamos a un objeto) y podríamos usar más sensores como entradas pero por simplificar
el modelo y su implementación mantendremos estas 2 entradas y 2 salidas. Para entrenar la red
tendremos las entradas y salidas que se ven en la tabla:
³⁴⁷
En la imagen anterior -y durante el ejemplo- usamos la siguiente notación en las neuronas:
1. O(j) Los pesos de las conexiones entre neuronas será una matriz que mapea la capa j a la j+1
2. Recordemos que utilizamos 1 neurona extra en la capa 1 y una neurona extra en la capa 2 a
modo de Bias³⁴⁸ -no están en la gráfica- para mejorar la precisión de la red neuronal, dandole
mayor “libertad algebraica”.
Funciones Sigmoide
Una de las razones para utilizar la función sigmoide -función Logística³⁵⁰- es por sus propiedades
matemáticas, en nuestro caso, sus derivadas. Cuando más adelante la red neuronal haga backpro-
pagation para aprender y actualizar los pesos, haremos uso de su derivada. En esta función puede
ser expresada como productos de f y 1-f . Entonces **f’(t) = f(t)(1 - f(t)). **Por ejemplo la función
tangente y su derivada arco-tangente se utilizan normalizadas, donde su pendiente en el origen es 1
y cumplen las propiedades.
³⁵¹ ç
Imagen de la Curva Logística Normalizada de Wikipedia
Resumiendo: tenemos una red; tenemos 2 entradas, éstas se multiplican por los pesos de las cone-
xiones y cada neurona en la capa oculta suma esos productos y les aplica la función de activación
para “emitir” un resultado a la siguiente conexión (concepto conocido en biología como sinapsis
química³⁵²).
Como bien sabemos, los pesos iniciales se asignan con valores entre -1 y 1 de manera
aleatoria. El desafío de este algoritmo, será que las neuronas aprendan por sí mismas a
ajustar el valor de los pesos para obtener las salidas correctas.
Fase 1: Propagar
Esta fase implica 2 pasos:
1.1 Hacer forward propagation de un patrón de entrenamiento (recordemos que es este es un
algoritmo supervisado³⁵⁴, y conocemos las salidas) para generar las activaciones de salida de la red.
1.2 Hacer backward propagation de las salidas (activación obtenida) por la red neuronal usando las
salidas “y” reales para generar los Deltas (error) de todas las neuronas de salida y de las neuronas
de la capa oculta.
³⁵⁵
En esta gráfica vemos cómo utilizamos el gradiente paso a paso para descender y minimizar el coste
total. Cada paso utilizará la Tasa de Aprendizaje -learning rate- que afectará la velocidad y calidad
de la red.
Deberemos repetir las fases 1 y 2 hasta que la performance de la red neuronal sea satisfactoria. Si
denotamos al error en el layer “l” como d(l) para nuestras neuronas de salida en layer 3 la activación
menos el valor actual será (usamos la forma vectorial):
d(3) = alayer3 - y
d(2) = OT2 d(3) . g’(zlayer2)
g’(zlayer2) = alayer2 . (1 - alayer2)
Al fin aparecieron las derivadas! Nótese que no tendremos delta para la capa 1, puesto que son los
valores X de entrada y no tienen error asociado. El valor del costo -que es lo que queremos minimizar-
de nuestra red será
J = alayer dlayer + 1
Usamos este valor y lo multiplicamos al learning rate antes de ajustar los pesos. Esto nos asegura
que buscamos el gradiente, iteración a iteración “apuntando” hacia el mínimo global.
1 import numpy as np
2
3 def sigmoid(x):
4 return 1.0/(1.0 + np.exp(-x))
5
6 def sigmoid_derivada(x):
7 return sigmoid(x)*(1.0-sigmoid(x))
8
9 def tanh(x):
10 return np.tanh(x)
11
12 def tanh_derivada(x):
13 return 1.0 - x**2
14
15
16 class NeuralNetwork:
17
18 def __init__(self, layers, activation='tanh'):
19 if activation == 'sigmoid':
20 self.activation = sigmoid
21 self.activation_prime = sigmoid_derivada
22 elif activation == 'tanh':
23 self.activation = tanh
24 self.activation_prime = tanh_derivada
25
26 # inicializo los pesos
27 self.weights = []
28 self.deltas = []
29 # capas = [2,3,2]
30 # rando de pesos varia entre (-1,1)
31 # asigno valores aleatorios a capa de entrada y capa oculta
32 for i in range(1, len(layers) - 1):
33 r = 2*np.random.random((layers[i-1] + 1, layers[i] + 1)) -1
34 self.weights.append(r)
35 # asigno aleatorios a capa de salida
36 r = 2*np.random.random( (layers[i] + 1, layers[i+1])) - 1
³⁵⁶https://github.com/jbagnato/machine-learning
Crear una Red Neuronal en Python desde cero 194
37 self.weights.append(r)
38
39 def fit(self, X, y, learning_rate=0.2, epochs=100000):
40 # Agrego columna de unos a las entradas X
41 # Con esto agregamos la unidad de Bias a la capa de entrada
42 ones = np.atleast_2d(np.ones(X.shape[0]))
43 X = np.concatenate((ones.T, X), axis=1)
44
45 for k in range(epochs):
46 i = np.random.randint(X.shape[0])
47 a = [X[i]]
48
49 for l in range(len(self.weights)):
50 dot_value = np.dot(a[l], self.weights[l])
51 activation = self.activation(dot_value)
52 a.append(activation)
53 # Calculo la diferencia en la capa de salida y el valor obtenido
54 error = y[i] - a[-1]
55 deltas = [error * self.activation_prime(a[-1])]
56
57 # Empezamos en el segundo layer hasta el ultimo
58 # (Una capa anterior a la de salida)
59 for l in range(len(a) - 2, 0, -1):
60 deltas.append(deltas[-1].dot(self.weights[l].T)*self.activation_prim\
61 e(a[l]))
62 self.deltas.append(deltas)
63
64 # invertir
65 # [level3(output)->level2(hidden)] => [level2(hidden)->level3(output)]
66 deltas.reverse()
67
68 # backpropagation
69 # 1. Multiplcar los delta de salida con las activaciones de entrada
70 # para obtener el gradiente del peso.
71 # 2. actualizo el peso restandole un porcentaje del gradiente
72 for i in range(len(self.weights)):
73 layer = np.atleast_2d(a[i])
74 delta = np.atleast_2d(deltas[i])
75 self.weights[i] += learning_rate * layer.T.dot(delta)
76
77 if k % 10000 == 0: print('epochs:', k)
78
79 def predict(self, x):
Crear una Red Neuronal en Python desde cero 195
80 ones = np.atleast_2d(np.ones(x.shape[0]))
81 a = np.concatenate((np.ones(1).T, np.array(x)), axis=0)
82 for l in range(0, len(self.weights)):
83 a = self.activation(np.dot(a, self.weights[l]))
84 return a
85
86 def print_weights(self):
87 print("LISTADO PESOS DE CONEXIONES")
88 for i in range(len(self.weights)):
89 print(self.weights[i])
90
91 def get_deltas(self):
92 return self.deltas
Y ahora creamos una red a nuestra medida, con 2 neuronas de entrada, 3 ocultas y 2 de salida.
Deberemos ir ajustando los parámetros de entrenamiento learning rate y la cantidad de iteraciones
“epochs” para obtener buenas predicciones.
La salidas obtenidas son: (comparar los valores “y” con los de “Network” )
Crear una Red Neuronal en Python desde cero 196
Como podemos ver son muy buenos resultados. Aquí podemos ver como el coste de la función se
va reduciendo y tiende a cero:
³⁵⁷
Y podemos ver los pesos obtenidos de las conexiones con nn.print_weights() pues estos valores
serán los que usaremos en la red final que en el próximo capítulo implementaremos en Arduino
para que un coche-robot conduzca sólo evitando obstáculos³⁵⁸.
Resumen
Creamos una red neuronal en pocas líneas de código Python:
En el próximo capitulo finalizaremos el proyecto al aplicar esta red que construimos en el mundo
real y comprobar si un coche Arduino será capaz de conducir³⁵⁹ por sí mismo y evitar obstáculos..!
³⁵⁷http://www.aprendemachinelearning.com/wp-content/uploads/2018/07/descenso-gradiente.png
³⁵⁸http://www.aprendemachinelearning.com/programa-un-coche-arduino-con-inteligencia-artificial/
³⁵⁹http://www.aprendemachinelearning.com/programa-un-coche-arduino-con-inteligencia-artificial/
Crear una Red Neuronal en Python desde cero 198
Recursos
• El código utilizado es una adaptación del original del BogoToBogo³⁶⁰ en donde se enseña la
función XOR.
• Pueden descargar el código de este artículo en un Jupyter Notebook aquí³⁶¹ o visualizar online³⁶²
ó pueden acceder a mi Github³⁶³.
³⁶⁰http://www.bogotobogo.com/python/python_Neural_Networks_Backpropagation_for_XOR_using_one_hidden_layer.php
³⁶¹http://www.aprendemachinelearning.com/wp-content/uploads/2018/07/Red_Neuronal_desde_cero.ipynb
³⁶²http://nbviewer.jupyter.org/github/jbagnato/machine-learning/blob/master/Red_Neuronal_desde_cero.ipynb
³⁶³https://github.com/jbagnato/machine-learning
Programa un coche Robot Arduino
que conduce con IA
El Machine Learning nos permitirá utilizar Redes Neuronales³⁶⁴ para que un coche Arduino
conduzca sólo evitando obstáculos.
³⁶⁴http://www.aprendemachinelearning.com/breve-historia-de-las-redes-neuronales-artificiales/
Programa un coche Robot Arduino que conduce con IA 200
³⁶⁵
Programa un coche Robot Arduino que conduce con IA 201
En un capítulo anterior³⁶⁶, creamos una red neuronal desde cero en Python. En este artículo
mejoraremos esa red y copiaremos sus pesos a una red con propagación hacia adelante en Arduino
que permitirá que el coche robot conduzca sólo sin chocar.
Aquí podemos ver el código Python Completo modificado de la Jupyter Notebook³⁶⁹. Y también
vemos la gráfica del coste, que disminuye a medida que se entrena tras 40.000 iteraciones.
³⁷⁰
¿¿No es impresionante cómo con apenas 9 datos de entrada podemos enseñar a un robot
a conducir??
El coche Arduino
En mi caso es un coche Arduino Elegoo Uno V3³⁷¹ de 4 motores. Si eres Maker, te resultará fácil
construir el tuyo o puede que ya tengas uno en casa para programarlo. El coche puede ser cualquier
otro, de hecho podría ser de 2 motores y modificando apenas la red funcionaría. En caso de querer
construirlo tu mismo explicaré brevemente los requerimientos.
Necesitaremos:
• Una placa Arduino Uno y una placa de expansión de IO
– o puede ser una placa Arduino Mega
• El controlador de motor L298N
³⁶⁹https://github.com/jbagnato/machine-learning/blob/master/Red_Neuronal_coche.ipynb
³⁷⁰http://www.aprendemachinelearning.com/wp-content/uploads/2018/08/grafica_coste40mil.png
³⁷¹https://www.amazon.es/gp/product/B077PZHM3T/ref=as_li_tl?ie=UTF8&tag=aprendeml-21&camp=3638&creative=24630&linkCode=
as2&creativeASIN=B077PZHM3T&linkId=163a6f15fc7e6f382f16ac50c6180ae2
Programa un coche Robot Arduino que conduce con IA 204
³⁷²
Montar el coche
Utilizaremos un Servo en la parte delantera del coche que moverá al sensor de distancia de izquierda
a derecha, a modo de radar, para detectar obstáculos.
Más allá de eso… es un coche! pondremos las 4 ruedas y las placas Arduino encima del chasis. (El
objetivo de este artículo es enseñar a programar una red neuronal en la IDE de Arduino)
³⁷²http://www.aprendemachinelearning.com/wp-content/uploads/2018/08/wire_connect.png
Programa un coche Robot Arduino que conduce con IA 205
³⁷⁴
³⁷⁵
Copiamos los pesos que obtenemos en la Jupyter Notebook de nuestra red neuronal en el código
Arduino, reemplazando las variables por los nuevos valores.
El código Arduino
El código Arduino controlará el servo motor con el sensor de distancia que se moverá de izquierda
a derecha y nos proveerá las entradas de la red: Distancia y Dirección(ó giro).
El resto, lo hará la red neuronal! En realidad, la red ya “aprendió” (en Python) es decir, sólo
hará multiplicaciones y sumas de los pesos para obtener salidas. Realizará el camino forward
propagation. Y las salidas controlarán directamente los 4 motores.
Hay código adicional para darle ciclos de tiempo a las ruedas a moverse (variable accionEnCurso) y
dar más o menos potencia a los motores al cambiar de dirección. Son relativamente pocas líneas de
código y logramos que la red neuronal conduzca el coche!
Nota: Para el movimiento del Servo motor se utiliza una librería “Servo” estándard.
Aquí vemos el código Arduino completo. Tal vez la parte más interesante sea la función conducir().
³⁷⁵http://www.aprendemachinelearning.com/wp-content/uploads/2018/08/copy_jupyter_arduino.gif
Programa un coche Robot Arduino que conduce con IA 207
44 digitalWrite(Trig, LOW);
45 delayMicroseconds(2);
46 digitalWrite(Trig, HIGH);
47 delayMicroseconds(20);
48 digitalWrite(Trig, LOW);
49 float Fdistance = pulseIn(Echo, HIGH);
50 Fdistance= Fdistance / 58;
51 return (int)Fdistance;
52 }
53
54 void setup() {
55 myservo.attach(3); // attach servo on pin 3 to servo object
56 Serial.begin(9600);
57 pinMode(Echo, INPUT);
58 pinMode(Trig, OUTPUT);
59 pinMode(IN1, OUTPUT);
60 pinMode(IN2, OUTPUT);
61 pinMode(IN3, OUTPUT);
62 pinMode(IN4, OUTPUT);
63 pinMode(ENA, OUTPUT);
64 pinMode(ENB, OUTPUT);
65 stop();
66 myservo.write(90); //posicion inicial en el centro
67 delay(500);
68 }
69
70 unsigned long previousMillis = 0; // para medir ciclos de tiempo
71 const long interval = 25; // intervalos cada x milisegundos
72 int grados_servo = 90; // posicion del servo que mueve el sensor \
73 ultrasonico
74 bool clockwise = true; // sentido de giro del servo
75 const long ANGULO_MIN = 30;
76 const long ANGULO_MAX = 150;
77 double ditanciaMaxima = 50.0; // distancia de lejania desde la que empieza\
78 a actuar la NN
79 int incrementos = 9; // incrementos por ciclo de posicion del ser\
80 vo
81 int accionEnCurso = 1; // cantidad de ciclos ejecutando una accion
82 int multiplicador = 1000/interval; // multiplica la cant de ciclos para dar tie\
83 mpo a que el coche pueda girar
84 const int SPEED = 100; // velocidad del coche de las 4 ruedas a la \
85 vez.
86
Programa un coche Robot Arduino que conduce con IA 209
87 void loop() {
88 unsigned long currentMillis = millis();
89
90 if (currentMillis - previousMillis >= interval) {
91 previousMillis = currentMillis;
92
93 /******************************************************************
94 MANEJAR GIRO de SERVO
95 ******************************************************************/
96 if(grados_servo<=ANGULO_MIN || grados_servo>=ANGULO_MAX){
97 clockwise=!clockwise; // cambio de sentido
98 grados_servo = constrain(grados_servo, ANGULO_MIN, ANGULO_MAX);
99 }
100 if(clockwise)
101 grados_servo=grados_servo+incrementos;
102 else
103 grados_servo=grados_servo-incrementos;
104
105 if(accionEnCurso>0){
106 accionEnCurso=accionEnCurso-1;
107 }else{
108 /******************************************************************
109 LLAMAMOS a la FUNCION DE CONDUCCION
110 ******************************************************************/
111 conducir();
112 }
113 myservo.write(grados_servo);
114 }
115
116 }
117
118 //USA LA RED NEURONAL YA ENTRENADA
119 void conducir()
120 {
121 double TestInput[] = {0, 0,0};
122 double entrada1=0,entrada2=0;
123
124 /******************************************************************
125 OBTENER DISTANCIA DEL SENSOR
126 ******************************************************************/
127 double distance = double(Distance_test());
128 distance= double(constrain(distance, 0.0, ditanciaMaxima));
129 entrada1= ((-2.0/ditanciaMaxima)*double(distance))+1.0; //uso una funcion li\
Programa un coche Robot Arduino que conduce con IA 210
216
217 }
El Coche en Acción!
Resumen
Aplicamos Machine Learning y sus redes neuronales a un objeto del mundo real y vimos cómo
funciona, haciendo que el coche evite obstáculos y tome las decisiones por sí mismo, sin haberle
dado instrucciones ni código explícito.
Mejoras a Futuro
Tengamos en cuenta que estamos teniendo como entradas los datos proporcionados por un sólo
sensor de distancia y un servo motor que nos indica si está a izquierda o derecha. Podríamos tener
más sensores de distancia, infrarrojos, medir velocidad, luz, sonido… en fin. Si tuviéramos que
programar “manualmente” ese algoritmo, tendría una complejidad enorme y sería muy difícil de
mantener o modificar. En cambio, hacer que una red neuronal aprenda sería muy sencillo. Tan sólo
agregaríamos features (columnas) a nuestro código y volveríamos a entrenar nuevamente la red.
Voila!. Copiar y pegar los pesos obtenidos en Arduino, y nuestro coche tendría la inteligencia de
manejarse por sí mismo nuevamente.
Recursos adicionales
• Artículo anterior, donde se explica con mayor detalle cómo se crea la Red Neuronal³⁷⁷
• Descarga el código Python con la nueva Red Neuronal³⁷⁸
• Descarga el código Arduino³⁷⁹
• Si quieres comprar el mismo coche Arduino que yo, click aqui: ELEGOO UNO Proyecto Kit
de Coche Robot Inteligente V3.0³⁸⁰. Te recuerdo que puedes construir tu propio coche Arduino
si te das maña y utilizar este código. De hecho puede funcionar con un coche de 2 motores
modificando las salidas de la red, en vez de tener 4, tener 2.
• Aquí puedes ver a otro Maker que hizo un coche Arduino con Red Neuronal que escapa de la
luz.³⁸¹
³⁷⁶https://www.youtube.com/watch?v=_b2EdqjKTmU&feature=emb_logo
³⁷⁷http://www.aprendemachinelearning.com/crear-una-red-neuronal-en-python-desde-cero/
³⁷⁸https://github.com/jbagnato/machine-learning/blob/master/Red_Neuronal_coche.ipynb
³⁷⁹https://github.com/jbagnato/machine-learning/tree/master/NN_Obstacle_Car
³⁸⁰https://www.amazon.es/gp/product/B077PZHM3T/ref=as_li_tl?ie=UTF8&tag=aprendeml-21&camp=3638&creative=24630&linkCode=
as2&creativeASIN=B077PZHM3T&linkId=163a6f15fc7e6f382f16ac50c6180ae2
³⁸¹https://www.instructables.com/id/Arduino-Neural-Network-Robot/
Una sencilla Red Neuronal con Keras
y Tensorflow
Crearemos una red neuronal artificial³⁸² muy sencilla en Python con Keras y Tensorflow para com-
prender su uso. Implementaremos la compuerta XOR³⁸³ y compararemos las ventajas del aprendizaje
automático frente a la programación tradicional.
• XOR(0,0) = 0
• XOR(0,1) = 1
• XOR(1,0) = 1
• XOR(1,1) = 0
1 import numpy as np
2 from keras.models import Sequential
3 from keras.layers.core import Dense
4
5 # cargamos las 4 combinaciones de las compuertas XOR
6 training_data = np.array([[0,0],[0,1],[1,0],[1,1]], "float32")
7
8 # y estos son los resultados que se obtienen, en el mismo orden
9 target_data = np.array([[0],[1],[1],[0]], "float32")
10
11 model = Sequential()
12 model.add(Dense(16, input_dim=2, activation='relu'))
13 model.add(Dense(1, activation='sigmoid'))
14
15 model.compile(loss='mean_squared_error',
16 optimizer='adam',
17 metrics=['binary_accuracy'])
18
19 model.fit(training_data, target_data, epochs=1000)
20
21 # evaluamos el modelo
22 scores = model.evaluate(training_data, target_data)
23
24 print("\n%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))
25 print (model.predict(training_data).round())
³⁸⁸https://keras.io
³⁸⁹https://www.tensorflow.org
Una sencilla Red Neuronal con Keras y Tensorflow 215
1 import numpy as np
2 from keras.models import Sequential
3 from keras.layers.core import Dense
Utilizaremos numpy para el manejo de arrays. De Keras importamos el tipo de modelo Sequential y
el tipo de capa Dense que es la “normal”. Creamos los arrays de entrada y salida.
Como se puede ver son las cuatro entradas posibles de la función XOR [0,0], [0,1], [1,0],[1,1] y sus
cuatro salidas: 0, 1, 1, 0. Ahora crearemos la arquitectura de nuestra red neuronal³⁹⁰:
1 model = Sequential()
2 model.add(Dense(16, input_dim=2, activation='relu'))
3 model.add(Dense(1, activation='sigmoid'))
Primero creamos un modelo vació de tipo Sequential. Este modelo indica que crearemos una
serie de capas de neuronas secuenciales, “una delante de otra”. Agregamos dos capas Dense con
“model.add()”. Realmente serán 3 capas, pues al poner input_dim=2 estamos definiendo la capa
de entrada con 2 neuronas (para nuestras entradas de la función XOR) y la primer capa oculta
(hidden) de 16 neuronas. Como función de activación utilizaremos “relu” que sabemos que da buenos
resultados. Podría ser otra función, esto es un mero ejemplo, y según la implementación de la red que
haremos, deberemos variar la cantidad de neuronas, capas y sus funciones de activación. Agregamos
una capa con 1 neurona de salida y función de activación sigmoid.
³⁹¹
A Entrenar la red!
Antes de de entrenar la red haremos unos ajustes de nuestro modelo:
1 model.compile(loss='mean_squared_error',
2 optimizer='adam',
3 metrics=['binary_accuracy'])
Con esto indicamos el tipo de pérdida (loss) que utilizaremos, el “optimizador” de los pesos de las
conexiones de las neuronas y las métricas que queremos obtener. Ahora sí que entrenaremos la red:
Indicamos con model.fit() las entradas y sus salidas y la cantidad de iteraciones de aprendizaje
(epochs) de entrenamiento. Este es un ejemplo sencillo, pero recuerda que en modelos más grandes
y complejos, necesitarán más iteraciones y a la vez será más lento el entrenamiento.
³⁹¹http://www.aprendemachinelearning.com/wp-content/uploads/2018/05/RedNeuronalXor.png
Una sencilla Red Neuronal con Keras y Tensorflow 217
1 Epoch 1/1000
2 4/4 [==============================] - 0s 43ms/step - loss: 0.2634 - binary_accuracy\
3 : 0.5000
4 Epoch 2/1000
5 4/4 [==============================] - 0s 457us/step - loss: 0.2630 - binary_accurac\
6 y: 0.2500
con esto vemos que la primer iteración “tuvo algo de suerte” y acierto la mitad de las salidas (0.5)
pero a partir de la segunda, sólo acierta 1 de cada 4 (0.25). Luego en la “epoch” 24 recupera el 0.5 de
aciertos, ya no es “por suerte”, si no por haber ajustado correctamente los pesos de la red.
1 Epoch 24/1000
2 4/4 [==============================] - 0s 482us/step - loss: 0.2549 - binary_accurac\
3 y: 0.5000
4
5 Epoch 107/1000
6 4/4 [==============================] - 0s 621us/step - loss: 0.2319 - binary_accurac\
7 y: 0.7500
8
9 Epoch 169/1000
10 4/4 [==============================] - 0s 1ms/step - loss: 0.2142 - binary_accuracy:\
11 1.0000
Y -en mi caso- en la iteración 107 aumenta los aciertos al 0,75 (son 3 de 4) y en la iteración 169
logra el 100% de aciertos y se mantiene así hasta finalizar. Como los pesos iniciales de la red son
aleatorios, puede que los resultados que tengas en tu ordenador sean levemente distintas en cuanto
a las iteraciones, pero llegarás a la “precisión binaria” (binara_accuracy) de 1.0.
Evaluamos y Predecimos
Primero evaluamos el modelo
Y vemos que tuvimos un 100% de precisión (recordemos lo trivial de este ejemplo). Y hacemos las 4
predicciones posibles de XOR, pasando nuestras entradas:
1 print (model.predict(training_data).round())
En este ejemplo puedes intentar variar la cantidad de neuronas de entrada, probar con 8 o con
32 y ver qué resultados obtienes. Revisar si necesitas más o menos iteraciones para alcanzar el
100% de aciertos. Realmente podemos apreciar que hay muchos meta-parámetros para ajustar. Si
hiciéramos la combinatoria de todos ellos, tendríamos una cantidad enorme de ajustes posibles. Y
queda sobretodo en ti, decidir esos parámetros y ajustarlos.
14 json_file.close()
15 loaded_model = model_from_json(loaded_model_json)
16 # cargar pesos al nuevo modelo
17 loaded_model.load_weights("model.h5")
18 print("Cargado modelo desde disco.")
19
20 # Compilar modelo cargado y listo para usar.
21 loaded_model.compile(loss='mean_squared_error', optimizer='adam', metrics=['binary_a\
22 ccuracy'])
Vemos que es una función con “4 ifs” que evalúa cada condición (se podría mejorar, lo sé). ¿Pero
que pasaría si en vez de 2 entradas tuviéramos más parámetros?… pues seguramente la cantidad
de “ifs” anidados aumentaría creando un código caótico y propenso a errores, difícil de mantener.
Piénsalo un momento. No quiere decir que haya que reemplazar todo el código del mundo con redes
neuronales, pero sí pensar en qué casos las redes neuronales nos brindan una flexibilidad y un poder
de predicción increíbles -y que justifican el tiempo de desarrollo-.
Una sencilla Red Neuronal con Keras y Tensorflow 220
Resumen
Hemos creado nuestra primera red neuronal artificial con 3 capas para recrear la función XOR.
Utilizamos la librería Keras -y a través de ella, Tensorflow como backend- y creamos el modelo,
entrenamos los datos y obtuvimos un buen resultado. Este es el puntapié inicial para seguir viendo
diversas arquitecturas de Redes Neuronales e ir aprendiendo poco a poco con Python.
Código Python
Pueden ver el código en mi cuenta de GitHub aqui³⁹². O pueden descargar el código de la Notebook
Jupyter desde aqui³⁹³.
1. Es dependiente del Tiempo. Esto rompe con el requerimiento que tiene la regresión lineal⁴⁰⁰
de que sus observaciones sean independientes.
2. Suelen tener algún tipo de estacionalidad, ó de tendencias a crecer ó decrecer. Pensemos en
cuánto más producto vende una heladería en sólo 4 meses al año que en el resto de estaciones.
Creo que con eso ya se dan una idea :) Como también pueden entrever, las series temporales pueden
ser de 1 sóla variable, ó de múltiples.
Vamos a comenzar con la práctica, cargando un dataset que contiene información de casi 2 años de
ventas diarias de productos. Los campos que contiene son fecha y la cantidad de unidades vendidas.
³⁹⁸http://www.aprendemachinelearning.com/una-sencilla-red-neuronal-en-python-con-keras-y-tensorflow/
³⁹⁹http://www.aprendemachinelearning.com/regresion-lineal-en-espanol-con-python/
⁴⁰⁰http://www.aprendemachinelearning.com/regresion-lineal-en-espanol-con-python/
Pronóstico de Series Temporales con Redes Neuronales 222
1 import pandas as pd
2 import numpy as np
3 import matplotlib.pylab as plt
4 %matplotlib inline
5 plt.rcParams['figure.figsize'] = (16, 9)
6 plt.style.use('fast')
7
8 from keras.models import Sequential
9 from keras.layers import Dense,Activation,Flatten
10 from sklearn.preprocessing import MinMaxScaler
11
12 df = pd.read_csv('time_series.csv', parse_dates=[0], header=None,index_col=0, squee\
13 ze=True,names=['fecha','unidades'])
14 df.head()
⁴⁰¹http://www.aprendemachinelearning.com/category/practica/
⁴⁰²http://www.aprendemachinelearning.com/instalar-ambiente-de-desarrollo-python-anaconda-para-aprendizaje-automatico/
⁴⁰³https://keras.io
⁴⁰⁴https://www.tensorflow.org
⁴⁰⁵https://github.com/jbagnato/machine-learning/blob/master/Series_Temporales_con_RRNN.ipynb
⁴⁰⁶https://raw.githubusercontent.com/jbagnato/machine-learning/master/time_series.csv
⁴⁰⁷https://raw.githubusercontent.com/jbagnato/machine-learning/master/time_series.csv
Pronóstico de Series Temporales con Redes Neuronales 223
1 fecha
2 2017-01-02 236
3 2017-01-03 237
4 2017-01-04 290
5 2017-01-05 221
6 2017-01-07 128
7 Name: unidades, dtype: int64
Notemos una cosa antes de seguir: el dataframe que cargamos con pandas tiene como Indice
nuestra primera columna con las fechas. Esto es para que nos permita hacer filtrados por fecha
directamente y algunas operaciones especiales.
Por ejemplo, podemos ver de qué fechas tenemos datos con:
1 print(df.index.min())
2 print(df.index.max())
1 2017-01-02 00:00:00
2 2018-11-30 00:00:00
Presumiblemente tenemos las ventas diarias de 2017 y de 2018 hasta el mes de noviembre. Y ahora
veamos cuantas muestras tenemos de cada año:
1 print(len(df['2017']))
2 print(len(df['2018']))
1 315
2 289
Como este comercio cierra los domingos, vemos que de 2017 no tenemos 365 días como erróneamente
podíamos presuponer. Y en 2018 nos falta el último mes… que será lo que trataremos de pronosticar.
Visualización de datos
Veamos algunas gráficas sobre los datos que tenemos. Pero antes… aprovechemos los datos estadís-
ticos que nos brinda pandas con describe()
1 df.describe()
Pronóstico de Series Temporales con Redes Neuronales 224
1 count 604.000000
2 mean 215.935430
3 std 75.050304
4 min 51.000000
5 25% 171.000000
6 50% 214.000000
7 75% 261.250000
8 max 591.000000
9 Name: unidades, dtype: float64
Son un total de 604 registros, la media de venta de unidades es de 215 y un desvío de 75, es decir que
por lo general estaremos entre 140 y 290 unidades.
De hecho aprovechemos el tener indice de fechas con pandas y saquemos los promedios mensuales:
1 meses =df.resample('M').mean()
2 meses
1 fecha
2 2017-01-31 203.923077
3 2017-02-28 184.666667
4 2017-03-31 182.964286
5 2017-04-30 198.960000
6 2017-05-31 201.185185
7 2017-06-30 209.518519
8 2017-07-31 278.923077
9 2017-08-31 316.000000
10 2017-09-30 222.925926
11 2017-10-31 207.851852
12 2017-11-30 185.925926
13 2017-12-31 213.200000
14 2018-01-31 201.384615
15 2018-02-28 190.625000
16 2018-03-31 174.846154
17 2018-04-30 186.000000
18 2018-05-31 190.666667
19 2018-06-30 196.037037
20 2018-07-31 289.500000
21 2018-08-31 309.038462
22 2018-09-30 230.518519
23 2018-10-31 209.444444
24 2018-11-30 184.481481
25 Freq: M, Name: unidades, dtype: float64
Pronóstico de Series Temporales con Redes Neuronales 225
1 plt.plot(meses['2017'].values)
2 plt.plot(meses['2018'].values)
⁴⁰⁸
Vemos que en 2017 (en azul) tenemos un inicio de año con un descenso en la cantidad de unidades,
luego comienza a subir hasta la llegada del verano europeo en donde en los meses junio y julio
tenemos la mayor cantidad de ventas. Finalmente vuelve a disminuir y tiene un pequeño pico en
diciembre con la Navidad.
También vemos que 2018 (naranja) se comporta prácticamente igual. Es decir que pareciera que
tenemos una estacionalidad. Por ejemplo podríamos aventurarnos a pronosticar que “el verano de
2019 también tendrá un pico de ventas”.
Veamos la gráfica de ventas diarias (en unidades) en junio y julio
1 verano2017 = df['2017-06-01':'2017-09-01']
2 plt.plot(verano2017.values)
3 verano2018 = df['2018-06-01':'2018-09-01']
4 plt.plot(verano2018.values)
⁴⁰⁸http://www.aprendemachinelearning.com/wp-content/uploads/2019/02/vtas_mensual.png
Pronóstico de Series Temporales con Redes Neuronales 226
⁴⁰⁹
⁴¹²
Pues nosotros que somos unos alumnos tan avanzados y aplicados utilizaremos Machine Learning:
una red neuronal⁴¹³ para hacer el pronóstico. Curiosamente crear esta red es algo relativamente
sencillo, y en poco tiempo estaremos usando un modelo de lo más moderno para hacer el pronóstico.
Lo que haremos es alterar nuestro flujo de entrada del archivo csv que contiene una columna con las
unidades despachadas, y lo convertiremos en varias columnas. *¿Y porqué hacer esto? *En realidad
lo que haremos es tomar nuestra serie temporal y la convertiremos en un “problema de tipo su-
pervisado⁴¹⁵“ para poder alimentar nuestra red neuronal y poder entrenarla con backpropagation⁴¹⁶
(“como es habitual”). Para hacerlo, debemos tener unas entradas y unas salidas para entrenar al
modelo.
Lo que haremos -en este ejemplo- es tomar los 7 días previos para “obtener” el octavo. Podríamos
intentar entrenar a la red con 2, ó 3 días. O también podríamos tener 1 sola salida, ó hasta “atrevernos”
intentar predecir más de un “día futuro”. Eso lo dejo a ustedes cómo actividad extra. Pero entonces
quedémonos con que:
• Entradas: serán “7 columnas” que representan las ventas en unidades de los 7 días anteriores.
• Salida: El valor del “8vo día”. Es decir, las ventas (en unids) de ese día.
Para hacer esta transformación usaré una función llamada series_to_supervised() creada y explicada
en este blog⁴¹⁷. (La verás en el código, a continuación)
Antes de usar la función, utilizamos el MinMaxScaler⁴¹⁸ para transformar el rango de nuestros
valores entre -1 y 1 (pues sabemos que a nuestra red neuronal, le favorece para realizar los cálculos).
Entonces aqui vemos cómo queda nuestro set de datos de entrada.
1 PASOS=7
2
3 # convert series to supervised learning
4 def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
5 n_vars = 1 if type(data) is list else data.shape[1]
6 df = pd.DataFrame(data)
7 cols, names = list(), list()
8 # input sequence (t-n, ... t-1)
9 for i in range(n_in, 0, -1):
10 cols.append(df.shift(i))
11 names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
12 # forecast sequence (t, t+1, ... t+n)
13 for i in range(0, n_out):
14 cols.append(df.shift(-i))
⁴¹⁵http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/#supervisado
⁴¹⁶http://neuralnetworksanddeeplearning.com/chap2.html
⁴¹⁷https://machinelearningmastery.com/convert-time-series-supervised-learning-problem-python/
⁴¹⁸https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MinMaxScaler.html
Pronóstico de Series Temporales con Redes Neuronales 229
15 if i == 0:
16 names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
17 else:
18 names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
19 # put it all together
20 agg = pd.concat(cols, axis=1)
21 agg.columns = names
22 # drop rows with NaN values
23 if dropnan:
24 agg.dropna(inplace=True)
25 return agg
26
27 # load dataset
28 values = df.values
29 # ensure all data is float
30 values = values.astype('float32')
31 # normalize features
32 scaler = MinMaxScaler(feature_range=(-1, 1))
33 values=values.reshape(-1, 1) # esto lo hacemos porque tenemos 1 sola dimension
34 scaled = scaler.fit_transform(values)
35 # frame as supervised learning
36 reframed = series_to_supervised(scaled, PASOS, 1)
37 reframed.head()
⁴¹⁹
Usaremos como entradas las columnas encabezadas como var1(t-7) a (t-1) y nuestra salida (lo que
sería el valor “Y” de la función) será el var1(t) -la última columna-.
“mezclar” los datos de entrada, es que en este caso nos importa mantener el orden en el que
alimentaremos la red. Por lo tanto, haremos una subdivisión de los primeros 567 días consecutivos
para entrenamiento de la red y los siguientes 30 para su validación. Esta es una proporción que elegí
yo, y que me pareció conveniente, pero definitivamente, puede no ser la óptima (queda propuesto
al lector, variar esta proporción por ejemplo a 80-20 y comparar resultados )
Hemos transformado la entrada en un arreglo con forma (567,1,7) esto al castellano significa algo
así como “567 entradas con vectores de 1x7”.
La arquitectura de la red neuronal será:
⁴²⁰https://es.wikipedia.org/wiki/Tangente_hiperb%C3%B3lica
⁴²¹https://www.quora.com/Can-you-explain-basic-intuition-behind-ADAM-a-method-for-stochastic-optimization
⁴²²https://www.statisticshowto.datasciencecentral.com/absolute-error/
⁴²³https://medium.com/human-in-a-machine-world/mae-and-rmse-which-metric-is-better-e60ac3bde13d
Pronóstico de Series Temporales con Redes Neuronales 231
1 def crear_modeloFF():
2 model = Sequential()
3 model.add(Dense(PASOS, input_shape=(1,PASOS),activation='tanh'))
4 model.add(Flatten())
5 model.add(Dense(1, activation='tanh'))
6 model.compile(loss='mean_absolute_error',optimizer='Adam',metrics=["mse"])
7 model.summary()
8 return model
Entrenamiento y Resultados
Veamos cómo se comporta nuestra máquina al cabo de 40 épocas.
1 EPOCHS=40
2
3 model = crear_modeloFF()
4
5 history=model.fit(x_train,y_train,epochs=EPOCHS,validation_data=(x_val,y_val),batch_\
6 size=PASOS)
En pocos segundos vemos una reducción del valor de pérdida tanto del set de entrenamiento como
del de validación.
1 Epoch 40/40
2 567/567 [==============================] - 0s 554us/step - loss: 0.1692 - mean_squar\
3 ed_error: 0.0551 - val_loss: 0.1383 - val_mean_squared_error: 0.03
1 results=model.predict(x_val)
2 plt.scatter(range(len(y_val)),y_val,c='g')
3 plt.scatter(range(len(results)),results,c='r')
4 plt.title('validate')
5 plt.show()
Pronóstico de Series Temporales con Redes Neuronales 232
⁴²⁴En
la gráfica vemos que los puntitos verdes intentan aproximarse a los rojos. Cuanto más cerca ó
superpuestos mejor. TIP: Si aumentamos la cantidad de EPOCHS mejora cada vez más.
Veamos y comparemos también cómo disminuye el LOSS tanto en el conjunto de train como el de
Validate, esto es bueno ya que indica que el modelo está aprendiendo. A su vez pareciera no haber
overfitting⁴²⁵, pues las curvas de train y validate son distintas.
⁴²⁴http://www.aprendemachinelearning.com/wp-content/uploads/2019/02/RN_Validation_plot.png
⁴²⁵http://www.aprendemachinelearning.com/que-es-overfitting-y-underfitting-y-como-solucionarlo/
Pronóstico de Series Temporales con Redes Neuronales 233
⁴²⁶
1 ultimosDias = df['2018-11-16':'2018-11-30']
2 ultimosDias
1 fecha
2 2018-11-16 152
3 2018-11-17 111
4 2018-11-19 207
5 2018-11-20 206
6 2018-11-21 183
7 2018-11-22 200
8 2018-11-23 187
9 2018-11-24 189
10 2018-11-25 76
⁴²⁶http://www.aprendemachinelearning.com/wp-content/uploads/2019/02/visualice_loss.png
⁴²⁷http://www.aprendemachinelearning.com/7-pasos-machine-learning-construir-maquina/
Pronóstico de Series Temporales con Redes Neuronales 234
11 2018-11-26 276
12 2018-11-27 220
13 2018-11-28 183
14 2018-11-29 251
15 2018-11-30 189
16 Name: unidades, dtype: int64
Y ahora seguiremos el mismo preprocesado de datos que hicimos para el entrenamiento: escalando
los valores, llamando a la función series_to_supervised pero esta vez sin incluir la columna de salida
“Y” pues es la que queremos hallar. Por eso, verán en el código que hacemos drop() de la última
columna.
1 values = ultimosDias.values
2 values = values.astype('float32')
3 # normalize features
4 values=values.reshape(-1, 1) # esto lo hacemos porque tenemos 1 sola dimension
5 scaled = scaler.fit_transform(values)
6 reframed = series_to_supervised(scaled, PASOS, 1)
7 reframed.drop(reframed.columns[[7]], axis=1, inplace=True)
8 reframed.head(7)
⁴²⁸
De este conjunto “ultimosDias” tomamos sólo la última fila, pues es la que correspondería a la última
semana de noviembre y la dejamos en el formato correcto para la red neuronal con reshape:
⁴²⁸http://www.aprendemachinelearning.com/wp-content/uploads/2019/02/set_test_para_pronostico.png
Pronóstico de Series Temporales con Redes Neuronales 235
1 values = reframed.values
2 x_test = values[6:, :]
3 x_test = x_test.reshape((x_test.shape[0], 1, x_test.shape[1]))
4 x_test
Ahora crearemos una función para ir “rellenando” el desplazamiento que hacemos por cada pre-
dicción. Esto es porque queremos predecir los 7 primeros días de diciembre. Entonces para el 1
de diciembre, ya tenemos el set con los últimos 7 días de noviembre. Pero para pronosticar el 2
de diciembre necesitamos los 7 días anteriores que INCLUYEN al 1 de diciembre y ese valor, lo
obtenemos en nuestra predicción anterior. Y así hasta el 7 de diciembre.
1 def agregarNuevoValor(x_test,nuevoValor):
2 for i in range(x_test.shape[2]-1):
3 x_test[0][0][i] = x_test[0][0][i+1]
4 x_test[0][0][x_test.shape[2]-1]=nuevoValor
5 return x_test
6
7 results=[]
8 for i in range(7):
9 parcial=model.predict(x_test)
10 results.append(parcial[0])
11 print(x_test)
12 x_test=agregarNuevoValor(x_test,parcial[0])
Ya casi lo tenemos… Ahora las predicciones están en el dominio del -1 al 1 y nosotros lo queremos
en nuestra escala “real” de unidades vendidas. Entonces vamos a “re-transformar” los datos con el
objeto “scaler” que creamos antes.
1 array([[174.48904094],
2 [141.26934129],
3 [225.49292353],
4 [203.73262324],
5 [177.30941712],
6 [208.1552254 ],
7 [175.23698644]])
Ya podemos crear un nuevo DataFrame Pandas por si quisiéramos guardar un nuevo csv con el
pronóstico. Y lo visualizamos.
1 prediccion1SemanaDiciembre = pd.DataFrame(inverted)
2 prediccion1SemanaDiciembre.columns = ['pronostico']
3 prediccion1SemanaDiciembre.plot()
4 prediccion1SemanaDiciembre.to_csv('pronostico.csv')
Resumen
Durante este nuevo capítulo del aprendizaje automático⁴³⁰, diferenciamos lo que son las Series
Temporales y su predicción de los problemas de Regresión⁴³¹. Aprovechamos la capacidad de las
⁴²⁹http://www.aprendemachinelearning.com/wp-content/uploads/2019/02/pronostico_unidades.png
⁴³⁰http://www.aprendemachinelearning.com/que-es-machine-learning/
⁴³¹http://www.aprendemachinelearning.com/regresion-lineal-en-espanol-con-python/
Pronóstico de Series Temporales con Redes Neuronales 237
redes neuronales⁴³² de generalizar⁴³³ y lograr predecir ventas futuras. Uno de los pasos más impor-
tantes, al realizar el pre procesado, consiste en convertir nuestra serie en un modelo de aprendizaje
supervisado⁴³⁴, donde tenemos valores de entrada y salida, para poder entrenar la red. Y finalizamos
realizando pronóstico de una semana utilizando la red neuronal creada.
Propongo al lector hacer diversas pruebas para mejorar las predicciones, alterando parámetros del
ejercicio:
El próximo capítulo retoma este ejercicio pero aplicando Embeddings que puede mejorar la precisión
de las predicciones poniendo en juego el día de la semana y mes que estamos pronosticando,
considerándolos como datos adicionales de entrada a la red neuronal para preservar mejor la
estacionalidad.
NOTA 1: recordemos que el futuro es IMPREDECIBLE… por lo que debo decir al Científico de datos:
cuidado sobre todo si debemos predecir resultados de series con comportamiento errático, como los
valores de la bolsa! y también cautela en asuntos sensibles sobretodo relacionados con la salud.
NOTA 2: Debo confesar que inicialmente implementé el ejercicio utilizando Redes Neuronales
Recurrentes, de tipo LSTM pero obtuve pésimos resultados… encontré mucho mejor performante
a nuestras queridas “redes neuronales tradicionales” MLP.
Recursos Adicionales
• Acceder a la Jupyter Notebook con el ejercicio completo⁴³⁵ (y siempre algún Bonus Track) en
Github. (Si te falla el enlace, prueba con ESTE⁴³⁶)
• Descargar el archivo de entrada csv ⁴³⁷con la serie temporal usada en el ejercicio
• Herramientas para valorar y mejorar el modelo: Interpretación de modelos de ML⁴³⁸
⁴⁴¹https://towardsdatascience.com/time-series-analysis-tutorial-using-financial-data-4d1b846489f9
⁴⁴²https://www.analyticsvidhya.com/blog/2016/02/time-series-forecasting-codes-python/
Pronóstico de Ventas con Redes
Neuronales (Parte 2)
Mejora del modelo de Series Temporales con Múltiples
Variables y Embeddings
Este capítulo es la continuación de “Pronóstico de Series Temporales con Redes Neuronales en
Python⁴⁴³” en donde vimos cómo a partir de un archivo de entrada con las unidades vendidas
por una empresa durante años anteriores, podíamos estimar las ventas de la próxima semana.
Continuaremos a partir de ese modelo -por lo que te recomiendo leer antes de continuar- y haremos
propuestas para mejorar la predicción.
• Un primer modelo tomando la fecha como nueva variable de entrada valiosa y que aporta
datos.
⁴⁴³http://www.aprendemachinelearning.com/pronostico-de-series-temporales-con-redes-neuronales-en-python/
⁴⁴⁴http://www.aprendemachinelearning.com/pronostico-de-series-temporales-con-redes-neuronales-en-python/
⁴⁴⁵http://www.aprendemachinelearning.com/breve-historia-de-las-redes-neuronales-artificiales/
⁴⁴⁶http://www.aprendemachinelearning.com/7-pasos-machine-learning-construir-maquina/
⁴⁴⁷http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/#supervisado
⁴⁴⁸http://www.aprendemachinelearning.com/aprendizaje-profundo-una-guia-rapida/
Pronóstico de Ventas con Redes Neuronales (Parte 2) 240
• Un segundo modelo también usando la fecha como variable adicional, pero utilizándola con
Embeddings… y a ver si mejora el pronóstico.
Por lo tanto explicaremos lo qué son los embeddings utilizados en variables categóricas (se utiliza
mucho en problemas de Procesamiento del Lenguaje Natural NLP⁴⁴⁹ para modelar).
Para estos modelos propuestos haremos la transformación a “problema de aprendizaje supervi-
sado”. Para ello usaremos la misma función series_to_supervised() de la web machinelearningmas-
tery⁴⁵⁰ como en el artículo anterior.
decir que “diciembre valga más que agosto”. Y de hecho, sabemos en la práctica para este ejercicio,
que realmente en julio y agosto, es cuando más aumentan las ventas. Para intentar resolver esta
problemática, es que aparecen los Embeddings.
En
este caso “simplificado” los Embeddings se pueden ver como vectores de coordenadas (x,y) que
acercan películas similares en 2 dimensiones y a su vez quedan distanciadas de Identificadores
opuestos.
Conclusión de Embeddings
Al asignarle vectores con valor numérico continuo a entradas categóricas , estos terminan funcio-
nando como “una mini red neuronal” dentro de la red principal. Aprenden con backpropagation⁴⁵⁷.
Y resuelven como valores continuos esos identificadores discretos, acentuando su valor intrínseco.
⁴⁵⁵http://www.aprendemachinelearning.com/que-es-overfitting-y-underfitting-y-como-solucionarlo/
⁴⁵⁶http://course.fast.ai/lessons/lesson3.html
⁴⁵⁷http://neuralnetworksanddeeplearning.com/chap2.html
Pronóstico de Ventas con Redes Neuronales (Parte 2) 243
Una ventaja de usar Embeddings es que se pueden reutilizar. Una vez entrenados podemos guar-
darlos para utilizarlos en otra red. Gracias a esto es que encontramos archivos de Embeddings con
millones de palabras “ya entrenadas” por Google⁴⁵⁸, listos para descargar y usar.
Quiero Python!
Dejaré enlace a los códigos, pues me quiero centrar un más en las comparaciones y conclusiones de
cada modelo, y no tanto en su implementación (cualquier duda, me escriben comentarios!). Aquí los
enlaces de las 3 notebooks puedes abrirlas en pestañas nuevas
El modelo ST1 y STMV quedan prácticamente iguales. Es decir que tras agregar las variables de
fecha no pareciera haber mejoría en las métricas. Sin embargo el modelo con embeddings sí que
logra una mejora algo más evidente: el validation_loss pasa de 0.14 a 0.09 y el validation_MSE de
0.04 a 0.02.
Modelo 2) STMV: Bastante similar al modelo 1 pero con algo mayor de amplitud.
Pronóstico de Ventas con Redes Neuronales (Parte 2) 248
Modelo 3) STE: Los Embeddings proveen mayor flexibilidad a la curva de pronóstico y aciertos.
Podemos ver que la primera red es “más conservadora”, manteniéndoselo en “la media” de 200,
sin picos bruscos. El segundo modelo tiene algo más de amplitud en sus predicciones y la red
neuronal que mejor se comporta es la tercera, que evidentemente gracias a los Embeddings logra
pronosticar mejor los valores y vemos picos “más alejados” de la media de 200 que son * <<buenos
aciertos>>*.
Resumen
Como primer conclusión podemos decir que mejoran las predicciones al agregar más variables de
entrada a la red. Realmente notamos mejoría con nuestro modelo 3 al usar Embeddings en la red
neuronal.
NOTA 1: recordemos que hay muchos de los parámetros para “tunear” que hemos fijado arbitra-
riamente. Al igual que en artículo anterior⁴⁶⁶, animo al lector a variar esos parámetros en los 3
modelos para mejorarlos, empezando por la cantidad de EPOCHS=40 (aumentar a 100), ó la variable
de PASOS que está en 7 (probar con 4 ó con 10).
NOTA 2: en el modelo de múltiples variables “hicimos un truco” tomando como variable adicional
la fecha, pero realmente estaría bien tener otras variables con datos útiles como en el ejemplo de
pronóstico del clima: 3 variables con temperatura, presión y humedad.
Podemos ver cómo el Machine Learning, puede a partir de relativamente pocos datos, sacar de su
galera nuevas herramientas y adaptar y mejorar el modelo. En este caso, sabemos que podemos
⁴⁶⁶http://www.aprendemachinelearning.com/pronostico-de-series-temporales-con-redes-neuronales-en-python/
Pronóstico de Ventas con Redes Neuronales (Parte 2) 249
utilizar las variables categóricas a través de Embeddings y mejorar sustancialmente los resultados
obtenidos.
Recursos Adicionales
• Primera Parte: Pronóstico de Series Temporales con Redes Neuronales en Python⁴⁶⁷
• Abrir código Modelo 1: Red Neuronal con una Variable⁴⁶⁸
• Abrir código Modelo 2: Serie Temporal multiples variables⁴⁶⁹
⁴⁶⁷http://www.aprendemachinelearning.com/pronostico-de-series-temporales-con-redes-neuronales-en-python/
⁴⁶⁸https://nbviewer.jupyter.org/github/jbagnato/machine-learning/blob/master/Series_Temporales_con_RRNN.ipynb
⁴⁶⁹https://nbviewer.jupyter.org/github/jbagnato/machine-learning/blob/master/Series_Temporales_Multivariate.ipynb
⁴⁷⁰https://nbviewer.jupyter.org/github/jbagnato/machine-learning/blob/master/Series_Temporales_Embeddings.ipynb
⁴⁷¹https://raw.githubusercontent.com/jbagnato/machine-learning/master/time_series.csv
⁴⁷²https://www.aprendemachinelearning.com/tu-propio-servicio-de-machine-learning/
⁴⁷³https://towardsdatascience.com/neural-network-embeddings-explained-4d028e6f0526
⁴⁷⁴https://machinelearningmastery.com/multivariate-time-series-forecasting-lstms-keras/
⁴⁷⁵https://www.fast.ai/2018/04/29/categorical-embeddings/
Crea tu propio servicio de Machine
Learning con Flask
Dale vida a tu IA
Ya tienes tu modelo⁴⁷⁶, probado⁴⁷⁷, funciona bien y está listo para entrar en acción. Entonces, ¿cómo
lo desplegamos? Si es una solución que quieres ofrecer al público desde la nube, puedes implementar
tu propio servicio online y ofrecer soluciones de Machine Learning⁴⁷⁸!
Veamos cómo hacerlo!
actualización o borrado de los datos a los que tienen acceso. En nuestro caso, lo típico será ofrecer
un servicio de Machine Learning de predicción ó clasificación (por nombrar alguno). Entonces nos
llegarán en la petición GET ó POST las entradas que tendrá el modelo (nuestras features, ó lo que
normalmente son las “columnas” de un csv que usamos para entrenar). Y nuestra salida podría ser
según el caso, el resultado de la predicción, ó una probabilidad, ó un número (por ej. “cantidad de
ventas pronosticadas para ese día”).
Para crear una API, podemos utilizar diversas infraestructuras ya existentes en el mercado que
ofrecen Google, Amazon, Microsoft (u otros) ó podemos “levantar” nuestro propio servicio con Flask.
Flask es un web framework en Python que simplifica la manera de publicar nuestra propia API (Hay
otros como Django, Falcon y más).
Instalar Flask
Veamos rápidamente como instalar y dejar montado Flask.
• Instalar Anaconda⁴⁷⁹ en el servidor ó en nuestra máquina local para desarrollo. (Para servidores
también puedes usar la versión de mini-conda⁴⁸⁰)
• Prueba ejecutar el comando “conda” en el terminal para verificar que esté todo ok.
• Crear un nuevo environment en el que trabajaremos conda create --name mi_ambiente
python=3.6
• Activa el ambiente creado con source activate mi_ambiente
• Instalar los paquetes Python que utilizaremos: pip install flask gunicorn
Hagamos un “Hello world” con Flask. Crea un archivo de texto nuevo llamado “mi_server.py⁴⁸¹”
Con eso ya tenemos nuestro servidor ejecutando. En breve haremos cambios para poder servir
nuestro modelo de Machine Learning⁴⁸² desde Flask al mundo :)
⁴⁸²https://www.aprendemachinelearning.com/7-pasos-machine-learning-construir-maquina/
Crea tu propio servicio de Machine Learning con Flask 253
Crear el modelo de ML
Hagamos un ejemplo de un modelo de ML basándonos en el ejercicio de Pronóstico de Series
Temporales⁴⁸³ que hace un pronóstico de ventas con redes neuronales con Embeddings. Esta vez
no usaremos una notebook de Jupyter, si no, archivos de “texto plano” Python:
1 import pandas as pd
2 import numpy as np
3 from sklearn.preprocessing import MinMaxScaler
4
5 from utiles import *
6
7 df = pd.read_csv('time_series.csv', parse_dates=[0], header=None,index_col=0, names\
8 =['fecha','unidades'])
9 df['weekday']=[x.weekday() for x in df.index]
10 df['month']=[x.month for x in df.index]
11 print(df.head())
12
13 EPOCHS=40
14 PASOS=7
15
16 scaler = MinMaxScaler(feature_range=(-1, 1))
17
18 reframed = transformar(df, scaler)
19
20 reordenado=reframed[ ['weekday','month','var1(t-7)','var1(t-6)','var1(t-5)','var1(t-\
21 4)','var1(t-3)','var1(t-2)','var1(t-1)','var1(t)'] ]
22 reordenado.dropna(inplace=True)
23
24 training_data = reordenado.drop('var1(t)', axis=1)
25 target_data=reordenado['var1(t)']
26 cant = len(df.index)
27 valid_data = training_data[cant-30:cant]
28 valid_target=target_data[cant-30:cant]
29
30 training_data = training_data[0:cant]
31 target_data=target_data[0:cant]
32 print(training_data.shape, target_data.shape, valid_data.shape, valid_target.shape)
33 print(training_data.head())
34
35 model = crear_modeloEmbeddings()
⁴⁸³https://www.aprendemachinelearning.com/pronostico-de-ventas-redes-neuronales-python-embeddings/
Crea tu propio servicio de Machine Learning con Flask 254
36
37 continuas = training_data[['var1(t-7)','var1(t-6)','var1(t-5)','var1(t-4)','var1(t-3\
38 )','var1(t-2)','var1(t-1)']]
39 valid_continuas = valid_data[['var1(t-7)','var1(t-6)','var1(t-5)','var1(t-4)','var1(\
40 t-3)','var1(t-2)','var1(t-1)']]
41
42 history = model.fit([training_data['weekday'],training_data['month'],continuas], tar\
43 get_data, epochs=EPOCHS,
44 validation_data=([valid_data['weekday'],valid_data['month'],vali\
45 d_continuas],valid_target))
46
47 results = model.predict([valid_data['weekday'],valid_data['month'],valid_continuas])
48
49 print( 'Resultados escalados',results )
50 inverted = scaler.inverse_transform(results)
51 print( 'Resultados',inverted )
Ya logramos entrenar un nuevo modelo del que estamos conformes. Ahora veamos como guardarlo
para poder reutilizarlo en la API!
• Pickle de Python para almacenar objetos (en nuestro caso un Transformador que debemos
mantener para “reconvertir los resultados escalados” al finalizar de entrenar)
• h5py para el modelo Keras (podemos guardar el modelo completo ó los pesos asociados a la
red)
Crea tu propio servicio de Machine Learning con Flask 255
1 import pickle
2
3 #definimos funciones de guardar y cargar
4 def save_object(filename, object):
5 with open(''+filename, 'wb') as file:
6 pickle.dump(object, file)
7
8 def load_object(filename):
9 with open(''+filename ,'rb') as f:
10 loaded = pickle.load(f)
11 return loaded
12
13 # guardamos los objetos que necesitaremos mas tarde
14 save_object('scaler_time_series.pkl', scaler)
15 model.save_weights("pesos.h5")
16
17 # cargamos cuando haga falta
18 loaded_scaler = load_object('scaler_time_series.pkl')
19 loaded_model = crear_modeloEmbeddings()
20 loaded_model.load_weights("pesos.h5")
Podemos comprobar a ver las predicciones sobre el set de validación antes y después de guardar los
objetos y veremos que da los mismos resultados.
Vamos a la acción:
⁴⁸⁴https://github.com/jbagnato/machine-learning/blob/master/api_ml/server.py
⁴⁸⁵https://github.com/jbagnato/machine-learning/blob/master/api_ml/test_api.py
⁴⁸⁶https://github.com/jbagnato/machine-learning/blob/master/api_ml/utiles.py
⁴⁸⁷https://github.com/jbagnato/machine-learning/blob/master/api_ml/api_train_model.py
⁴⁸⁸https://www.aprendemachinelearning.com/pronostico-de-ventas-redes-neuronales-python-embeddings/
⁴⁸⁹https://github.com/jbagnato/machine-learning/blob/master/api_ml/time_series.csv
Crea tu propio servicio de Machine Learning con Flask 256
1 """Filename: server.py
2 """
3 import pandas as pd
4 from sklearn.externals import joblib
5 from flask import Flask, jsonify, request
6
7 from utiles import *
8
9 app = Flask(__name__)
10
11 @app.route('/predict', methods=['POST'])
12 def predict():
13 """API request
14 """
15 try:
16 req_json = request.get_json()
17 input = pd.read_json(req_json, orient='records')
18 except Exception as e:
19 raise e
20
21 if input.empty:
22 return(bad_request())
23 else:
24 #Load the saved model
25 print("Cargar el modelo...")
26 loaded_model = crear_modeloEmbeddings()
27 loaded_model.load_weights("pesos.h5")
28
29 print("Hacer Pronosticos")
30 continuas = input[['var1(t-7)','var1(t-6)','var1(t-5)','var1(t-4)','var1(t-3\
31 )','var1(t-2)','var1(t-1)']]
32 predictions = loaded_model.predict([input['weekday'], input['month'], contin\
33 uas])
34
35 print("Transformando datos")
36 loaded_scaler = load_object('scaler_time_series.pkl')
37 inverted = loaded_scaler.inverse_transform(predictions)
38 inverted = inverted.astype('int32')
Crea tu propio servicio de Machine Learning con Flask 257
39
40 final_predictions = pd.DataFrame(inverted)
41 final_predictions.columns = ['ventas']
42
43 print("Enviar respuesta")
44 responses = jsonify(predictions=final_predictions.to_json(orient="records"))
45 responses.status_code = 200
46 print("Fin de Peticion")
47
48 return (responses)
Muy bien, podemos ejecutar nuestra API desde la terminal para testear con:
Y ahora hagamos una petición para probar nuestra API con un archivo Python y veamos la salida:
1 import json
2 import requests
3 import pandas as pd
4 import pickle
5 from utiles import *
6
7 """Setting the headers to send and accept json responses
8 """
9 header = {'Content-Type': 'application/json', \
10 'Accept': 'application/json'}
11
12 # creamos un dataset de pruebas
13 df = pd.DataFrame({"unidades": [289,288,260,240,290,255,270,300],
14 "weekday": [5,0,1,2,3,4,5,0],
15 "month": [4,4,4,4,4,4,4,4]})
16
17 loaded_scaler = load_object('scaler_time_series.pkl')
18
19 reframed = transformar(df, loaded_scaler)
20
21 reordenado=reframed[ ['weekday','month','var1(t-7)','var1(t-6)','var1(t-5)','var1(t-\
22 4)','var1(t-3)','var1(t-2)','var1(t-1)'] ]
23 reordenado.dropna(inplace=True)
24
25 """Converting Pandas Dataframe to json
Crea tu propio servicio de Machine Learning con Flask 258
26 """
27 data = reordenado.to_json(orient='records')
28
29 print('JSON para enviar en POST', data)
30
31 """POST <url>/predict
32 """
33 resp = requests.post("http://localhost:8000/predict", \
34 data = json.dumps(data),\
35 headers= header)
36
37 print('status',resp.status_code)
38
39
40 """The final response we get is as follows:
41 """
42 print('Respuesta de Servidor')
43 print(resp.json())
1 {'predictions': '[{"ventas":194}]'}
Resumen
En este artículo vimos que nuestro modelo de ML puede llegar a ser una pequeña pieza de un puzzle
mayor y puede ofrecer soluciones a usuarios finales ó a otros subsistemas. Para poder ofrecer sus
servicios podemos contar con diversas soluciones, siendo una de ellas el despliegue de una API.
Podemos crear una API fácil y rápidamente con el web framework de Flask. Ya puedes ofrecer tus
modelos al mundo!
NOTAS finales: Recuerda ejecutar los archivos en el siguiente orden:
Crea tu propio servicio de Machine Learning con Flask 259
Recursos Adicionales
Descarga los archivos creados en este artículo
• Archivos en GitHub⁴⁹⁰
⁴⁹⁰https://github.com/jbagnato/machine-learning/tree/master/api_ml
⁴⁹¹https://www.bogotobogo.com/python/Flask/Python_Flask_Embedding_Machine_Learning_1.php
Clasificación de Imágenes en Python
Crearemos una Convolutional Neural Network⁴⁹² con Keras y Tensorflow en Python para reconoci-
miento de Imágenes.
En este capítulo iremos directo al grano: veremos el código que crea la red neuronal para visión
artificial. En el próximo capítulo explicaré bien los conceptos utilizados⁴⁹³, pero esta vez haremos un
aprendizaje Top-down⁴⁹⁴ ;)
⁴⁹²http://www.aprendemachinelearning.com/como-funcionan-las-convolutional-neural-networks-vision-por-ordenador/
⁴⁹³http://www.aprendemachinelearning.com/como-funcionan-las-convolutional-neural-networks-vision-por-ordenador/
⁴⁹⁴https://classroom.synonym.com/difference-between-topdown-teaching-bottomup-teaching-12059397.html
⁴⁹⁵https://deeplearninglaptop.com/blog/2017/11/24/mnist/
⁴⁹⁶https://ffmpeg.org
⁴⁹⁷http://www.aprendemachinelearning.com/como-funcionan-las-convolutional-neural-networks-vision-por-ordenador/
Clasificación de Imágenes en Python 261
Dividiremos el set de datos en 80-20 para entrenamiento y para test. A su vez, el conjunto de
entrenamiento también lo subdividiremos en otro 80-20 para Entrenamiento y Validación en
cada iteración (EPOCH⁴⁹⁸) de aprendizaje.
⁴⁹⁸http://sgsai.blogspot.com/2015/02/epoch-batch-and-iteration.html
Clasificación de Imágenes en Python 262
Una muestra de las imágenes del Dataset que he titulado sportsMNIST. Contiene más de 70.000
imágenes de los 10 deportes más populares del mundo.
Clasificación de Imágenes en Python 263
Requerimientos Técnicos
Necesitaremos tener Python 3.6 y como lo haremos en una Notebook Jupyter,⁴⁹⁹ recomiendo tener
instalada una suite como Anaconda⁵⁰⁰, que nos facilitará las tareas. Además instalar Keras y Tensor-
flow como backend.
Necesitarás descargar el archivo zip con las imágenes (están comprimidas) y decomprimirlas en el
mismo directorio en donde ejecutarás la Notebook con el código. Al descomprimir, se crearán 10
subdirectorios con las imágenes: uno por cada deporte.
1. Importar librerías
2. Cargar las 70.000 imágenes (en memoria!)
3. Crear dinámicamente las etiquetas de resultado.
4. Dividir en sets de Entrenamiento, Validación y Test, preprocesamiento de datos
5. Crear el modelo de la CNN
6. Ejecutar nuestra máquina de aprendizaje (Entrenar la red)
7. Revisar los resultados obtenidos
Empecemos a programar!:
1- Importar librerías
Cargaremos las libs que utilizaremos para el ejercicio.
⁴⁹⁹http://data-speaks.luca-d3.com/2018/03/python-para-todos-2-jupyternotebook.html
⁵⁰⁰https://www.anaconda.com/download/
⁵⁰¹https://github.com/jbagnato/machine-learning/raw/master/sportimages.zip
⁵⁰²https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_CNN.ipynb
⁵⁰³http://www.aprendemachinelearning.com/como-funcionan-las-convolutional-neural-networks-vision-por-ordenador/
Clasificación de Imágenes en Python 264
1 import numpy as np
2 import os
3 import re
4 import matplotlib.pyplot as plt
5 %matplotlib inline
6 from sklearn.model_selection import train_test_split
7 from sklearn.metrics import classification_report
8 import keras
9 from keras.utils import to_categorical
10 from keras.models import Sequential,Input,Model
11 from keras.layers import Dense, Dropout, Flatten
12 from keras.layers import Conv2D, MaxPooling2D
13 from keras.layers.normalization import BatchNormalization
14 from keras.layers.advanced_activations import LeakyReLU
21 if prevRoot !=root:
22 print(root, cant)
23 prevRoot=root
24 directories.append(root)
25 dircount.append(cant)
26 cant=0
27 dircount.append(cant)
28
29 dircount = dircount[1:]
30 dircount[0]=dircount[0]+1
31 print('Directorios leidos:',len(directories))
32 print("Imagenes en cada directorio", dircount)
33 print('suma Total de imagenes en subdirs:',sum(dircount))
1 labels=[]
2 indice=0
3 for cantidad in dircount:
4 for i in range(cantidad):
5 labels.append(indice)
6 indice=indice+1
7 print("Cantidad etiquetas creadas: ",len(labels))
8
9 deportes=[]
10 indice=0
11 for directorio in directories:
12 name = directorio.split(os.sep)
13 print(indice , name[len(name)-1])
⁵⁰⁴http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/
Clasificación de Imágenes en Python 266
14 deportes.append(name[len(name)-1])
15 indice=indice+1
16
17 y = np.array(labels)
18 X = np.array(images, dtype=np.uint8) #convierto de lista a numpy
19
20 # Find the unique numbers from the train labels
21 classes = np.unique(y)
22 nClasses = len(classes)
23 print('Total number of outputs : ', nClasses)
24 print('Output classes : ', classes)
⁵⁰⁵https://machinelearningmastery.com/why-one-hot-encode-data-in-machine-learning/
⁵⁰⁶https://medium.com/simple-ai/how-good-is-your-model-intro-to-machine-learning-4-ec7289bb7dca
Clasificación de Imágenes en Python 267
• Declaramos 3 “constantes”:
– El valor inicial del learning rate INIT_LR
– cantidad de epochs y
– tamaño batch de imágenes a procesar batch_size (cargan en memoria).
• Crearemos una primer capa de neuronas “Convolucional de 2 Dimensiones” Conv2D() , donde
entrarán nuestras imágenes de 21x28x3.
⁵⁰⁷http://www.aprendemachinelearning.com/como-funcionan-las-convolutional-neural-networks-vision-por-ordenador/
Clasificación de Imágenes en Python 268
• Aplicaremos 32 filtros (kernel) de tamaño 3x3 (no te preocupes si aún no entiendes esto!) que
detectan ciertas características de la imagen (ejemplo: lineas verticales).
• Utilizaremos La función LeakyReLU⁵⁰⁸ como activación de las neuronas.
• Haremos un MaxPooling (de 2x2) que reduce la imagen que entra de 21x28 a la mitad,(11x14)
manteniendo las características “únicas” que detectó cada kernel.
• Para evitar el overfitting, añadimos una técnica llamada Dropout⁵⁰⁹
• “Aplanamos” Flatten() los 32 filtros y creamos una capa de 32 neuronas “tradicionales” Dense()
• Y finalizamos la capa de salida con 10 neuronas con activación Softmax, para que se correspon-
da con el “hot encoding” que hicimos antes.
• Luego compilamos nuestra red sport_model.compile() y le asignamos un optimizador (en este
caso de llama Adagrad).
1 INIT_LR = 1e-3
2 epochs = 6
3 batch_size = 64
4
5 sport_model = Sequential()
6 sport_model.add(Conv2D(32, kernel_size=(3, 3),activation='linear',padding='same'\
7 ,input_shape=(21,28,3)))
8 sport_model.add(LeakyReLU(alpha=0.1))
9 sport_model.add(MaxPooling2D((2, 2),padding='same'))
10 sport_model.add(Dropout(0.5))
11
12 sport_model.add(Flatten())
13 sport_model.add(Dense(32, activation='linear'))
14 sport_model.add(LeakyReLU(alpha=0.1))
15 sport_model.add(Dropout(0.5))
16 sport_model.add(Dense(nClasses, activation='softmax'))
17
18 sport_model.summary()
19
20 sport_model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.\
21 optimizers.Adagrad(lr=INIT_LR, decay=INIT_LR / 100),metrics=['accuracy'])
⁵⁰⁸https://en.wikipedia.org/wiki/Rectifier_(neural_networks)
⁵⁰⁹https://en.wikipedia.org/wiki/Convolutional_neural_network#Dropout
Clasificación de Imágenes en Python 269
6-Entrenamos la CNN
Llegó el momento!!! con esta linea sport_model.fit() iniciaremos el entrenamiento y validación de
nuestra máquina. Pensemos que introduciremos miles de imágenes, pixeles, arrays, colores… filtros y
la red se irá regulando sola, “aprendiendo” los mejores pesos para las más de 150.000 interconexiones
para distinguir los 10 deportes. Esto tomará tiempo en un ordenador como mi Macbook Pro (del 2016)
unos 4 minutos… puede parecer mucho o muy poco… según se lo mire.
NOTA: podemos ejecutar este mismo código pero utilizando GPU (en tu ordenador o en la nube⁵¹⁰)
y los mismos cálculos tomaría apenas 40 segundos.
Por último guardamos la red YA ENTRENADA sport_model.save() en un formato de archivo h5py
que nos permitirá poder utilizarla en el futuro **SIN necesidad de volver a entrenar **(y ahorrarnos
los 4 minutos de impaciencia!).
⁵¹⁰https://colab.research.google.com/
Clasificación de Imágenes en Python 270
Vemos que tras 6 iteraciones completas al set de entrenamiento, logramos un valor de precisión
del 70% y en el set de validación alcanza un 83%. ¿Será esto suficiente para distinguir las imágenes
deportivas?
Clasificación de Imágenes en Python 271
Clasificación de Imágenes en Python 272
7-Resultados de la clasificación
Ya con nuestra red entrenada, es la hora de la verdad: ponerla a prueba con el set de imágenes para
Test que separamos al principio y que son muestras que nunca fueron “vistas” por la máquina.
En el conjunto de Testing vemos que alcanza una precisión del 84% reconociendo las imágenes de
deportes. Ahora podríamos hacer un análisis más profundo, para mejorar la red, revisando los fallos
que tuvimos… pero lo dejaremos para otra ocasión (BONUS: en la Jupyter Notebook verás más
información con esto!) Spoiler Alert: La clase que peor detecta, son las de Fórmula 1.
⁵¹¹
Puedes probar con esta imagen de Basketball y de Fútbol a clasificarlas. En mi caso, fueron clasifi-
cadas con éxito.
⁵¹¹http://www.aprendemachinelearning.com/wp-content/uploads/2018/11/test_basket.png
Clasificación de Imágenes en Python 273
⁵¹²
En mis pruebas, a veces confundía esta imagen de Fútbol con Golf… ¿Será por el verde del campo?
Resumen
Creamos una red neuronal “novedosa”: una red convolucional, que aplica filtros a las imágenes y es
capaz de distinguir distintos deportes con un tamaño de entrada de 21x28 pixels a color en tan sólo 4
minutos de entrenamiento. Esta vez fuimos a la inversa que en otras ocasiones y antes de conocer
la teoría de las redes específicas para reconocimiento de imágenes (las CNN) les he propuesto que
hagamos un ejercicio práctico. Aunque pueda parecer contra-intuitivo, muchas veces este método
de aprendizaje (en humanos!) funciona mejor, pues vuelve algo más dinámica la teoría. Espero que
les hayan quedado algunos de los conceptos y los terminaremos de asentar en un próximo capítulo⁵¹³
Los recursos
• Descarga el conjunto de 70.000 imágenes para entrenar la red en archivo comprimido⁵¹⁴ (ocupa
63MB)
• Descarga el código Python Completo, en Jupyter Notebook⁵¹⁵
• Ver mi cuenta Github, con todos los ejercicios de Machine Learning⁵¹⁶
• De la universidad de Stanford, una referencia indudable: CS231N CNN for Visual Recogni-
tion⁵¹⁷
• Introducing Convolutional Neural Networks⁵¹⁸
⁵¹²http://www.aprendemachinelearning.com/wp-content/uploads/2018/11/test_futbol.png
⁵¹³http://www.aprendemachinelearning.com/como-funcionan-las-convolutional-neural-networks-vision-por-ordenador/
⁵¹⁴https://github.com/jbagnato/machine-learning/raw/master/sportimages.zip
⁵¹⁵https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_CNN.ipynb
⁵¹⁶https://github.com/jbagnato/machine-learning
⁵¹⁷http://cs231n.github.io/convolutional-networks/
⁵¹⁸http://neuralnetworksanddeeplearning.com/chap6.html#introducing_convolutional_networks
Clasificación de Imágenes en Python 274
⁵¹⁹https://towardsdatascience.com/intuitively-understanding-convolutions-for-deep-learning-1f6f42faee1
⁵²⁰https://www.datacamp.com/community/tutorials/convolutional-neural-networks-python#cnn
¿Cómo funcionan las Convolutional
Neural Networks?
En este capítulo intentaré explicar la teoría relativa a las Redes Neuronales Convolucionales (en
inglés CNN⁵²¹) que son el algoritmo utilizado en Aprendizaje Automático⁵²² para dar la capacidad
de “ver” al ordenador. Gracias a esto, desde apenas 1998⁵²³, podemos clasificar imágenes, detectar
diversos tipos de tumores automáticamente, enseñar a conducir a los coches autónomos y un sinfín
de otras aplicaciones⁵²⁴.
El tema es bastante complejo/complicado e intentaré explicarlo lo más claro posible. En este artículo
doy por sentado que tienes conocimientos básicos de cómo funciona una red neuronal artificial
multicapa feedforward (fully connected).
La CNN es un tipo de Red Neuronal Artificial con aprendizaje supervisado que procesa sus capas
imitando al cortex visual del ojo humano para identificar distintas características en las entradas
que en definitiva hacen que pueda identificar objetos y “ver”. Para ello, la CNN contiene varias
capas ocultas especializadas y con una jerarquía: esto quiere decir que las primeras capas pueden
detectar lineas, curvas y se van especializando hasta llegar a capas más profundas que reconocen
formas complejas como un rostro o la silueta de un animal.
Muchas imágenes
Recodemos que la red neuronal deberá aprender por sí sola a reconocer una diversidad de objetos
dentro de imágenes y para ello necesitaremos una gran cantidad de imágenes -lease más de 10.000
imágenes de gatos, otras 10.000 de perros,…- para que la red pueda captar sus características únicas
-de cada objeto- y a su vez, poder generalizarlo -esto es que pueda reconocer como gato tanto a un
felino negro, uno blanco, un gato de frente, un gato de perfil, gato saltando, etc.-
⁵²¹https://en.wikipedia.org/wiki/Convolutional_neural_network
⁵²²http://www.aprendemachinelearning.com/que-es-machine-learning/
⁵²³http://www.aprendemachinelearning.com/breve-historia-de-las-redes-neuronales-artificiales/
⁵²⁴http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/
¿Cómo funcionan las Convolutional Neural Networks? 276
Pixeles y neuronas
Para comenzar, la red toma como entrada los pixeles de una imagen. Si tenemos una imagen con
apenas 28x28 pixeles de alto y ancho, eso equivale a 784 neuronas. Y eso es si sólo tenemos 1 color
(escala de grises). Si tuviéramos una imagen a color, necesitaríamos 3 canales: red, green, blue
y entonces usaríamos 28x28x3 = 2352 neuronas de entrada. Esa es nuestra capa de entrada. Para
continuar con el ejemplo, supondremos que utilizamos la imagen con 1 sólo color.
No Olvides: Pre-procesamiento
Antes de alimentar la red, recuerda que como entrada nos conviene normalizar los valores. Los
colores de los pixeles tienen valores que van de 0 a 255, haremos una transformación de cada pixel:
“valor/255” y nos quedará siempre un valor entre 0 y 1.
¿Cómo funcionan las Convolutional Neural Networks? 277
Convoluciones
Ahora comienza el “procesado distintivo” de las CNN. Es decir, haremos las llamadas “convolucio-
nes”: Estas consisten en tomar “grupos de pixeles cercanos” de la imagen de entrada e ir operando
matemáticamente (producto escalar) contra una pequeña matriz que se llama kernel. Ese kernel
supongamos de tamaño 3x3 pixels “recorre” todas las neuronas de entrada (de izquierda-derecha,
de arriba-abajo) y genera una nueva matriz de salida, que en definitiva será nuestra nueva capa de
neuronas ocultas.
NOTA: si la imagen fuera a color, el kernel realmente sería de 3x3x3: un filtro con 3 kernels de 3x3;
luego esos 3 filtros se suman (y se le suma una unidad bias) y conformarán 1 salida (cómo si fuera
1 solo canal).
¿Cómo funcionan las Convolutional Neural Networks? 278
⁵²⁵
Aquí vemos al kernel realizando el producto matricial con la imagen de entrada y desplazando de a
1 pixel de izquierda a derecha y de arriba-abajo y va generando una nueva matriz que compone al
mapa de features.
A medida que vamos desplazando el kernel y vamos obteniendo una “nueva imagen” filtrada por el
kernel. En esta primer convolución y siguiendo con el ejemplo anterior, es como si obtuviéramos 32
“imágenes filtradas nuevas”. Estas imágenes nuevas lo que están “dibujando” son ciertas caracterís-
ticas de la imagen original. Esto ayudará en el futuro a poder distinguir un objeto de otro (por ej.
gato ó perro).
⁵²⁶
La imagen realiza una convolución con un kernel y aplica la función de activación, en este caso
ReLu[/caption]
⁵²⁵http://www.aprendemachinelearning.com/wp-content/uploads/2018/11/cnn_kernel.gif
⁵²⁶http://www.aprendemachinelearning.com/wp-content/uploads/2018/11/CNN-04.png
¿Cómo funcionan las Convolutional Neural Networks? 280
La función de Activación
La función de activación más utilizada para este tipo de redes neuronales es la llamada ReLu⁵²⁷ por
Rectifier Linear Unit y consiste en f(x)=max(0,x).
Subsampling
Ahora viene un paso en el que reduciremos la cantidad de neuronas antes de hacer una nueva
convolución. ¿Por qué? Como vimos, a partir de nuestra imagen blanco y negro de 28x28px tenemos
una primer capa de entrada de 784 neuronas y luego de la primer convolución obtenemos una capa
oculta de 25.088 neuronas -que realmente son nuestros 32 mapas de características de 28x28- Si
hiciéramos una nueva convolución a partir de esta capa, el número de neuronas de la próxima capa
se iría por las nubes (y ello implica mayor procesamiento)! Para reducir el tamaño de la próxima
capa de neuronas haremos un proceso de subsampling en el que reduciremos el tamaño de nuestras
imágenes filtradas pero en donde deberán prevalecer las características más importantes que
detectó cada filtro. Hay diversos tipos de subsampling, yo comentaré el “más usado”: Max-Pooling
⁵²⁷https://en.wikipedia.org/wiki/Rectifier_(neural_networks)
¿Cómo funcionan las Convolutional Neural Networks? 281
⁵²⁸
Vamos a intentar explicarlo con un ejemplo: supongamos que haremos Max-pooling de tamaño 2x2.
Esto quiere decir que recorreremos cada una de nuestras 32 imágenes de características obtenidas
anteriormente de 28x28px de izquierda-derecha, arriba-abajo PERO en vez de tomar de a 1 pixel,
tomaremos de “2x2” (2 de alto por 2 de ancho = 4 pixeles) e iremos preservando el valor “más alto”
de entre esos 4 pixeles (por eso lo de “Max”). En este caso, usando 2x2, la imagen resultante es
reducida “a la mitad”y quedará de 14x14 pixeles. Luego de este proceso de subsamplig nos quedarán
32 imágenes de 14x14, pasando de haber tenido 25.088 neuronas a 6272, son bastantes menos y -en
teoría- siguen almacenando la información más importante para detectar características deseadas.
⁵²⁸http://www.aprendemachinelearning.com/wp-content/uploads/2018/11/cnn-05.png
¿Cómo funcionan las Convolutional Neural Networks? 282
⁵²⁹
Muy bien, pues esa ha sido una primer convolución: consiste de una entrada, un conjunto de filtros,
generamos un mapa de características y hacemos un subsampling. Con lo cual, en el ejemplo de
imágenes de 1 sólo color tendremos:
La primer convolución es capaz de detectar características primitivas como lineas ó curvas. A medida
que hagamos más capas con las convoluciones, los mapas de características serán capaces de
reconocer formas más complejas, y el conjunto total de capas de convoluciones podrá “ver”. Pues
ahora deberemos hacer una Segunda convolución que será:
⁵²⁹http://www.aprendemachinelearning.com/wp-content/uploads/2018/11/cnn-06.png
¿Cómo funcionan las Convolutional Neural Networks? 283
⁵³⁰
1)Entrada: Imagen 14x14x32
2)Aplico Kernel 64 filtros de 3x3
3)Obtengo Feature Mapping 14x14x64
4)Aplico Max-Pooling de 2x2
5)Obtengo “Salida” de la Convolución 7x7x64
La 3er convolución comenzará en tamaño 7x7 pixels y luego del max-pooling quedará en 3x3 con
lo cual podríamos hacer sólo 1 convolución más. En este ejemplo empezamos con una imagen de
28x28px e hicimos 3 convoluciones. Si la imagen inicial hubiese sido mayor (de 224x224px) aún
hubiéramos podido seguir haciendo convoluciones.
⁵³¹
Entonces, a esta nueva capa oculta “tradicional”, le aplicamos una función llamada Softmax⁵³² que
conecta contra la capa de salida final que tendrá la cantidad de neuronas correspondientes con
las clases que estamos clasificando. Si clasificamos perros y gatos, serán 2 neuronas. Si es el dataset
Mnist numérico serán 10 neuronas de salida. Si clasificamos coches, aviones ó barcos serán 3, etc. Las
salidas al momento del entrenamiento tendrán el formato conocido como “one-hot-encoding⁵³³” en
el que para perros y gatos sera: [1,0] y [0,1], para coches, aviones ó barcos será [1,0,0]; [0,1,0];[0,0,1].
Y la función de Softmax se encarga de pasar a probabilidad (entre 0 y 1) a las neuronas de salida. Por
ejemplo una salida [0,2 0,8] nos indica 20% probabilidades de que sea perro y 80% de que sea gato.
⁵³¹http://www.aprendemachinelearning.com/wp-content/uploads/2018/11/CNN-08.png
⁵³²https://en.wikipedia.org/wiki/Softmax_function
⁵³³https://en.wikipedia.org/wiki/One-hot
¿Cómo funcionan las Convolutional Neural Networks? 285
⁵³⁴http://www.aprendemachinelearning.com/aplicaciones-del-machine-learning/#supervisado
¿Cómo funcionan las Convolutional Neural Networks? 286
Arquitectura básica
Resumiendo: podemos decir que los elementos que usamos para crear CNNs son:
• Entrada: Serán los pixeles de la imagen. Serán alto, ancho y profundidad será 1 sólo color o 3
para Red,Green,Blue.
• Capa De Convolución: procesará la salida de neuronas que están conectadas en “regiones
locales” de entrada (es decir pixeles cercanos), calculando el producto escalar entre sus pesos
(valor de pixel) y una pequeña región a la que están conectados en el volumen de entrada. Aquí
usaremos por ejemplo 32 filtros o la cantidad que decidamos y ese será el volumen de salida.
• “CAPA RELU” aplicará la función de activación en los elementos de la matriz.
• POOL ó SUBSAMPLING: Hará una reducción en las dimensiones alto y ancho, pero se
mantiene la profundidad.
• CAPA “TRADICIONAL” red de neuronas feedforward que conectará con la última capa de
subsampling y finalizará con la cantidad de neuronas que queremos clasificar.
No incluido
Quedan muchas cosas más que explicar. Temas y definiciones como padding, stride, evitar overfit-
ting, image-aumentation, dropout… o por nombrar algunas redes famosas ResNet, AlexNet, GoogLe-
Net and DenseNet, al mismísimo Yann LeCun… todo eso.. se queda fuera de este texto. Este artículo
pretende ser un punto inicial para seguir investigando y aprendiendo sobre las CNN. Al final dejo
enlace a varios artículos para ampliar información sobre CNN.
¿Cómo funcionan las Convolutional Neural Networks? 287
Resumen
Hemos visto cómo este algoritmo utiliza variantes de una red neuronal tradicional y las combina
con el comportamiento biológico del ojo humano, para lograr aprender a ver.
the-best-explanation-of-convolutional-neural-networks-on-the-internet-fbb8b1ad5df8)
⁵³⁵https://towardsml.com/2018/10/16/deep-learning-series-p2-understanding-convolutional-neural-networks/
⁵³⁶http://cs231n.github.io/
⁵³⁷http://neuralnetworksanddeeplearning.com/chap6.html#introducing_convolutional_networks
⁵³⁸https://towardsdatascience.com/intuitively-understanding-convolutions-for-deep-learning-1f6f42faee1
⁵³⁹https://distill.pub/2017/feature-visualization/
⁵⁴⁰https://becominghuman.ai/back-propagation-in-convolutional-neural-networks-intuition-and-code-714ef1c38199
Detección de Objetos con Python
Veremos de manera práctica cómo crear tu propio detector de objetos que podrás utilizar con
imagenes estáticas, video o cámara. Avanzaremos paso a paso en una Jupyter Notebook con el código
completo usando Keras sobre Tensorflow.
Agenda
Tenemos mucho por delante!
crear tu propio dataset de imagenes y anotaciones xml para detectar el ó los objetos que tu quieras!
1 $ detectaEnv\Scripts\activate.bat
1 $ source detectaEnv/bin/activate
Aclaraciones: usamos una versión antigua de Tensorflow. Si tienes GPU en tu máquina, puedes usar
la versión apropiada de Tensorflow.
Si vas crear tu propio dataset como se explica a continuación, deberás instalar LabelImg, que
requiere:
Si no, puedes usar el dataset de legos que provee el blog y saltarte la parte de crear el dataset.
Además otros archivos que deberás descargar:
Detección de Objetos con Python 291
Anotarlo Todo
Muy bien, ya tienes tus imágenes hechas y guardadas en un directorio.
Ahora deberás crear un archivo XML donde anotarás cada objeto, sus posiciones x,y su alto y ancho.
El xml será de este tipo:
⁵⁴¹https://drive.google.com/file/d/1Q9WhhRlqQbA4jgBkCDrynvgquRXZA_f8/view?usp=sharing
⁵⁴²https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_Object_Detection.ipynb
⁵⁴³https://leanpub.com/aprendeml
Detección de Objetos con Python 292
1 <annotation>
2 <folder>lego</folder>
3 <filename>croped12_231359.jpg</filename>
4 <path>/detectaobjetos/images/lego3/croped12_231359.jpg</path>
5 <size>
6 <width>4512</width>
7 <height>4512</height>
8 <depth>3</depth>
9 </size>
10 <object>
11 <name>lego</name>
12 <bndbox>
13 <xmin>909</xmin>
14 <ymin>879</ymin>
15 <xmax>3200</xmax>
16 <ymax>4512</ymax>
17 </bndbox>
18 </object>
19 </annotation>
Si lo instalaste con Pip, puedes ejecutarlo simplemente poniendo en línea de comandos labelImg. Se
abrirá el editor y podrás
En el editor deberás crear una caja sobre cada objeto que quieras detectar en la imagen y escribir su
nombre. Cuando terminas le das a Guardar y Siguiente.
El lego dataset
Si quieres puedes utilizar un dataset de imágenes que creé para este ejercicio y consta de 300
imágenes. Son fotos tomadas con móvil de diversos personajes lego. Realmente son 100 fotos y 200
variaciones en zoom y recortes. Y sus correspondientes 300 archivos de anotaciones xml
Dicho esto, recuerda que siempre es mejor más y más imágenes para entrenar.
El código Python
Usaremos Keras sobre Tensorflow para crear la red!, manos a la obra.
Detección de Objetos con Python 294
En el artículo copiaré los trozos de código más importante, pero recuerda descargar la notebook
Jupyter con el código completo desde Github⁵⁴⁴.
Leer el Dataset
Primer paso, será el de leer las anotaciones xml que tenemos creadas en un directorio e ir iterando
los objetos para contabilizar las etiquetas.
1 xml_dir = "annotation/lego/"
2 img_dir = "images/lego/"
3 labels = ["lego"]
4 tamanio = 416
5 mejores_pesos = "red_lego.h5"
6
7 def leer_annotations(ann_dir, img_dir, labels=[]):
8 all_imgs = []
9 seen_labels = {}
10
11 for ann in sorted(os.listdir(ann_dir)):
12 img = {'object':[]}
13
14 tree = ET.parse(ann_dir + ann)
15
16 for elem in tree.iter():
17 if 'filename' in elem.tag:
18 img['filename'] = img_dir + elem.text
19 if 'width' in elem.tag:
20 img['width'] = int(elem.text)
21 if 'height' in elem.tag:
22 img['height'] = int(elem.text)
23 if 'object' in elem.tag or 'part' in elem.tag:
24 obj = {}
25
26 for attr in list(elem):
27 if 'name' in attr.tag:
28 obj['name'] = attr.text
29
30 if obj['name'] in seen_labels:
31 seen_labels[obj['name']] += 1
32 else:
⁵⁴⁴https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_Object_Detection.ipynb
Detección de Objetos con Python 295
33 seen_labels[obj['name']] = 1
34
35 if len(labels) > 0 and obj['name'] not in labels:
36 break
37 else:
38 img['object'] += [obj]
39
40 if 'bndbox' in attr.tag:
41 for dim in list(attr):
42 if 'xmin' in dim.tag:
43 obj['xmin'] = int(round(float(dim.text)))
44 if 'ymin' in dim.tag:
45 obj['ymin'] = int(round(float(dim.text)))
46 if 'xmax' in dim.tag:
47 obj['xmax'] = int(round(float(dim.text)))
48 if 'ymax' in dim.tag:
49 obj['ymax'] = int(round(float(dim.text)))
50
51 if len(img['object']) > 0:
52 all_imgs += [img]
53
54 return all_imgs, seen_labels
55
56 train_imgs, train_labels = leer_annotations(xml_dir, img_dir, labels)
57 print('imagenes',len(train_imgs), 'labels',len(train_labels))
Train y Validación
Separaremos un 20% de las imágenes y anotaciones para testear el modelo. En este caso se utilizará
el set de Validación al final de cada época para evaluar métricas, pero nunca se usará para entrenar.
1 train_valid_split = int(0.8*len(train_imgs))
2 np.random.shuffle(train_imgs)
3 valid_imgs = train_imgs[train_valid_split:]
4 train_imgs = train_imgs[:train_valid_split]
5 print('train:',len(train_imgs), 'validate:',len(valid_imgs))
Data Augmentation
El Data Augmentation sirve para agregar pequeñas alteraciones ó cambios a las imágenes de entradas
aumentando nuestro dataset de imágenes y mejorando la capacidad de la red para detectar objetos.
Detección de Objetos con Python 296
Para hacerlo nos apoyamos sobre una librería imgaug que nos brinda muchas funcionalidades como
agregar desenfoque, agregar brillo, ó ruido aleatoriamente a las imágenes. Además podemos usar
OpenCV para voltear la imagen horizontalmente y luego recolocar la “bounding box”.
10 # Layer 2
11 x = Conv2D(64, (3,3), strides=(1,1), padding='same', name='conv_2', use_bias=False)(\
12 x)
13 x = BatchNormalization(name='norm_2')(x)
14 x = LeakyReLU(alpha=0.1)(x)
15 x = MaxPooling2D(pool_size=(2, 2))(x)
16
17 # Layer 3
18 x = Conv2D(128, (3,3), strides=(1,1), padding='same', name='conv_3', use_bias=False)\
19 (x)
20 x = BatchNormalization(name='norm_3')(x)
21 x = LeakyReLU(alpha=0.1)(x)
No olvides descargar y copiar en el mismo directorio donde ejecutes la notebook los pesos de la red
Darknet⁵⁴⁵, pues en este paso se cargaran para incializar la red.
17 kernel_initializer='lecun_normal')(features)
18 output = Reshape((self.grid_h, self.grid_w, self.nb_box, 4 + 1 + self.nb_cla\
19 ss))(output)
20 output = Lambda(lambda args: args[0])([output, self.true_boxes])
21
22 self.model = Model([input_image, self.true_boxes], output)
En total, la red crea una grilla de 13x13 y en cada una realizará 5 predicciones, lo que da un total
de 845 posibles detecciones para cada clase que queremos detectar. Si tenemos 10 clases esto serían
8450 predicciones, cada una con la clase y sus posiciones x,y ancho y alto. Lo más impresionante de
esta red YOLO es que lo hace Todo de 1 sólo pasada! increíble!
Detección de Objetos con Python 299
Para refinar el modelo y que detecte los objetos que hay, utilizará dos funciones con las cuales
descartará áreas vacías y se quedará sólo con las mejores propuestas. Las funciones son:
• IOU: Intersection Over Union, que nos da un porcentaje de acierto del área de predicción contra
la “cajita” real que queremos predecir
• Non Maximum suppression: nos permite quedarnos de entre nuestras 5 anclas, con la que mejor
se ajusta al resultado. Esto es porque podemos tener muchas áreas diferentes propuestas que
se superponen. De entre todas, nos quedamos con la mejor y eliminamos al resto.
Detección de Objetos con Python 300
Entonces, pensemos que si en nuestra red de detección de 1 sólo clase detectamos 1 objeto, esto
quiere decir que la red descarto a las 844 restantes.
NOTA: por más que haya separado en 2 redes: red YOLO y red de detección, realmente es 1 sóla red
convolucional, pues están conectadas y al momento de entrenar, los pesos se ajustan “como siempre”
con el backpropagation.
Pues según lo que quieras detectar conviene ajustar esos tamaños. Ejecutaremos un pequeño script
que utiliza k-means y determina los mejores 5 clusters (de dimensiones) que se adapten a tu dataset.
Entrenar la Red!
A entrenar la red neuronal. Como dato informativo, en mi ordenador macbook de 4 núcleos y 8GB
de RAM, tardó 7 horas en entrenar las 300 imágenes del dataset de lego con 7 épocas (y 5 veces cada
imagen).
Detección de Objetos con Python 302
Al finalizar verás que se ha creado un archivo nuevo llamado “red_lego.h5” que contiene los pesos
de la red creada.
Probar la Red
Para finalizar, podemos probar la red con imágenes nuevas, distintas que no ha visto nunca, veamos
cómo se comporta la red!
Crearemos unas funciones de ayuda para dibujar el rectángulo sobre la imagen original y guardar
la imagen nueva:
15 1e-3 * image_h,
16 (0,255,0), 2)
17
18 return image
Recuerda que utilizaremos el archivo de pesos creado al entrenar, para recrear la red (esto nos permite
poder hacer predicciones sin necesidad de reentrenar cada vez).
1 mejores_pesos = "red_lego.h5"
2 image_path = "images/test/lego_girl.png"
3
4 mi_yolo = YOLO(input_size = tamanio,
5 labels = labels,
6 max_box_per_image = 5,
7 anchors = anchors)
8
9 mi_yolo.load_weights(mejores_pesos)
10
11 image = cv2.imread(image_path)
12 boxes = mi_yolo.predict(image)
13 image = draw_boxes(image, boxes, labels)
14
15 print('Detectados', len(boxes))
16
17 cv2.imwrite(image_path[:-4] + '_detected' + image_path[-4:], image)
Como salida tendremos una nueva imagen llamada “lego_girl_detected.png” con la detección reali-
zada.
Detección de Objetos con Python 304
Esta imagen
me fue prestada por @Shundeez_official⁵⁴⁶, muchas gracias! Les recomiendo ver su cuenta de
Instagram que es genial!
⁵⁴⁶https://www.instagram.com/Shundeez_official/
Detección de Objetos con Python 305
Detección de Objetos con Python 306
Luego de procesar el video, nos dejará una versión nueva del archivo mp4 con la detección que
realizó cuadro a cuadro.
Y para usar tu cámara: (presiona ‘q’ para salir)
Detección de Objetos con Python 307
Resumen
Esta fue la parte práctica de una de las tareas más interesantes dentro de la Visión Artificial, que es la
de lograr hacer detección de objetos. Piensen todo el abanico de posibilidades que ofrece poder hacer
esto! Podríamos con una cámara contabilizar la cantidad de coches y saber si hay una congestión de
tráfico, podemos contabilizar cuantas personas entran en un comercio, si alguien toma un producto
de una estantería y mil cosas más! Ni hablar en robótica, donde podemos hacer que el robot vea y
pueda coger objetos, ó incluso los coches de Tesla con Autopilot… Tiene un gran potencial!
Además en este capíítulo te ofrece la posibilidad de entrenar tus propios detectores, para los casos
de negocio que a ti te importan.
En un próximo artículo espero escribir sobre la Teoría que hoy pusimos en práctica sobre Detección
de Objetos.
Recursos
Recuerda todo lo que tienes que descargar:
* Código Python completo en la Jupyter Notebook⁵⁴⁷
* Los pesos iniciales de la red⁵⁴⁸ YOLOv2
* Set de imágenes y anotaciones Lego⁵⁴⁹ (adquiriendo el libro de pago ó gratis)
Y enlaces a otros artículos de interés:
* Object Detection⁵⁵⁰
* A Brief History of CNN in Image Segmentation⁵⁵¹
* Beginers Guito to implementing Yolov3 in Tensorflow⁵⁵²
* Practical Guide to Object Detection with Yolo⁵⁵³
* A very shallow overview of Yolo and Darknet⁵⁵⁴
* Yolo v2 object detection⁵⁵⁵
⁵⁴⁷https://github.com/jbagnato/machine-learning/blob/master/Ejercicio_Object_Detection.ipynb
⁵⁴⁸https://drive.google.com/file/d/1Q9WhhRlqQbA4jgBkCDrynvgquRXZA_f8/view?usp=sharing
⁵⁴⁹https://leanpub.com/aprendeml
⁵⁵⁰https://www.saagie.com/blog/object-detection-part1/
⁵⁵¹https://blog.athelas.com/a-brief-history-of-cnns-in-image-segmentation-from-r-cnn-to-mask-r-cnn-34ea83205de4
⁵⁵²https://machinelearningspace.com/yolov3-tensorflow-2-part-1/
⁵⁵³https://www.analyticsvidhya.com/blog/2018/12/practical-guide-object-detection-yolo-framewor-python/
⁵⁵⁴https://martinapugliese.github.io/recognise-objects-yolo/
⁵⁵⁵https://www.geeksforgeeks.org/yolo-v2-object-detection/
Anexo I: Webscraping
Ejemplo Web Scraping en Python: IBEX35® la Bolsa de
Madrid
En este artículo aprenderemos a utilizar la librería BeatifulSoap de Python para obtener contenidos
de páginas webs de manera automática.
En internet encontramos de todo: artículos, noticias, estadísticas e información útil (¿e inútil?), pero
¿cómo la extraemos? No siempre se encuentra en forma de descarga ó puede haber información
repartida en multiples dominios, ó puede que necesitemos información histórica, de webs que
cambian con el tiempo.
Para poder generar nuestros propios archivos con los datos que nos interesan y de manera automática
es que utilizaremos la técnica de WebScraping.
Contenidos:
• Requerimientos para WebScraping
• Lo básico de HTML y CSS que debes saber
• Inspeccionar manualmente una página web
• Al código! Obtener el valor actual del IBEX35®** de la Bolsa de Madrid**
• Exportar a archivo csv (y poder abrir en Excel)
• Otros casos frecuentes de “rascar la web”
Puedes ver y descargar el código python completo de este artículo desde GitHub haciendo
click aquí⁵⁵⁶
Requerimientos
Para poder usar esta técnica hay diversas librerías, pero utilizaremos una muy popular llamada Beau-
tiful Soap. Como siempre, te recomiendo tener instalado el ambiente de desarrollo con Anaconda⁵⁵⁷
que ya trae incluida la librería. Si no, lo puedes instalar desde línea de comandos con:
⁵⁵⁶https://github.com/jbagnato/machine-learning/blob/master/Ejemplo_WebScraping_Bolsa_y_Futbol.ipynb
⁵⁵⁷http://www.aprendemachinelearning.com/instalar-ambiente-de-desarrollo-python-anaconda-para-aprendizaje-automatico/
Anexo I: Webscraping 310
Si bien utilizaremos una Jupyter Notebook para el código Python 3, podríamos ejecutar un archivo
de texto plano “.py” desde nuestra Terminal.
1 <html>
2 <head><title>Titulo de pagina</title>
3 </head>
4 <body>
5 <p> Soy un parrafo</p>
6 <div>Soy un texto en un DIV</div>
7 <table><tr><td>soy una celda dentro de una tabla</td></tr>
8 </table>
9 </body>
10 </html>
Aqui Vemos las etiquetas básicas de HTML, es decir las de inicio y cierre y dentro de body el
contenido de la página. Como ejemplo vemos un párrafo “p”, un “div” y una tabla.
¿Y porqué CSS? en realidad no necesitamos estrictamente saber CSS, pero sí sus selectores, puesto
que nos pueden ser de mucha ayuda. Lo básico para comprender selectores, usando este bloque de
ejemplo es:
1 <html>
2 <head></head>
3 <body>
4 <div class="contenedor">
5 <div id="123" name="bloque_bienvenida" class="verde">
6 Bienvenido a mi web
7 </div>
8 </div>
9 </body>
10 </html>
Anexo I: Webscraping 311
• la más directa será si la etiqueta tiene un atributo id que es único en el ejemplo “123”
• Podríamos buscar los nodos de tipo div, pero podría haber muchos y deberemos filtrarlos.
• Podemos filtrar un div con el atributo name = “bloque_bienvenida”.
• Podemos buscar por clase CSS, en el ejemplo “verde”.
• Muchas veces se combinan selectores, por ejemplo: dentro de la clase “contenedor”, la clase
“verde”. O decir: “traer un div con la clase verde”
La librería de Beautiful Soap nos permite buscar dentro de los nodos del árbol de la página web,
también conocido como DOM. Al final del artículo veremos como obtener el texto “Bienvenido a
mi web” con diversos selectores (y en la Jupyter Notebook de Github⁵⁵⁸).
Esta es la web de la bolsa de Madrid⁵⁵⁹, en donde nos interesa obtener el Indice del IBEX35®
Para el ejemplo inspeccionaremos la web de la Bolsa de Madrid⁵⁶⁰. ¿Qué es eso de inspeccionar?
Bueno, los navegadores web “modernos” (Safari, Firefox, Chrome) cuentan con una opción que nos
permite ver el código html completo de la página que estamos viendo.
Además existe una opción de “inspección del código” que nos permite ver el HTML, Javascript, CSS
y la web al mismo tiempo. Con ello buscaremos la manera de extraer el texto que nos interesa, si
buscamos por id, por algún atributo, clase ó nodos.
Por lo general podemos inspeccionar haciendo click con el botón derecho del mouse sobre el área
que nos interesa. Veamos cómo hacerlo con un gif animado :)
⁵⁵⁸https://github.com/jbagnato/machine-learning/blob/master/Ejemplo_WebScraping_Bolsa_y_Futbol.ipynb
⁵⁵⁹http://www.bolsamadrid.es/esp/aspx/Indices/Resumen.aspx
⁵⁶⁰http://www.bolsamadrid.es/esp/aspx/Indices/Resumen.aspx
Anexo I: Webscraping 312
⁵⁶¹
Al hacer clic derecho, aparece la opción de Inspeccionar Elemento. Así podemos ver las entrañas
de la web en la que estamos navegando y pensar la mejor opción para extraer contenidos.
En nuestro caso nos interesa obtener el valor de la fila con nombre IBEX35® y el valor de la columna
“último”.
1 import requests
2 from bs4 import BeautifulSoup
3 import csv
4 from datetime import datetime
1 # indicar la ruta
2 url_page = 'http://www.bolsamadrid.es/esp/aspx/Indices/Resumen.aspx'
Y ahora haremos el request a esa ruta y procesaremos el HTML mediante un objeto de tipo
BeautifulSoap:
⁵⁶¹https://i1.wp.com/www.aprendemachinelearning.com/wp-content/uploads/2019/01/inspeccionar_web_safari.gif
Anexo I: Webscraping 313
Bien, ahora toca pensar la estrategia para acceder al valor. En nuestro caso nos interesa primero
acceder a la tabla, y de allí a sus celdas. Por suerte la tabla tiene un id único!
⁵⁶²
Aqui vemos el id de la tabla marcado en amarillo.
En rojo, se muestra la tercera celda de la primer fila a la que queremos acceder.
Bien, ahora dentro de la tabla y siendo que en este caso no tenemos un acceso directo a las celdas por
ids únicos ni por clases, sólo nos queda iterar… Entonces, accederemos a la primer fila y obtendremos
de las celdas el nombre del índice y su valor:
NOTA: realmente es la segunda fila, pues hay un encabezado, por eso usamos el índice 1
y no el cero.
1 name=""
2 price=""
3 nroFila=0
4 for fila in tabla.find_all("tr"):
5 if nroFila==1:
6 nroCelda=0
7 for celda in fila.find_all('td'):
8 if nroCelda==0:
9 name=celda.text
10 print("Indice:", name)
⁵⁶²https://i0.wp.com/www.aprendemachinelearning.com/wp-content/uploads/2019/01/inspecciona_bolsa_mad.png
Anexo I: Webscraping 314
11 if nroCelda==2:
12 price=celda.text
13 print("Valor:", price)
14 nroCelda=nroCelda+1
15 nroFila=nroFila+1
1 # Abrimos el csv con append para que pueda agregar contenidos al final del archivo
2 with open('bolsa_ibex35.csv', 'a') as csv_file:
3 writer = csv.writer(csv_file)
4 writer.writerow([name, price, datetime.now()])
Finalmente obtenemos el archivo llamado “bolsa_ibex35.csv” listo para ser usado en nuestro proyec-
to :)
Podemos abrir el archivo csv en Excel, LibreOffice, SpreadSheets ó como archivo de texto plano.
Anexo I: Webscraping 315
1 url_page = 'https://www.lifeder.com/cientificos-famosos/'
2 page = requests.get(url_page).text
3 soup = BeautifulSoup(page, "lxml")
4 contenido = soup.find('div', attrs={'class': 'td-post-content'})
5 items = contenido.find_all('a')
6 for item in items:
7 print(item['href'])
En el archivo Jupyter Notebook de mi cuenta de Github⁵⁶³ se ven estos ejemplos (y alguno más).
Resumen
Ahora sabemos cómo afrontar el proceso de obtener información de cualquier página web. Resu-
miendo el procedimiento básico que seguimos es:
* Mediante ID
* Mediante Etiqueta
* Mediante Clases CSS
* Otros Atributos
6. Guardamos los datos en csv
Repasando, cuando ya tenemos el contenido en un objeto “soap”, solemos utilizar los métodos find()
ó para múltiples etiquetas el find_all().
Si combinamos un script para webscraping, como en el ejemplo para capturar valores de la bolsa con
el cron del sistema (ó con algún tipo de “repetidor de tareas del sistema”) que nos permita ejecutar
nuestro código cada “x” tiempo, podremos generar un valioso archivo de información muy a medida
de lo que necesitamos.
Otro ejemplo “clásico” es el de la obtención automática de los resultados de partidos de fútbol y en
el código de este ejemplo en Github⁵⁶⁴, encontrarás cómo hacerlo.
Obtener el Jupyter Notebook con código Python con este y más ejemplos de WebSca-
ping⁵⁶⁵
Si bien este artículo no es estrictamente sobre Machine Learning, me pareció bueno comentarlo
pues he utilizado técnicas de Webscraping en ejercicios anteriores (como en el de Procesamiento
del Lenguaje Natural⁵⁶⁶) pasando por alto la explicación de esta porción del código. Además es un
recurso utilizado frecuentemente para trabajar y para hacer pequeños experimentos con datos.
⁵⁶⁴https://github.com/jbagnato/machine-learning/blob/master/Ejemplo_WebScraping_Bolsa_y_Futbol.ipynb
⁵⁶⁵https://github.com/jbagnato/machine-learning/blob/master/Ejemplo_WebScraping_Bolsa_y_Futbol.ipynb
⁵⁶⁶http://www.aprendemachinelearning.com/ejercicio-nlp-cuentos-de-hernan-casciari-python-espanol/
Anexo II: Machine Learning en la
Nube
¿Machine Learning en la Nube? Google Colaboratory
con GPU!
Por increíble que parezca, tenemos disponible una cuenta gratuita para programar nuestros modelos
de Machine Learning en la nube, con Python, Jupyter Notebooks de manera remota y hasta con GPU
para poder aumentar nuestro poder de procesamiento…. gratis! sí sí… esto no es un “cuento del tío”
ni tiene trampa!…
Si tienes una tarjeta Nvidia con GPU ya instalada, felicidades ya tienes el poder! Si no la tienes y no
tienes previsto invertir unos cuántos dólares en comprarla, puedes tener toda(*) su potencia desde
la nube!
(*)NOTA: Google se reserva el poder limitar el uso de GPU si considera que estás abusando ó
utilizando en demasía ese recurso ó para fines indebidos (como la minería de bitcoins)
Pero si quieres poder usar cualquier archivo, por ej. csv que tengas en tu unidad de drive, deberas
ejecutar en una celda:
Te pedirá que hagas click a un enlace y escribas un código que te dará cuando autorices la app.
Cuando vuelvas y hagas actualizar en el tab de archivos veras tu unidad montada y lista para usar !!
1. seleccionamos GITHUB,
2. copiamos la dirección del repositorio, en nuestro caso https://github.com/jbagnato/machine-
learning/⁵⁷³
3. y le damos a la lupa de buscar.
4. Nos aparecerá el listado con los archivos del repo.
5. Y de allí seleccionamos el cuaderno llamado Ejercicio_CNN.ipynb
• !wget https://github.com/jbagnato/machine-learning/raw/master/sportimages.zip *
y veremos que aparece nuestro archivo zip en el listado (dale a “Actualizar” si hace falta)
⁵⁷³https://github.com/jbagnato/machine-learning/
Anexo II: Machine Learning en la Nube 322
⁵⁷⁴
RECUERDA habilitar el entorno de ejecución con GPU como vimos antes. Ahora Ya podemos
ejecutar todas las celdas y veremos qué rápido ejecuta la CNN con GPU, en comparación con CPU.
Pasa de tardar 4 minutos a sólo 40 segundos.
Resumen
Hemos visto que tenemos la opción de tener nuestro ambiente de desarrollo local⁵⁷⁵ pero también
esta alternativa de poder programar, experimentar y trabajar en la nube. Gracias a este servicio
podemos tener listo el ambiente en pocos minutos y aprovechar las ventajas que nos ofrece, sobre
todo el uso de GPU que es un recurso del que no todos disponemos.
Otros Recursos
Otros artículos que explican el uso de Google Colab (en inglés):
⁵⁷⁴http://www.aprendemachinelearning.com/wp-content/uploads/2019/02/descomprimir_imagenes.png
⁵⁷⁵http://www.aprendemachinelearning.com/instalar-ambiente-de-desarrollo-python-anaconda-para-aprendizaje-automatico/
Anexo II: Machine Learning en la Nube 323
⁵⁷⁶https://medium.com/deep-learning-turkey/google-colab-free-gpu-tutorial-e113627b9f5d
⁵⁷⁷https://medium.com/lean-in-women-in-tech-india/google-colab-the-beginners-guide-5ad3b417dfa
⁵⁷⁸https://blog.slavv.com/picking-a-gpu-for-deep-learning-3d4795c273b9
Anexo III: Principal Component
Analysis
En este capítulo veremos una herramienta muy importante para nuestro kit de Machine Learning⁵⁷⁹
y Data Science: PCA para Reducción de dimensiones. Como bonus-track veremos un ejemplo
rápido-sencillo en Python usando Scikit-learn.
Introducción a PCA
Imaginemos que queremos predecir los precios de alquiler de vivienda del mercado. Al recopilar
información⁵⁸⁰ de diversas fuentes tendremos en cuenta variables como tipo de vivienda, tamaño
de vivienda, antigüedad, servicios, habitaciones, con/sin jardín, con/sin piscina, con/sin muebles
pero también podemos tener en cuenta la distancia al centro, si hay colegio en las cercanías, o
supermercados, si es un entorno ruidoso, si tiene autopistas en las cercanías, la “seguridad del
barrio”, si se aceptan mascotas, tiene wifi, tiene garaje, trastero… y seguir y seguir sumando variables.
Es posible que cuanta más (y mejor) información, obtengamos una predicción más acertada. Pero
también empezaremos a notar que la ejecución de nuestro algoritmo seleccionado⁵⁸¹ (regresión lineal,
redes neuronales, etc.) empezará a tomar más y más tiempo y recursos. Es posible que algunas de
las variables sean menos importantes y no aporten demasiado valor a la predicción. También
podríamos acercarnos peligrosamente a causar overfitting⁵⁸² al modelo.
Eliminar por completo algunas dimensiones no estaría mal, pero deberemos tener certeza en que es-
tamos quitando dimensiones poco importantes. Por ejemplo para nuestro ejemplo, podemos suponer
que el precio de alquiler no cambiará mucho si el dueño acepta mascotas en la vivienda. Podría ser un
⁵⁷⁹http://www.aprendemachinelearning.com/que-es-machine-learning/
⁵⁸⁰http://www.aprendemachinelearning.com/7-pasos-machine-learning-construir-maquina/
⁵⁸¹http://www.aprendemachinelearning.com/principales-algoritmos-usados-en-machine-learning/
⁵⁸²http://www.aprendemachinelearning.com/que-es-overfitting-y-underfitting-y-como-solucionarlo/
Anexo III: Principal Component Analysis 325
Tranquilos, que todo esto ya lo hace solito scikit-learn (u otros paquetes Python). Ahora que
tenemos las nuevas dimensiones, deberemos seleccionar con cuales nos quedamos.
⁵⁸³https://es.wikipedia.org/wiki/Vector_propio_y_valor_propio
Anexo III: Principal Component Analysis 326
Y veremos cómo los resultados “comprar ó alquilar” tienen [icon name=”angle-double-left” class=””
unprefixed_class=”“]bastante buena[icon name=”angle-double-right” class=”” unprefixed_class=””]
separación en 2 dimensiones.
1 #importamos librerías
2 import pandas as pd
3 import numpy as np
4 import matplotlib.pyplot as plt
5 %matplotlib inline
6 plt.rcParams['figure.figsize'] = (16, 9)
7 plt.style.use('ggplot')
8 from sklearn.decomposition import PCA
9 from sklearn.preprocessing import StandardScaler
10
11 #cargamos los datos de entrada
12 dataframe = pd.read_csv(r"comprar_alquilar.csv")
13 print(dataframe.tail(10))
14
15 #normalizamos los datos
16 scaler=StandardScaler()
17 df = dataframe.drop(['comprar'], axis=1) # quito la variable dependiente "Y"
18 scaler.fit(df) # calculo la media para poder hacer la transformacion
19 X_scaled=scaler.transform(df)# Ahora si, escalo los datos y los normalizo
20
21 #Instanciamos objeto PCA y aplicamos
22 pca=PCA(n_components=9) # Otra opción es instanciar pca sólo con dimensiones nuevas \
23 hasta obtener un mínimo "explicado" ej.: pca=PCA(.85)
24 pca.fit(X_scaled) # obtener los componentes principales
25 X_pca=pca.transform(X_scaled) # convertimos nuestros datos con las nuevas dimensione\
26 s de PCA
27
28 print("shape of X_pca", X_pca.shape)
29 expl = pca.explained_variance_ratio_
30 print(expl)
Anexo III: Principal Component Analysis 328
31 print('suma:',sum(expl[0:5]))
32 #Vemos que con 5 componentes tenemos algo mas del 85% de varianza explicada
33
34 #graficamos el acumulado de varianza explicada en las nuevas dimensiones
35 plt.plot(np.cumsum(pca.explained_variance_ratio_))
36 plt.xlabel('number of components')
37 plt.ylabel('cumulative explained variance')
38 plt.show()
39
40 #graficamos en 2 Dimensiones, tomando los 2 primeros componentes principales
41 Xax=X_pca[:,0]
42 Yax=X_pca[:,1]
43 labels=dataframe['comprar'].values
44 cdict={0:'red',1:'green'}
45 labl={0:'Alquilar',1:'Comprar'}
46 marker={0:'*',1:'o'}
47 alpha={0:.3, 1:.5}
48 fig,ax=plt.subplots(figsize=(7,5))
49 fig.patch.set_facecolor('white')
50 for l in np.unique(labels):
51 ix=np.where(labels==l)
52 ax.scatter(Xax[ix],Yax[ix],c=cdict[l],label=labl[l],s=40,marker=marker[l],alpha=\
53 alpha[l])
54
55 plt.xlabel("First Principal Component",fontsize=14)
56 plt.ylabel("Second Principal Component",fontsize=14)
57 plt.legend()
58 plt.show()
Anexo III: Principal Component Analysis 329
⁵⁸⁹
En esta gráfica de variabilidad explicada acumulada, vemos que tomando los primeros 5 componen-
tes llegamos al 85%
⁵⁸⁹http://www.aprendemachinelearning.com/wp-content/uploads/2018/10/graficaPCA.png
Anexo III: Principal Component Analysis 330
⁵⁹⁰
Aquí vemos que al reducir las 9 dimensiones iniciales a tan sólo 2 logramos darnos una idea de dónde
visualizar nuestras predicciones para comprar o alquilar casa.
Resumen
Con PCA obtenemos:
1. una medida de como cada variable se asocia con las otras (matriz de covarianza)
2. La dirección en las que nuestros datos están dispersos (autovectores)
3. La relativa importancia de esas distintas direcciones (autovalores)
PCA combina nuestros predictores y nos permite deshacernos de los autovectores de menor impor-
tancia relativa.
PCA para minimizar esta debilidad. Entre otros se encuentran: RandomizedPCA⁵⁹², SparcePCA y
KernelPCA⁵⁹³. Por último decir que PCA fue creado en 1933 y ha surgido una buena alternativa en
2008 llamada t-SNE⁵⁹⁴ con un enfoque distinto.
Aplicando PCA al MNIST con una varianza retenida del 90% logramos reducir las dimen-
siones de 748 a 236. Ejecutar Regresión Logística ahora toma 10 segundos y la precisión
obtenida sigue siendo del 91% !!!
Más recursos
• El ejercicio Python en mi cuenta de Github⁵⁹⁹
• Archivo csv de Entrada para el ejercicio⁶⁰⁰