Los datos nunca se quedan quietos, al igual que la red de aviones que sobrepasan nuestras cabezas todos los días en infinidad de momentos. Las personas siempre intentamos encontrar las mejores soluciones a nuestros problemas o necesidades, pero ¿Sabíais que el análisis de datos es nuestro mejor aliado en estas ocasiones?

¡En este nuevo webinar te lo demostramos! ¿Quieres saber cómo viaja un Data Scientist?

El análisis de datos tiene infinitas aplicaciones, en este webinar podremos aprender una de ellas, cómo optimizar las búsquedas de vuelos directos mediante Python.

¿Te has pasado horas buscando las mejores combinaciones de vuelos para llegar a tu destino? Jorge López Lázaro (Senior-Expert Data Scientist en BBVA) se encargará de explicar mediante este caso de uso, cómo solucionar estos problemas con Python.

En este evento se resumirá en:

No dejes escapar esta oportunidad e infórmate junto a verdaderos profesionales del Big Data.

Jorge López Lázaro

Senior-Expert Data Scientist en BBVA

¡Anímate y realiza este caso práctico para desarrollar tus capacidades en Python!

¿Qué tienes que hacer para asistir a este #webinargratuito? Muy sencillo. Únicamente tendrás que registrarte desde este evento y esperar al día 29 (se realizará desde LinkedIn Live por lo que se deberá acceder a la plataforma de LinkedIn a la hora del evento).

Regístrate aquí gratis para asistir online:

🔵 Esta sesión será online en directo y desde la plataforma de LinkedIn Live.

🔵 Este formulario es para apuntarte a la sesión online.

🔵 Durante la sesión podrás preguntar todas las dudas que tengas al ponente y las irá respondiendo. No te quedes con ninguna duda.

🔵 Al registrarte recibirás un enlace en tu email con el que podrás conectarte a la sesión online.

En este artículo creado por Rafael Garrote Hernández, vamos a conocer más a fondo el Snowflake.

El ecosistema de almacenes de datos está en continuo crecimiento y cada poco oímos de un nuevo miembro de la familia. En este caso quiero hablaros de Snowflake, que recoge la tradición de las bases de datos específicas para crear un data Warehouse y la actualiza para adecuarse a los tiempos que imperan, haciéndola nativa al cloud, con capacidades para gestionar grandes volúmenes de datos y con capacidades de procesamiento en streaming.

Snowflake, como su propio nombre indica, es una base de datos pensada para albergar los modelos de datos dimensionales tradicionales de un data warehouse, copo de nieve, data mart, pero además permite adecuarse a las necesidades para crear modelos más actuales como data vaults o data hubs. Sus principales características son que está diseñada para trabajar de forma nativa en los principales proveedores de infraestructura y que separa la capa de almacenamiento de datos de la capa de procesamiento de datos. Son precisamente estas dos características las que hacen que Snowflake pueda gestionar volúmenes de datos mucho más grandes que sus predecesoras. Vamos a ver sus características más en detalle.

Arquitectura

Snowflake está diseñada en una arquitectura con tres capas; la capa de almacenamiento que se encarga de persistir el dato y gestionar las micro particiones, una capa de procesamiento de datos independiente al resto organizada en clusters aislados de máquinas que trabajan sobre el conjunto de datos y por último la capa de servicios cloud entre los que encontramos la autorización, la gestión de la infraestructura, gestión de metadatos, control de accesos, seguridad y parseo y optimización de consultas.

Almacenamiento de datos

Como capa de almacenamiento Snowflake utiliza el sistema de almacenamiento del proveedor de infraestructura, AWS S3, Azure Blob Storage y Google Cloud Storage respectivamente. De esta manera, podemos utilizar estos almacenamientos como capa de staging desde la que cargar los datos de forma sencilla en Snowflake.

Permite almacenar tanto datos estructurados como semiestructurados y con soporte nativo para formatos abiertos de datos: JSON, XML, CSV, Avro, Parquet, ORC, etc.

El almacenamiento está orientado a columnas lo que la hace idónea para ejecutar trabajos de tipo analítico tradicionales de un data warehouse y además permite particionado de las tablas.

Y por último es transaccional y ACID, dos características muy valiosas y que no encontramos en todos los competidores.

Micro Particionado

Snowflake basa su almacenamiento en lo que él denomina micro particiones que gestiona de forma automática y transparente para el usuario. Las tablas se particionan de forma transparente utilizando el orden de carga o inserción de los datos creando particiones de 50 a 500 MB.

Para esas consultas que necesitan más rendimiento o para gestionar volúmenes de datos más grandes, Snowflake nos permite modificar el comportamiento por defecto del micro particionado y gestionar estas particiones para optimizar las consultas sobre conjuntos de datos más grandes especificando la clave de particionado con la cláusula CLUSTER BY tanto al crear la tabla como al modificarla. De esta manera podremos indicar qué campo o campos queremos utilizar como clave de particionado para crear unas particiones acordes al patrón de acceso al dato optimizando por tanto el rendimiento de las consultas.

Time travel

El almacenamiento de datos de Snowflake permite indicar un tiempo de retención a los datos entre 1 y 90 días, de tal forma que se puede consultar el estado de los datos en un punto anterior en el tiempo, por ejemplo, antes de que hayan sido modificados o borrados. También permite clonar o recuperar tablas en un punto en concreto en el pasado, incluso si se han borrado.

Adicionalmente al tiempo de retención del time travel, se le puede indicar a Snowflake un tiempo adicional de como máximo 7 días, en los que guardará los datos de las tablas para poder recuperarse de fallos eventuales. Estos datos sólo son recuperables por Snowflake y no se pueden consultar hasta su recuperación. Este tiempo de fail-safe empieza a contar justo después de que termine el tiempo de retención del time travel.

Capa de computación

Como se ha indicado antes, la capa de procesamiento está separada de la capa de almacenamiento y consta de uno o varios clusters de máquinas encargados de realizar las tareas de cómputo sobre los datos. Estos clusters se denominan Virtual Warehouses y podemos crear tantos como necesitemos. Idealmente crearemos uno por tipología de procesos que realicemos sobre los datos. Por ejemplo podemos tener un Virtual Warehouse para realizar las tareas de ETL y otro para los procesos de ciencia de datos. De esta manera garantizamos los recursos necesarios para cada uno de estos procesos ya que los Virtual Warehouses no comparten recursos entre sí.

Estos clusters se pueden configurar para que crezcan o decrezcan de forma elástica según la demanda de carga en cada momento y además se pueden auto suspender y reiniciar según las necesidades para hacer una correcta gestión de los recursos y del coste de la infraestructura.

Snowflake no sólo está pensada para ejecutar sentencias de consulta, sino que al igual que sus predecesoras, permite realizar procesos de Extracción Carga y Transformación (ELT) para realizar las transformaciones de los datos e integrarlos en el modelo dimensional creado. Para ello permite encadenar las sentencias para ejecutarlas en un orden específico y bajo ciertas condiciones.

Cada sentencia SQL es una tarea o task y estas task se pueden encadenar formando un árbol de ejecución. Este árbol representa el pipeline de ejecución de una ELT. Una Task se puede programar para ser ejecutada de forma periódica o como consecuencia de una Task anterior. Esto que permite encadenar Task en función del resultado anterior en lo que se denomina Tasks condicionales.

Adquisición o ingesta de datos

Para ingestar datos en Snowflake, esta hace uso del almacenamiento de datos nativo del cloud, así por ejemplo en AWS S3, dejaríamos los ficheros con el dato en bruto a ingestar en un bucket de S3. Indicaremos a snowflake que use ese bucket como staging, creamos la tabla que alojará estos datos y le decimos a Snowflake que copie los datos del staging a la tabla. Una vez que los datos ya están en Snowflake podemos crear los pipelines necesarios para transformar e integrar el dato según nuestras necesidades.

Además de este procesamiento de datos por lotes o en batch, Snowflake provee de un mecanismo para la ingesta de datos en streaming y/o tiempo real que denomina Snowpipe.

Snowpipe permite quedarse escuchando un fichero de la capa de almacenamiento de la infraestructura, por ejemplo AWS S3 y cada nueva inserción en este fichero, automáticamente se insertarla en la tabla de destino. Otra opción es utilizar el conector de Kafka que permite conectar Snowflake a Kafka para consumir los mensajes que se vayan almacenando en los topics de Kafka.

Junto con estos mecanismos de ingesta en streaming, Snowflake dispone de un conjunto de operaciones de ventana para poder realizar operaciones de transformación y cálculo en streaming.

A parte de todas estas funcionalidades Snowflake provee las siguientes capacidades:

Por todo lo que hemos visto en este artículo Snowflake moderniza los sistemas de bases de datos tradicionales para data Warehouses, actualizándose a las necesidades actuales del mercado convirtiéndose en una tendencia al alza sobre todo si se busca una alternativa que te independice del proveedor de infraestructura considerándola una alternativa a tener en cuenta a la hora de diseñar nuestro sistema informacional.

¡Si te ha gustado el contenido de este artículo no te olvides de suscribirte a la newsletter!

En este artículo creado por Héctor Escaso Gil, vamos a crear una red neuronal que nos sirva de clasificador de imágenes para algunas de las razas que habitan la tierra media.

Vamos a crear un dataset de imágenes de 5 razas del universo Tolkien: Orcos, Elfos, Enanos, Hobbits y Magos.

El principal problema que tenemos, es que contamos con un reducido número de imágenes, unas 200 de cada raza. Para solucionar esto, vamos a utilizar dos técnicas:

Transfer Learning -> Entrenar con tan pocas imágenes es un problema, ya que el modelo tiene pocos ejemplos para su aprendizaje, por lo que utilizaremos la red neuronal preentrenada “mobilenet_2”. Eliminaremos la capa de salida e incluiremos una nueva que se adapte a nuestro modelo.
Data Augmentation -> Aunque contemos con una red preentrenada muy potente, necesitamos entrenar la última capa. Así que utilizaremos esta técnica con la generaremos un mayor número de imágenes para nuestro entrenamiento.
Una vex hayamos entrenado nuestro modelo haremos algunas predicciones usando imágenes de prueba.

Comencemos con el ejercicio

1. Creación del dataset

Para crear nuestro dataset, vamos a buscar las imágenes directamente en google. Haremos una búsqueda por cada una de las razas y nos descargaremos todas las imágenes fácilmente con la extensión de Chrome Download All Images.

Tras esto limpiaremos nuestras imágenes, eliminando duplicados y borrando las que no nos sirvan para nuestro entrenamientos. Yo he seleccionado exactamente 200 por cada raza.

2. Descarga y preparación de los datos

Os dejo las imágenes que he utilizado en mi repositorio.

Tengo las imágenes en el drive, así que permito acceder a mis archivos desde colab.

from google.colab import drive
drive.mount('/content/drive')
Mounted at /content/drive

Tras esto, entro en cada carpeta y descomprimo los archivos zip

!unzip /content/drive/MyDrive/ClasificadorImagenes/Elfos.zip
!unzip /content/drive/MyDrive/ClasificadorImagenes/Enanos.zip
!unzip /content/drive/MyDrive/ClasificadorImagenes/Magos.zip
!unzip /content/drive/MyDrive/ClasificadorImagenes/Orcos.zip
!unzip /content/drive/MyDrive/ClasificadorImagenes/Hobbits.zip

Revisamos que la descarga haya sido correcta, mostrando el número de imágenes en cada carpeta.

#Mostrar cuantas imagenes tengo de cada categoria
!ls /content/Elfos | wc -l 
!ls /content/Magos | wc -l  
!ls /content/Orcos | wc -l 
!ls /content/Hobbits | wc -l 
!ls /content/Enanos | wc -l 
200
200
200
200
200

Una vez comprobado que la descarga ha sido correcta, elimino la conexión con drive.

drive.flush_and_unmount()

Vamos a ver alguna imágenes a ver qué pinta tienen.

# Utilizaremos pyplot
import os
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

plt.figure(figsize=(15,15))

carpeta = '/content/Hobbits'
imagenes = os.listdir(carpeta)

for i, nombreimg in enumerate(imagenes[:25]):
  plt.subplot(5,5,i+1)
  imagen = mpimg.imread(carpeta + '/' + nombreimg)
  plt.imshow(imagen)

Instalamos 2 librerías que vamos a necesitar.

!pip install split-folders
!pip install pytest-shutil

Vamos a utilizar la librería splitfolders para separar nuestras imágenes en train, test y validación. Esta librería coge todas las carpetas que haya y crea 3 carpetas nuevas por cada una de ellas con la proporción de imágenes que le indiquemos.

Como tenemos la carpeta “sample_data” que se genera automáticamente y no la necesitamos, la vamos a eliminar previamente.

import shutil
shutil.rmtree('/content/sample_data') # Eliminamos la carpeta sample_data

Tras esto, hacemos la división de las imágenes entre train, validation y test.

import splitfolders
splitfolders.ratio('/content', output = "dataset", ratio=(0.78, 0.2, 0.02)) # Haremos copia de la imágenes y las dividiremos en 3 carpetas dentro de "dataset".
Copying files: 1003 files [00:00, 5322.86 files/s]

Comprobamos una carpeta para ver que se haya realizado correctamente.

!ls /content/dataset/train/Elfos | wc -l 
!ls /content/dataset/val/Elfos | wc -l 
!ls /content/dataset/test/Elfos | wc -l 
156
40
4

Se ha creado un archivo .config en cada una de las carpetas. Los eliminamos porque sino aparecerían como una clase más e interferiría en el entrenamiento.

!rm -rf /content/dataset/train/.config
!rm -rf /content/dataset/val/.config
!rm -rf /content/dataset/test/.config

3. Data Augmentation

Está técnica se basa en la creación de nuevas imágenes partiendo de los datos antiguos con los que contamos. En este caso haciendo zoom de las imágenes, reescalandolas, realizando un flip horizontal, etc…

Vamos a utilizar ImageDataGenerator para crear nuestros generadores de imágenes para los sets de entrenamiento y validación, aunque en la validación lo único que haremos será reescalar las imágenes.

#Aumento de datos con ImageDataGenerator
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import numpy as np

#Crear el dataset generador
train_datagen = ImageDataGenerator(
    rescale=1. / 255,
    rotation_range = 30,
    width_shift_range = 0.25,
    height_shift_range = 0.25,
    shear_range = 15,
    zoom_range = [0.5, 1.5],
    #validation_split = 0.2 -> En este caso no modificamos las imágenes de validación.
)

validation_datagen = ImageDataGenerator(rescale=1. / 255)

#Generadores para sets de entrenamiento y pruebas
data_gen_train = train_datagen.flow_from_directory('/content/dataset/train', target_size=(224,224),
                                                     batch_size=32, shuffle=True)

data_gen_val = validation_datagen.flow_from_directory('/content/dataset/val', target_size=(224,224),
                                                     batch_size=32, shuffle=True)
Found 780 images belonging to 5 classes.
Found 200 images belonging to 5 classes.

Vamos a imprimir unas imágenes aleatorias para ver como funciona nuestro generador.

#Imprimir 10 imagenes del generador de entrenamiento
for imagen, etiqueta in data_gen_train:
  for i in range(10):
    plt.subplot(2,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.imshow(imagen[i])
  break
plt.show()

4. Creación del modelo

Lo primero que vamos a hacer es buscar en tensorflow hub la red mobilenet_2. En este caso nos facilitan las cosas y tenemos la red ya empaquetada pero sin la capa de salida. Es el modo “feature_vector”.

La descargamos

import tensorflow as tf
import tensorflow_hub as hub

url = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4"
mobilenetv2 = hub.KerasLayer(url, input_shape=(224,224,3))

Para no desaprovechar el entrenamiento que se ha realizado con esta red, congelamos todas las capas entrenadas.

mobilenetv2.trainable = False

Creamos nuestro modelo con la red que nos hemos descargado añadiendo una capa densa de salida, de 5 neuronas, con activación softmax que es la que se suele utilizar en los casos de clasificación.

modelo = tf.keras.Sequential([
    mobilenetv2,
    tf.keras.layers.Dense(5, activation='softmax')
])

Vemos el resumen del modelo que hemos creado.

modelo.summary()
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 keras_layer (KerasLayer)    (None, 1280)              2257984   
                                                                 
 dense (Dense)               (None, 5)                 6405      
                                                                 
=================================================================
Total params: 2,264,389
Trainable params: 6,405
Non-trainable params: 2,257,984
_________________________________________________________________

Compilamos nuestro modelo. Utilizamos el optimizador adam, para la función de pérdida seleccionamos categorical_crossentropy y por último como métrica accuracy.

modelo.compile(
    optimizer='adam',
    loss='categorical_crossentropy',
    metrics=['accuracy']
)

Antes de entrenar nuestro modelo definimos un par de callbacks para intentar afinar nuestro modelo.

Incluimos EarlyStopping para que al pasar más de 8 epochs sin que la función de pérdida disminuya, el entrenamiento se detenga. También incluimos ReduceLROPlateau para que modifique la tasa de aprendizaje pero en este caso en 4 epochs.

from keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint, Callback 
early_stop = EarlyStopping(monitor='val_loss', patience=8, verbose=1, min_delta=1e-4)  
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=4, verbose=1, min_delta=1e-4)  
callbacks_list = [early_stop, reduce_lr] 

Entrenamos nuestro modelo durante 50 épocas.

#Entrenar el modelo
EPOCAS = 50

historial =  modelo.fit(
    data_gen_train, 
    epochs= EPOCAS, 
    batch_size= 32,
    validation_data= data_gen_val,
    callbacks= callbacks_list
)
Epoch 1/50
25/25 [==============================] - 29s 553ms/step - loss: 1.6465 - accuracy: 0.3064 - val_loss: 1.2034 - val_accuracy: 0.4800 - lr: 0.0010
Epoch 2/50
25/25 [==============================] - 13s 517ms/step - loss: 1.2504 - accuracy: 0.4962 - val_loss: 0.9545 - val_accuracy: 0.6400 - lr: 0.0010
Epoch 3/50
25/25 [==============================] - 13s 518ms/step - loss: 1.0655 - accuracy: 0.5564 - val_loss: 0.8287 - val_accuracy: 0.6900 - lr: 0.0010
Epoch 4/50
25/25 [==============================] - 16s 654ms/step - loss: 0.9625 - accuracy: 0.6333 - val_loss: 0.7622 - val_accuracy: 0.7300 - lr: 0.0010
Epoch 5/50
25/25 [==============================] - 13s 521ms/step - loss: 0.8724 - accuracy: 0.6641 - val_loss: 0.7374 - val_accuracy: 0.7200 - lr: 0.0010
Epoch 6/50
25/25 [==============================] - 13s 517ms/step - loss: 0.8747 - accuracy: 0.6474 - val_loss: 0.6525 - val_accuracy: 0.7600 - lr: 0.0010
Epoch 7/50
25/25 [==============================] - 13s 515ms/step - loss: 0.8304 - accuracy: 0.6603 - val_loss: 0.6433 - val_accuracy: 0.7600 - lr: 0.0010
Epoch 8/50
25/25 [==============================] - 13s 525ms/step - loss: 0.7791 - accuracy: 0.7192 - val_loss: 0.6277 - val_accuracy: 0.7800 - lr: 0.0010
Epoch 9/50
25/25 [==============================] - 13s 529ms/step - loss: 0.7142 - accuracy: 0.7500 - val_loss: 0.6079 - val_accuracy: 0.7850 - lr: 0.0010
Epoch 10/50
25/25 [==============================] - 13s 518ms/step - loss: 0.6840 - accuracy: 0.7321 - val_loss: 0.6077 - val_accuracy: 0.7550 - lr: 0.0010
Epoch 11/50
25/25 [==============================] - 13s 513ms/step - loss: 0.7069 - accuracy: 0.7282 - val_loss: 0.5746 - val_accuracy: 0.7950 - lr: 0.0010
Epoch 12/50
25/25 [==============================] - 13s 523ms/step - loss: 0.6649 - accuracy: 0.7500 - val_loss: 0.5767 - val_accuracy: 0.8000 - lr: 0.0010
Epoch 13/50
25/25 [==============================] - 13s 521ms/step - loss: 0.6841 - accuracy: 0.7474 - val_loss: 0.5574 - val_accuracy: 0.7850 - lr: 0.0010
Epoch 14/50
25/25 [==============================] - 13s 519ms/step - loss: 0.6286 - accuracy: 0.7705 - val_loss: 0.5336 - val_accuracy: 0.8000 - lr: 0.0010
Epoch 15/50
25/25 [==============================] - 13s 519ms/step - loss: 0.6390 - accuracy: 0.7628 - val_loss: 0.5323 - val_accuracy: 0.8100 - lr: 0.0010
Epoch 16/50
25/25 [==============================] - 13s 517ms/step - loss: 0.6009 - accuracy: 0.7833 - val_loss: 0.5202 - val_accuracy: 0.8050 - lr: 0.0010
Epoch 17/50
25/25 [==============================] - 13s 520ms/step - loss: 0.6138 - accuracy: 0.7718 - val_loss: 0.5191 - val_accuracy: 0.8000 - lr: 0.0010
Epoch 18/50
25/25 [==============================] - 13s 521ms/step - loss: 0.6067 - accuracy: 0.7833 - val_loss: 0.5235 - val_accuracy: 0.8250 - lr: 0.0010
Epoch 19/50
25/25 [==============================] - 13s 520ms/step - loss: 0.5915 - accuracy: 0.7821 - val_loss: 0.5250 - val_accuracy: 0.8250 - lr: 0.0010
Epoch 20/50
25/25 [==============================] - 13s 518ms/step - loss: 0.5729 - accuracy: 0.7987 - val_loss: 0.5177 - val_accuracy: 0.8000 - lr: 0.0010
Epoch 21/50
25/25 [==============================] - 13s 517ms/step - loss: 0.5508 - accuracy: 0.7962 - val_loss: 0.5142 - val_accuracy: 0.8000 - lr: 0.0010
Epoch 22/50
25/25 [==============================] - 13s 527ms/step - loss: 0.5802 - accuracy: 0.7885 - val_loss: 0.5322 - val_accuracy: 0.8000 - lr: 0.0010
Epoch 23/50
25/25 [==============================] - 13s 513ms/step - loss: 0.5815 - accuracy: 0.7974 - val_loss: 0.5090 - val_accuracy: 0.8050 - lr: 0.0010
Epoch 24/50
25/25 [==============================] - 15s 614ms/step - loss: 0.5397 - accuracy: 0.8064 - val_loss: 0.5141 - val_accuracy: 0.8200 - lr: 0.0010
Epoch 25/50
25/25 [==============================] - 13s 531ms/step - loss: 0.5252 - accuracy: 0.8103 - val_loss: 0.5360 - val_accuracy: 0.8150 - lr: 0.0010
Epoch 26/50
25/25 [==============================] - 13s 524ms/step - loss: 0.5526 - accuracy: 0.7910 - val_loss: 0.4965 - val_accuracy: 0.8250 - lr: 0.0010
Epoch 27/50
25/25 [==============================] - 13s 517ms/step - loss: 0.5777 - accuracy: 0.7756 - val_loss: 0.4837 - val_accuracy: 0.8150 - lr: 0.0010
Epoch 28/50
25/25 [==============================] - 13s 521ms/step - loss: 0.5323 - accuracy: 0.8000 - val_loss: 0.5096 - val_accuracy: 0.8150 - lr: 0.0010
Epoch 29/50
25/25 [==============================] - 13s 516ms/step - loss: 0.5434 - accuracy: 0.7923 - val_loss: 0.5274 - val_accuracy: 0.8100 - lr: 0.0010
Epoch 30/50
25/25 [==============================] - 13s 512ms/step - loss: 0.5127 - accuracy: 0.8141 - val_loss: 0.5095 - val_accuracy: 0.8250 - lr: 0.0010
Epoch 31/50
25/25 [==============================] - ETA: 0s - loss: 0.4902 - accuracy: 0.8269
Epoch 31: ReduceLROnPlateau reducing learning rate to 0.00010000000474974513.
25/25 [==============================] - 13s 517ms/step - loss: 0.4902 - accuracy: 0.8269 - val_loss: 0.5002 - val_accuracy: 0.8400 - lr: 0.0010
Epoch 32/50
25/25 [==============================] - 13s 516ms/step - loss: 0.4964 - accuracy: 0.8167 - val_loss: 0.4903 - val_accuracy: 0.8500 - lr: 1.0000e-04
Epoch 33/50
25/25 [==============================] - 13s 508ms/step - loss: 0.4725 - accuracy: 0.8333 - val_loss: 0.4877 - val_accuracy: 0.8250 - lr: 1.0000e-04
Epoch 34/50
25/25 [==============================] - 13s 507ms/step - loss: 0.4926 - accuracy: 0.8385 - val_loss: 0.4862 - val_accuracy: 0.8400 - lr: 1.0000e-04
Epoch 35/50
25/25 [==============================] - ETA: 0s - loss: 0.4591 - accuracy: 0.8269
Epoch 35: ReduceLROnPlateau reducing learning rate to 1.0000000474974514e-05.
25/25 [==============================] - 13s 515ms/step - loss: 0.4591 - accuracy: 0.8269 - val_loss: 0.4869 - val_accuracy: 0.8300 - lr: 1.0000e-04
Epoch 35: early stopping

Parece que tras 35 épocas la función de pérdida no disminuye, por lo que el entramiento se detiene.

Vamos a ver gráficamente como se han comportado la función de pérdida y el accuracy con datos de entrenamiento y validación.

#Graficas de precisión
acc = historial.history['accuracy']
val_acc = historial.history['val_accuracy']

loss = historial.history['loss']
val_loss = historial.history['val_loss']

rango_epocas = range(35)

plt.figure(figsize=(8,8))
plt.subplot(1,2,1)
plt.ylim(0, 1)
plt.plot(rango_epocas, acc, label='Precisión Entrenamiento')
plt.plot(rango_epocas, val_acc, label='Precisión Pruebas')
plt.legend(loc='lower right')
plt.title('Precisión de entrenamiento y pruebas')

plt.subplot(1,2,2)
plt.ylim(0, 1)
plt.plot(rango_epocas, loss, label='Pérdida de entrenamiento')
plt.plot(rango_epocas, val_loss, label='Pérdida de pruebas')
plt.legend(loc='upper right')
plt.title('Pérdida de entrenamiento y pruebas')
plt.show()

Podemos ver que el modelo se comporta correctamente, llegando a una accuracy de 0.85 con los datos de validación. El modelo nos puede servir.

5. Predicciones

Lo primero que vamos a ver es la etiqueta que se ha asignado a cada una de las razas.

data_gen_train.class_indices
{'Elfos': 0, 'Enanos': 1, 'Hobbits': 2, 'Magos': 3, 'Orcos': 4}
from PIL import Image
import cv2

dicc= data_gen_train.class_indices

for raza in list(dicc.keys()):
  test  = '/content/dataset/test/' + raza + '/'
  lista = os.listdir('/content/dataset/test/'+ raza + '/')

  for img in lista:
    plt.imshow(mpimg.imread(test + img))
    
    img = Image.open(test + str(img))
    img = np.array(img).astype(float)/255
    img = cv2.resize(img, (224,224))

    prediccion = modelo.predict(img.reshape(-1, 224, 224, 3))
    print("La imagen es de " + raza + " y el modelo predice: ", list(dicc.keys())[list(dicc.values()).index(np.argmax(prediccion[0], axis=-1))])
    
    plt.show()
1/1 [==============================] - 1s 720ms/step
La imagen es de Elfos y el modelo predice:  Magos
1/1 [==============================] - 0s 19ms/step
La imagen es de Elfos y el modelo predice:  Hobbits
1/1 [==============================] - 0s 19ms/step
La imagen es de Elfos y el modelo predice:  Elfos
1/1 [==============================] - 0s 20ms/step
La imagen es de Elfos y el modelo predice:  Elfos

1/1 [==============================] - 0s 19ms/step
La imagen es de Enanos y el modelo predice:  Enanos
1/1 [==============================] - 0s 20ms/step
La imagen es de Enanos y el modelo predice:  Enanos
1/1 [==============================] - 0s 20ms/step
La imagen es de Enanos y el modelo predice:  Elfos
1/1 [==============================] - 0s 19ms/step
La imagen es de Enanos y el modelo predice:  Enanos
1/1 [==============================] - 0s 19ms/step
La imagen es de Hobbits y el modelo predice:  Hobbits
1/1 [==============================] - 0s 20ms/step
La imagen es de Hobbits y el modelo predice:  Hobbits
1/1 [==============================] - 0s 20ms/step
La imagen es de Hobbits y el modelo predice:  Hobbits
1/1 [==============================] - 0s 21ms/step
La imagen es de Hobbits y el modelo predice:  Hobbits
1/1 [==============================] - 0s 25ms/step
La imagen es de Magos y el modelo predice:  Enanos
1/1 [==============================] - 0s 23ms/step
La imagen es de Magos y el modelo predice:  Magos
1/1 [==============================] - 0s 22ms/step
La imagen es de Magos y el modelo predice:  Magos
1/1 [==============================] - 0s 22ms/step
La imagen es de Magos y el modelo predice:  Magos
1/1 [==============================] - 0s 21ms/step
La imagen es de Orcos y el modelo predice:  Orcos
1/1 [==============================] - 0s 22ms/step
La imagen es de Orcos y el modelo predice:  Orcos
1/1 [==============================] - 0s 21ms/step
La imagen es de Orcos y el modelo predice:  Orcos
1/1 [==============================] - 0s 24ms/step
La imagen es de Orcos y el modelo predice:  Orcos

Vemos que las predicciones son bastante acertadas.

Ahora vamos a jugar un poco más con nuestro modelo, y vamos a realizar predicciones con imágenes completamente distintas del dataset original.

Así en cada raza tenemos:

Descargamos las imágenes de drive.

from google.colab import drive
drive.mount('/content/drive')
!unzip /content/drive/MyDrive/ClasificadorImagenes/Predict.zip
Archive:  /content/drive/MyDrive/ClasificadorImagenes/Predict.zip
  inflating: Predict/Elfo.jpg        
  inflating: Predict/Enano.jpg       
  inflating: Predict/hobbit.jpg      
  inflating: Predict/mago.jpg        
  inflating: Predict/orco.jpg        

Realizamos las predicciones, a ver si nuestro modelo es capaz de identificarlas.

test  = '/content/Predict/'
lista = os.listdir('/content/Predict/')

for img in lista:
  plt.imshow(mpimg.imread(test + img))
  
  img = Image.open(test + str(img))
  img = np.array(img).astype(float)/255
  img = cv2.resize(img, (224,224))

  prediccion = modelo.predict(img.reshape(-1, 224, 224, 3))
  print("El modelo predice:", list(dicc.keys())[list(dicc.values()).index(np.argmax(prediccion[0], axis=-1))])
  
  plt.show()
1/1 [==============================] - 0s 21ms/step
El modelo predice: Orcos
1/1 [==============================] - 0s 19ms/step
El modelo predice: Enanos
1/1 [==============================] - 0s 28ms/step
El modelo predice: Hobbits
1/1 [==============================] - 0s 21ms/step
El modelo predice: Hobbits
1/1 [==============================] - 0s 19ms/step
El modelo predice: Magos

Hemos tenido un buen resultado, solo ha fallado al identificar al Elfo, quizás un duende de navidad se asemeja más a un hobbit.

Por último, vamos a ver en qué raza me ubica el modelo.

plt.imshow(mpimg.imread('/content/drive/MyDrive/foto_hector.jfif'))

img = Image.open('/content/drive/MyDrive/foto_hector.jfif')
img = np.array(img).astype(float)/255
img = cv2.resize(img, (224,224))

prediccion = modelo.predict(img.reshape(-1, 224, 224, 3))
print("El modelo predice:", list(dicc.keys())[list(dicc.values()).index(np.argmax(prediccion[0], axis=-1))])

plt.show()
1/1 [==============================] - 0s 43ms/step
El modelo predice: Hobbits

6. Guardar el modelo

Creamos la carpeta para poder exportarla a donde queramos.

!mkdir -p carpeta_salida/modelo_razas

Guardamos el modelo.

modelo.save('carpeta_salida/modelo_razas')

Hacemos un zip de la carpeta para poder transportarlo.

!zip -r modelo_razas.zip /content/carpeta_salida/modelo_razas/
  adding: content/carpeta_salida/modelo_razas/ (stored 0%)
  adding: content/carpeta_salida/modelo_razas/saved_model.pb (deflated 92%)
  adding: content/carpeta_salida/modelo_razas/variables/ (stored 0%)
  adding: content/carpeta_salida/modelo_razas/variables/variables.data-00000-of-00001 (deflated 8%)
  adding: content/carpeta_salida/modelo_razas/variables/variables.index (deflated 78%)
  adding: content/carpeta_salida/modelo_razas/keras_metadata.pb (deflated 81%)
  adding: content/carpeta_salida/modelo_razas/assets/ (stored 0%)

Este sería el final del proyecto, espero haya explicado bien las distintas técnicas empleadas.

¡Si te ha gustado el contenido de este artículo no te olvides de suscribirte a la newsletter!

El metaverso es disruptivo, por lo que hemos decidido tratarlo de la misma manera. 𝐄𝐬𝐭𝐞 𝐧𝐨 𝐞𝐬 𝐨𝐭𝐫𝐨 𝐞𝐯𝐞𝐧𝐭𝐨 𝐦𝐚́𝐬 𝐬𝐨𝐛𝐫𝐞 𝐦𝐞𝐭𝐚𝐯𝐞𝐫𝐬𝐨.

🎞️ En la película "Sex, Lies, and Videotape" (1989), el director nos muestra las grandes mentiras existentes en torno al sexo en los 80-90 y cómo todo el mundo tiene un lado oculto que desea probar pero no se atreve. En ese punto se encuentra el metaverso, rodeado de deseos aún inalcanzables y de mentiras de todo tipo. Por ello, pensamos en aportar algo de luz sobre el tema con "𝐌𝐄𝐓𝐀𝐕𝐄𝐑𝐒𝐎, 𝐌𝐄𝐍𝐓𝐈𝐑𝐀𝐒 𝐘 𝐂𝐈𝐍𝐓𝐀𝐒 𝐃𝐄 𝐕𝐈́𝐃𝐄𝐎".

📰 En unos años donde reina el 𝐜𝐥𝐢𝐜𝐤𝐛𝐚𝐢𝐭 𝐲 𝐥𝐚𝐬 𝐟𝐚𝐤𝐞 𝐧𝐞𝐰𝐬, hacer un filtro de información veraz es realmente complicado. En el caso del metaverso, ocurre lo mismo: gurús, promesas vacías y esperanzas desmesuradas. ¿Qué parte de todo lo que hemos leído estos últimos meses 𝐞𝐬 𝐫𝐞𝐚𝐥𝐢𝐳𝐚𝐛𝐥𝐞? ¿En qué punto está el metaverso? ¿Cuáles serán los 𝐞𝐦𝐩𝐥𝐞𝐨𝐬 más demandados a partir de ahora? ¿Y en la 𝐚𝐜𝐭𝐮𝐚𝐥𝐢𝐝𝐚𝐝?

Todas estas preguntas y muchas más serán resueltas por 𝐗𝐚𝐯𝐢 𝐃𝐞𝐥𝐠𝐚𝐝𝐨 (Impulsor de Metaverso y CEO de Köhler Servicios Educativos), El 𝐈𝐬𝐦𝐚 (Metaverse Early Adopter y especialista en transformación digital) y por 𝐋𝐨𝐮𝐫𝐝𝐞𝐬 𝐇𝐞𝐫𝐧𝐚́𝐧𝐝𝐞𝐳 (CEO de datahack).

Podrás disfrutar de este evento desde 𝐋𝐢𝐧𝐤𝐞𝐝𝐈𝐧 𝐋𝐢𝐯𝐞, por lo que tienes la posibilidad de comentar desde tu cuenta personal e interactuar con cualquiera de los ponentes en todo momento.

🔴 El evento seguirá este desorden, a lo Frank Muller Crazy Hours:

1) ⏳ Esperando a los impuntuales ⏳
2) Cortina de humo del metaverso
3) Mentiras Arriesgadas del Metaverso
4) Aplicaciones para los Lobos de Wall Street
5) Baloncesto en Metaverso: Falta personal
6) Doc y Marty Mcfly: regreso a web5
7) Cierre

✅ Esta sesión será online en directo.

✅ Durante el taller podrás preguntar todas las dudas que tengas al ponente y las irá respondiendo. ¡No te quedes con ninguna duda!

✅ Al registrarte recibirás una notificación el día del evento con la que podrás conectarte a la sesión.

Regístrate rápidamente en este evento 👉 https://www.linkedin.com/video/event/urn:li:ugcPost:6985272032984764416/




El sector del Big Data, además de encontrarse en pleno auge y desarrollo, forma parte de la realidad empresarial de numerosas empresas a nivel mundial. ¿Quieres conocer más sobre este sector desde el punto de vista de la empleabilidad, perfiles y condiciones laborales?


Si estás interesado en el mundo del Big Data o simplemente deseas información sobre los perfiles profesionales y sus rangos salariales apúntate de forma completamente gratuita a nuestro próximo webinar online que tendrá lugar el día 21 de julio a las 18:30h (duración 1h aprox.) a través de la plataforma LinkedIn Live.

¿Quieres saber cuál es el perfil Big Data que demandan las empresas? ¿Deseas descubrir los rangos salariales de dichos profesionales del sector? En esta sesión encontrarás las respuestas a todas tus preguntas de la mano de grandes profesionales del Big Data y de forma amena e interesante.

El evento se dividirá en tres bloques:

No dejes escapar esta oportunidad e infórmate junto a verdaderos profesionales del Big Data.

¡Anímate y adéntrate en uno de los sectores con mayor demanda del mercado!

Regístrate aquí gratis para asistir online:

https://www.linkedin.com/video/event/urn:li:ugcPost:6953310160811376640

🔵 Esta sesión será online en directo y desde la plataforma de LinkedIn Live.

🔵 Este formulario es para apuntarte a la sesión online.

🔵 Durante la sesión podrás preguntar todas las dudas que tengas al ponente y las irá respondiendo. No te quedes con ninguna duda.

🔵 Al registrarte recibirás un enlace en tu email con el que podrás conectarte a la sesión online.

Por Marta Regina Cano Jiménez

La nuestra es la era de los datos. Cada día se generan inmensas cantidades de datos y tanto la infrastructura para almacenarlos, como las herramientas y técnicas para tratar y analizar este volumen tan ingente de información, evoluciona a pasos agigantados.

Pero los datos no van solos y se ha demostrado que los proyectos más exitosos son aquellos que entienden las necesidades de las personas y se adaptan de forma personalizada. El futuro, por tanto, es impulsado por las personas y guiado por los datos.

Así pues, ¿Podremos avanzar a la misma velocidad que la tecnología? ¿O en algún momento seremos o estamos siendo un freno?

Según un artículo de MIT Sloan, los factores culturales, aquellos que tienen que ver con el cambio de pensamiento y manera de hacer de las personas, son los principales obstáculos para transformar este oro que son los datos, en valor de negocio y ventaja competitiva. No la tecnología o la arquitectura, las personas.

También podemos encontrar numerosos artículos sobre la importancia de generar e impulsar la Cultura del Dato en las personas de la organización, como este de Deloitte.

Cualquier proyecto de Big Data y Analytics ha de partir de las personas y las necesidades de los que serán sus usuarios, desde el momento del diseño. Es necesario entender sus miedos, estereotipos, sesgos, creencias y alinear con sus prioridades de negocio.

Tomar como punto de partida estas necesidades de negocio y orientarnos a resolverlas y no al revés (el a veces típico ‘tengos estos datos y herramientas, ¿qué puedo hacer con ellos?’), es imprescindible para un resultado exitoso. Y aunque suene básico, es el aspecto que muchas veces se deja en segundo término, deslumbrados por las técnicas o tecnologías de moda. 

Cambiar las metodologías de trabajo o aprender a usar nuevas herramientas no es como apretar un botón, requiere su tiempo, incluso si se trata de herramientas Low Code o No Code. 

Es muy importante por tanto planificar con tiempo, definir cuál es nuestro objetivo como empresa, realizar un diagnóstico del punto de partida 360º evaluando el punto de partida de las habilidades técnicas de las personas que conforman la empresa, uso de herramientas, así como disponibilidad, catalogación y calidad de los datos, automatización de procesos y gestión del cambio.  

A partir de ahí, diseñar un plan de formación personalizado que acompañe la formación técnica con la democratización de los datos disponibles, para la resolución de casos de uso reales y una integración de las nuevas técnicas en el día a día. Empezar por casos de uso pequeños pero con el impacto más relevante, e ir escalando a mayores proyectos.

Sólo partiendo de la definición del reto de negocio de resolver, alineando los esfuerzos a la cobertura de las necesidades, aportando valor desde el primer minuto y orientados a las personas, conseguiremos implantar con éxito los proyectos de Big Data, Analytics o Business Intelligence y convertirnos realmente en empresas Data Driven de forma transversal.

Marta Regina Cano Jiménez

Directora de Inteligencia de Negocio 

Caja de Ingenieros

www.linkedin.com/in/martareginacano

@regiemix

Si quieres más información sobre nuestro master, puedes contactar con nosotros bien por teléfono al +34 910 91 28 42 o +34 630 88 13 53, por whatsapp directamente pinchando aquí o aquí, o mandando un mail con tus datos de contacto (nombre completo y teléfono) a: info@datahack.es

Por Julián García Trueba.

En un tiempo en el que la escasez de recursos ocupa una de las principales preocupaciones de nuestra sociedad, existe un recurso cuya generación crece de forma exponencial con el paso de los años. Este recurso no es otro que los Datos. Los datos generados pueden ser de diversa tipología y procedencia, cada una de las cuales con una serie de aplicaciones de elevado valor para las empresas y administraciones. En concreto, en el presente artículo vamos a focalizarnos en la aportación de los datos geolocalizados de movilidad al contexto de la sociedad actual.

En primer lugar, cabe enfatizar que, si bien la recolección, representación y, en definitiva, el análisis de los datos geolocalizados puede resultar un tema de última tendencia, sus primeras aplicaciones se remontan a mucho antes de que se dieran los primeros hitos de la Inteligencia Artificial o de que se empezase a hablar del Big Data. Prueba de ello es, por ejemplo, es el empleo que el célebre médico inglés Jon Snow hizo de la visualización geolocalizada para salvar a la ciudad de Londres de una de los mayores brotes de cólera de su historia. En concreto, el análisis realizado por Jon Snow consistió en identificar sobre un mapa los hogares de los ciudadanos afectados por cólera, así como la fuente principal de agua que surtía dichos hogares. De tal forma, una vez recogidos los datos y representados en el mapa, le permitió determinar de forma objetiva cuáles eran las fuentes “infectadas”. Con dichos datos, no le resulto difícil la tarea a Jon Snow de convencer a las autoridades de la necesidad de clausurar dichas fuentes y, de esta forma, dar por concluida la epidemia de cólera que solaba la ciudad.

Cómo John Snow salvó la vida de miles de personas
Representación gráfica del mapa en el que se basó Jon Snow para identificar las fuentes afectadas

No obstante, si bien como hemos visto el empleo de la geolocalización no es algo que atañe únicamente a nuestros tiempos, en la actualidad, la convergencia de tecnologías tanto de comunicación como de información ha incentivado la aparición de innumerables aplicaciones multisectoriales. Un ejemplo de ello es las llamadas plataformas de Smart Cities, las cuales proveen de la infraestructura necesaria para garantizar la recopilación de datos resultantes de diversos puntos de la ciudad, la representación de los mismos y el posterior análisis para una gestión eficiente de los servicios focalizados en el ciudadano. 

Plataforma urbana de Coruña smart city seleccionada como referente en  Global City Teams Challenge - eleconomistaamerica.cl

No obstante, las plataformas Smart Cities no son los únicos casos de aplicación basados en la geolocalización. En este sentido, englobando también el concepto de movilidad dentro del análisis de datos geolocalizados cobran especial relevancia los datos generados por las operadoras, procedentes del dispositivo más popular y más empleado en nuestros días, el terminal móvil. Hoy en día, resulta realista afirmar que es extraño quien no dispone de un dispositivo móvil con acceso a internet y aplicaciones instaladas en el mismo. Este hecho es el aprovechado por las operadoras para tener acceso a ciertos datos de sus usuarios. En concreto, algunos de estos datos son los siguientes: la geolocalización del usuario, resultante de la antena a través de la cual puede accede a la conectividad del terminal, las aplicaciones a las que tiene acceso, las condiciones de contratación del usuario, así como datos personales del mismo (edad, sexo, etc). 

De tal forma, mediante el correcto procesamiento de los datos, resulta viable determinar tendencias de movilidad de los usuarios. Para ello, y con el objetivo de cumplir con la normativa vigente de Protección de Datos, como paso previo a su presentación y análisis, las operadoras se ven obligadas a llevar a ejecutar diversos y complejos algoritmos para la agrupación de los mismos según diversos criterios: procedencia, franja horaria, segmentación por edad, por poder adquisitivo o por sexo. 

Una vez ejecutados los procesos de agrupación y el procesamiento de datos por parte de los departamentos de Ingeniería de Datos de las operadoras habilitarán a una serie de insights con importantes aplicaciones en diversidad de sectores, como el turístico, el del retail, o el de la gestión de eventos. En concreto, en lo que respecta al sector turístico, el análisis de estos datos permite conocer la tendencia de movilidad en las principales zonas de atracción turística de las ciudades en función de la edad, las franjas horarias, el sexo, o el país o ciudad de procedencia, distinguiendo entre turistas que pernoctan en la ciudad y aquellos que la visitan en el día. Por otro lado, en lo que respecta al sector del retail, el análisis de los datos de operador, permite a las tiendas y sucursales conocer las tendencias de movilidad por franjas horarias y perfil tanto de los actuales clientes como de los potenciales. Un análisis que permitirá objetivizar la toma de decisiones en lo que respecta, por ejemplo, a la estrategia de expansión de las tiendas. Por último, en lo que respecta a la gestión de eventos, los datos de operador permiten tomar decisiones para una gestión más sostenible de los eventos, incrementando así la experiencia del cliente final. 

Vodafone Analytics Demo - Explore a City - YouTube

En definitiva, de forma adicional al servicio de conectividad y voz que las operadoras proveen a sus clientes, tanto personas físicas, como jurídicas y administraciones, en la actualidad estas compañías proveen de una serie de insights basados en los datos, anonimizados y agrupados, procedentes de los dispositivos móviles de los clientes, los cuales permiten extraer conclusiones objetivas sobre las tendencias de movilidad, un paso más allá en lo que respecta al análisis de datos geolocalizados.

Si quieres más información sobre nuestro master, puedes contactar con nosotros bien por teléfono al +34 910 91 28 42 o +34 630 88 13 53, por whatsapp directamente pinchando aquí o aquí, o mandando un mail con tus datos de contacto (nombre completo y teléfono) a: info@datahack.es

Por Alejandro Arranz

INTRODUCCIÓN

Existe un fenómeno común a los deportes de equipo (por lo menos a los más populares) y es que, para aquellos que les interese alguno de estos deportes, cuando van a consultar la prensa que los cubre, seguramente se encuentre que sus crónicas las copan aquellos que marcan los goles, las canastas, los tantos...etcétera. Igualmente, si este tipo de deportes no te interesa lo más mínimo, pero tuvieras que dar el nombre de algún deportista de élite que los practique...seguramente este se corresponda con el alguno de los omnipresentes en las susodichas crónicas. En pocas palabras, los que “molan” suelen ser invariablemente los máximos anotadores.

En los proyectos relacionados con Inteligencia Artificial, sean de Machine Learning o de Deep Learning (por mencionar las dos disciplinas más populares de esa rama), pasa un poco lo mismo. Si echamos manos de “la prensa” enseguida veremos que los titulares apuntan en la misma dirección: “El modelo que quitará el trabajo a los radiólogos”, “El modelo que ha derrotado al campeón mundial de Go”, “Los treinta modelos embebidos que hacen que los Tesla sean completamente autónomos…”. El modelo es al que apuntan los focos.

Claro...como cuando preguntan a los críos que empiezan a practicar deporte aquello de “y tú ¿cómo quien quieres ser?”, no es habitual que respondan “pues como tal jugador, porque me encanta la infatigable labor que hace en el medio del campo para robar la pelota y sacarla jugada de forma fácil y limpia para el compañero más próximo”. Igualmente cuando alguien que arranca su periplo como Data Scientist, seguramente si le preguntas a qué aspira...no te responderá “a conseguir dar forma a los datos de la forma más adecuada posible de tal manera que el modelo diseñado pueda sacar el máximo provecho de los mismos”.

Queremos meter goles. Queremos hacer modelos.

Si te apetece, otro día, podemos hacer una entrada en el blog sobre la importancia de este tipo de roles de trabajo menos vistoso en el mundo de los deportes de equipo. Por de pronto, vamos a ceñirnos al ámbito de las máquinas y desgranar la importancia de la(s) tarea(s) comprendidas dentro de la limpieza de datos y porque es algo que también mola.

MACHINE LEARNING Y LIMPIEZA DE DATOS

Aunque a estas alturas ya lo tengas seguramente más que claro, no está de mas recordar que el Machine Learning es una disciplina que tiene como objetivo que las máquinas aprendan a partir de la experiencia; es decir: que un modelo matemático sea capaz de extraer los patrones propios de un determinado problema a partir de de un (gran) conjunto de datos relativos a este. Aquel modelo matemático utilizará una o varias máquinas para disponer de la potencia de cálculo necesaria, que le permita exprimir todos esos datos y extraer así ese patrón o aprendizaje relativos a la resolución de ese problema.

Vamos a aterrizar esto con un ejemplo: supongamos que tenemos un conjunto de analíticas de pacientes enfermos y sanos con respecto a una determinada patología. Si queremos construir un modelo que sea capaz de, dada la analítica de un nuevo paciente, determinar si este padece o no aquella patología. Entrenaremos el modelo matemático con los datos que tenemos y este (a su manera) aprenderá qué patrones se dan en las analíticas de aquellos pacientes enfermos, de tal manera que pueda extrapolarlo a nuevos casos.

¿QUIÉN HA ENSUCIADO MIS DATOS?

Quizá el nombre limpieza de datos, resulte un poco engañoso. Valga decir que esta disciplina comprende todo lo necesario para que, según la definición de Machine Learning que acabas de leer, los datos disponibles para resolver el problema sean dispuestos de tal manera que puedan ser utilizados por un modelo matemático para su entrenamiento.

Hay que pensar que dicho modelo maneja únicamente números (existe alguna excepción a esto, pero en general es así). Es decir, nuestros datos, como mínimo, tienen que ser transformados a un formato numérico antes de poder ser utilizados para entrenar un modelo. Ojo a esa coletilla “como mínimo”, quiere decir que esto sería lo básico para que modelo llegue a comenzar su entrenamiento sin problemas. Pero si buscamos que este entrenamiento sea lo más exitoso posible, habrá que recurrir a otras técnicas.

Siempre decimos que, lamentablemente, no existe una receta que pueda ser aplicada a todos los problemas de Machine Learning. No obstante, existen una serie de pasos que prácticamente siempre podemos tomar como referencia a la hora de abordar la limpieza de datos.

MANOS A LA OBRA

Podemos decir que estos pasos que mencionamos a continuación, son innegociables, aunque, como ya hemos indicado, no tienen porque ser los únicos a seguir:

EXPLORACIÓN

Que no nos pueda el ansia por empezar a toquetear: si no nos hemos tomado la molestia siquiera de visualizar como se distribuyen nuestros datos, no tiene sentido empezar a manosearlos. Primero, lo primero: histogramas, boxplots, gráficos de dispersión...todo aquello que ayude a entender cómo se distribuyen las variables o features de las que disponemos. Muy seguramente, de aquí saquemos una intuición de cuales pueden ser problemáticas.

LIMPIEZA

Normalmente en este proceso nos encargamos de los problemas “de bulto”, es decir, aquellos que cantan bastante. Aquí incluimos los archiconocidos valores missing, null, NA, NaN...ya sabes, cualquiera de las distintas formas en las que el Mal puede materializarse en nuestros datos y que se manifiesta mediante la ausencia de dato, donde deberiá de haberlo.

Muy probablemente, el modelo matemático con el que hayas elegido empezar a probar, no sepa que hacer con uno de estos valores ausentes y cascará de forma inmisericorde cuando quieras empezar el proceso de entrenamiento. Así que hay que decidir como rellenarlos...o prescindir de ellos.

Hay más anomalías que podemos tratar en este punto, por ejemplo muestras o registros duplicados. Estas duplicidades pueden ser de distintos tipos, quizá podamos encontrar registros totalmente idénticos o quizá solamente idénticos según algunos campos. En este último caso, habría que considerar si esas duplicidades son normales o no.

En cuanto al entrenamiento se refiere, los registros duplicados no aportan nada, con lo cual se pueden eliminar sin mucho problema. Pero cabe preguntarse sobre su origen, ¿es posible que la presencia de duplicados sea indicativo de algún tipo de problema, quizá, en alguna proceso de extracción de datos?

Tenemos que ser conscientes de que las “cosas raras” que encontremos en nuestros datos, podrían no solo afectar a nuestro entrenamiento, sino ser síntomas de algún tipo de defecto o problema en el flujo de captura y tratamiento de los mismos. Y esto sería algo gordo.

TRANSFORMACIÓN

Salvo honrosas excepciones (mayormente aquellos modelos basados en árboles de decisión), los modelos matemáticos solo manejan números. Es decir que aquellas features categóricas, cuyos valores son de tipo texto (por ejemplo) que podemos encontrar en cualquier dataset, deben ser transformadas de alguna manera en algo numérico para que el modelo matemático pueda entrenar con ellas. El cómo hacer esto, ya depende de del tipo de feature categórica y de su significado.

ENRIQUECIMIENTO

Este es un buen percal. Aquí, podemos decir que practicamente vale todo, desde encontrar un dataset que pueda complementar al que estamos manejando: imagina un dataset con personas y otro dataset de renta per cápita en municipios de España que, cruzándolo con el primero, te permite tener una idea de la renta del individuo en cuestión. En este caso, habríamos enriquecido nuestro dataset de personas, con ese otro dataset de renta per cápita por municipios.

Pero no te preocupes si no tienes ningún otro dataset a mano, hay más maneras de enriquecer el dataset. Por ejemplo a través de features sintéticas, es decir, obtener nuevas features combinando de forma hábil las ya existentes. Esto permite proporcionar a nuestro modelo matemático features más potentes y representativas e, implicitamente, dejar de pasarle otras features más superfluas y menos necesarias.

Incluso el hecho de conseguir identificar simplemente este segundo punto y poder prescindir de esas features innecesarias para entrenar al modelo, sería un éxito. Hay que tener en cuenta, que un dataset más ligero, permitirá entrenamientos más rápidos y por lo tanto nos habilitará para probar más cosas distintas en menos tiempo.

Muy importante: es fácil embuclarse y perderser en cualquiera de estos pasos, pero muy especialmente en este. ¡No obsesionarse! Hay que ir iterando de forma más o menos ágil, probar, cosas, entrenar, avanzar, ir afinando...pero no dar vueltas y vueltas a lo mismo, porque sino, esto se convierte en una esponja de tiempo...y de dinero claro.

OTROS

Aquí podemos incluir lo que se conoce como  inverstigación de outliers o valores que se alejan de forma sospechosa del resto de “compañeros” de distribución. El problema de este tipo de valores es que pueden confundir al modelo a la hora de aprender, ya que suponen ruido para el mismo o lo que es lo mismo, suponen “excepciones a la regla” que queremos que el modelo aprenda. Dicho de otra manera: queremos que el modelo aprenda patrones, no excepciones. Y los outliers son excepciones.

Las acciones con respecto a outliers se orientan a su detección y análisis y en base a estos se determinará qué se hace con ellos (si se hace algo)

Llegados a este punto, es posible que por todo lo comentado hasta ahora, alguien haya colegido que si una feature es numérica y no tienen ningún hueco o valor missing, todo está bien. El caso es que esto no es así.

Es habitual que las features numéricas tengan magnitudes dispares, por ejemplo podemos tener la feature edad de la persona que rara vez pasará de las dos cifras y también la feature renta per capita que, esperemos, siempre llegue por lo menos a cinco. Esta disparidad de magnitudes, puede ocasionar que los modelos matemáticos tiendan a dar más peso a aquellas features cuya magnitud es mayor, opacando a aquellas otras de menor magnitud, por muy valiosas o representativas que puedan ser.

Para evitar esto, se recurren a distintas técnicas de escalado o de estandarización. Dependiendo del tipo de modelo matemático que queramos entrenar, el utilizar unas u otras puede ser crucial. En cualquier caso, la moraleja aquí es que, aun siendo numéricas, las features deben de ser “ajustadas”.

Tampoco queremos extendernos mucho más, como ves, estamos ante una disciplina sumamente interesante y que nos permitirá adquirir un conocimiento muy valioso de los datos que manejamos.

Si quieres más información sobre nuestro master, puedes contactar con nosotros bien por teléfono al +34 910 91 28 42 o +34 630 88 13 53, por whatsapp directamente pinchando aquí o aquí, o mandando un mail con tus datos de contacto (nombre completo y teléfono) a: info@admin_rubicon

Lee la parte 1 aquí.

En realidad, comparar el grado de similitud entre dos películas puede que no sea lo que más interese al usuario. Puede ser más valioso encontrar todas aquellas películas que son más parecidas a la que nos gusta. Para ello, seleccionaremos la columna de la película que nos gusta y la ordenaremos de mayor a menor. Así, Python nos mostrará en orden decreciente de similitud las películas.

Figura 13. Recomendar películas por grado de similitud con Python

3. Recomendaciones basadas en texto


Desafortunadamente, en el mundo real los problemas que tenemos que resolver no tienen etiquetas claras como los géneros para el caso particular de las películas. Por suerte, si hay texto relacionado con ese elemento entonces podemos hacer algo. Este texto puede ser un resumen, una descripción del elemento o la lista de contenidos de un libro. en estos casos usaremos "Term Frequency inverse Document Frequency" o TF-IDF para transformar el testo en información valiosa.


Estos algoritmos dividen el número de veces que una palabra aparece en un documento entre el ratio de documentos globales en que unes palabra aparece. De esta manera, se reduce la importancia de palabras comunes y se incrementa el peso de aquellas palabras que no aparecen en muchos documentos. Por ejemplo, si comparamos el texto de "Harry Potter y La Piedra Filosofal" con el resto de libros de la saga Harry Potter, la palabra Voldemort obtendrá una puntuación baja ya que aparece multitud de veces a lo largo de todos los libros. Por contra, la palabra elixir que está muy relacionada sólo al primer libro de la saga, obtendrá una puntuación alta.

Figura 14. Fórmula TF-IDF

Ahora vamos a trabajar con otro dataset de películas diferente. Este contiene los nombres de las películas y el resumen de las mismas que aparece en la página Wikipedia.

Figura 15. Cargamos el nuevo dataset con el resumen de las películas

La transformación de los datos se hace gracias a TfidfVectorizer de la biblioteca Scikit Learn. Porde efecto, esta herramienta genera una característica por cada palabra presente en un documento. Esto resulta en un gran número de características; por suerte, hay formas de reducir el número de características generador por el vectorizador.

Para ello incluiremos en primer lugar el argumento min_df y le daremos un valor de 2. De esta forma sólo se convertirán en características aquellas palabras que estén presentes en al menos dos documentos. Esto es muy útil ya que las palabras que sólo aparezcan en un documento no son muy importantes a la hora de encontrar similitudes.

Por otro lado, podemos incluir un segundo argumento max_df que elimine aquellas palabras que sean muy comunes. Si lo fijamos a 0.7, no se tendrán en cuenta aquellas palabras que aparecen en más de un 70% de los resúmenes.

Figura 16. inicializamos el vectorizador limitando el número de características a generar

Una vez iniciado el Vectorizer invocaremos al método fit_transform usando la columna resumen del dataframe. El método get_feature_names permite obtener las diferentes características. La matriz dispersa se almacena en un DataFrame que almacena por filas las películas y por columnas los nombres de las características.

Figura 17. Matriz de similitud coseno

Similitud Coseno

En este caso utilizaremos una métrica que cuantifica mejor la similitud entre elementos con mayor variabilidad. A esta métrica se la conoce como Cosine Similarity o Similitud Coseno. Sin entrar en los detalles matemáticos, se encarga de medir el ángulo entre dos documentos en el espacio métrico de multiples dimensiones. Mostramos un ejemplo de esta métrica trasladada al caso del espacio bidimensional. Toma valores entre 0 y 1, donde 1 representa similitud total.

Figura 18. Formula y representación gráfica de la similitud coseno

Esta función permite hacer el cálculo entre dos películas cualesquiera. La diferencia es que en este caso, será necesario hacer un reshape como se muestra a continuación. El grado de similitud entre los resúmenes de la primera y la segunda parte de la película Cars es de 0.38.

Figura 19. Similitud Coseno entre dos películas basado en su resumen

De forma similar y partiendo de un DataFrame, Scikit Learn es capaz de calcular de una vez la similitud coseno entre todas las filas.

Figura 20. Similitud coseno de todos los elementos

Una vez calculados esos valores construimos un nuevo DataFrame de similitudes coseno.

Figura 21. DataFrame de similitudes coseno

Esto nos permite saber qué películas son más parecidas a una en concreto basándonoslos en sus resúmenes. Si buscamos recomendaciones de películas similares a Harry Potter y el Cáliz de Fuego obtenemos sugerencias para visualizar el resto de la saga.

Figura 22. Recomendaciones de películas similares a Harry Potter y el Cáliz de Fuego

Si hacemos la consulta para el caso del Señor de los Anillos: La comunidad del anillo, vemos que nos recomienda las películas de la trilogía y el Hobbit. También nos recomienda Four Sisters and a Wedding debido a que el protagonista de la película se llama Frodo también.

Figura 23. Recomendaciones de películas similares a El Señor de los Anillos: La Comunidad del Anillo

Añadimos un último caso con la película Mary Poppins. El recomendador nos sugiere como segunda opción ver la película Saving Mr. Banks, que trata sobre la colaboración entre Walt Disney y la escritora de la novela Mary Poppins.

Figura 24. Recomendaciones de películas similares a Mary Poppins

Recomendar en base al perfil del usuario

Lo que no hemos tenido en cuenta hasta ahora es que los usuarios no son tan unidimensionales como para que les guste sólo un elemento. La realidad es que el usuario habrá visto una serie de películas y querrá que la recomendación proporcionada por los algoritmos esté alineada con su amplio gusto.

Consideremos el caso que acabamos de mencionar: un usuario que ha visto una serie de películas. La forma más directa de crear el perfil de usuario es inicialmente, creando un vector que contenga los títulos de dichas películas para conseguir a través del método .loc los vectores de características de las mismas.

Figura 25. creando el perfil del usuario

Para terminar de construir el perfil de este usuario es necesario representar todas las preferencias del usuario en una única serie. Eso lo conseguimos haciendo la media de cada característica con el método .mean.

Figura 26. Perfil del Usuario

Este perfil del usuario lo usaremos para encontrar las películas con mayor similitud que no haya visto todavía. En primer lugar, tendremos que determinar el subconjunto de películas que no ha visto todavía (eliminando del dataframe del vectorizer todas aquellas películas que están en la lista de vistas). El número de filas ha disminuido de 34886 a 34880 (6 filas).

Figura 27. resultado de eliminar las seis películas vistas por el usuario

Después calcularemos la similitud coseno entre el perfil de usuario que acabamos de crear y el DataFrame de películas que aún no ha visto el usuario. Después, almacenaremos la salida en un nuevo DataFrame y ordenaremos los resultados para poder acceder y ordenar los datos de forma sencilla.

Figura 28. Recomendación basada en el historial del usuario

Ahora si que el algoritmo ha sido capaz de recomendar en base al historial de películas vistas por nuestro usuario, y no sólo basándose en películas individuales. Los registros más arriba en la tabla son los más parecidos a los intereses del usuario en base al background de intereses que recoge su perfil.

Si quieres más información sobre nuestro master, puedes contactar con nosotros bien por teléfono al +34 910 91 28 42 o +34 630 88 13 53, por whatsapp directamente pinchando aquí o aquí, o mandando un mail con tus datos de contacto (nombre completo y teléfono) a: info@datahack.es

chevron-down