Archivo de la categoría: Big Data

Resumen del paper: Análisis de datos topológicos

Recientemente me encontré un par de papers relevantes para la minería de datos (data mining). Incluso hay una empresa que basa su business model en este concepto (Ayasdi). El concepto como habéis podido leer en el titulo es análisis de datos topológicos. ¿Que significa esto? La ida principal, tal y como se expone en la Figura 1 (sacada del paper [1]), se basa en que los datos tienen forma y la forma es consistente. Por ejemplo, la letra “A” seguirá siendo la misma letra a pesar de que le apliquemos distintas transformaciones ya que la información obtenida es calculada en base a las distancias relativas. Podemos rotar los datos, hacia un lado u otro. Podemos cambiar la tipografía o la forma (aplastarla o extenderla) que seguirá siendo la misma letra. Al final la letra “A” esta formada por millones de puntos que no vemos. Quizás perdemos algo de detalle especifico pero se gana en visión global.

descripción gráfica de la letra A
Figura 1: Transformaciones aplicadas a la letra A siguen formando la misma letra. Extraído de [1]
El primer paso consiste en agrupar en sub-poblaciones en bins (contenedores). En el segundo paso estas divisiones son analizadas. Cada uno de los contenedores contiene puntos que son similares el uno al otro. Como los bins han sido divididos de tal forma que solapan entre ellos por lo que cada punto de nuestros datos pueden estar en más de un grupo. Finalmente para construir la red (network) dibujamos un link entre los distintos clusters de la network final.

Para empezar a construir la red tenemos que escoger la métrica y la lente. La métrica la usaremos para medir la similitud (o distancia) entre dos puntos mientras que la lente es una función matemática para observar los datos. Cualquier métrica que sirva para producir un numero de un punto puede ser una lente. Una lente puede ser la media, max, min, el centro, PCA-score, distancia SVM, entre otros. Se pueden agrupar los resultados de distintas lentes multiplicando el resultado de los outputs.

El vector unitario producido por a lente es dividido en subgrupos que se solapan. Todos los puntos que tienen valores de lentes en el mismo subgrupo se agrupan juntos en un contenedor. De esta forma distintas particiones son obtenidas para todos los puntos gracias al resultado de la lente. Como las lentes producen sets que solapan es posible que un punto este en múltiples contenedores. Todos los puntos en un contenedor son agrupados ya que todos los puntos son altamente similares entre si y este grupo representa un simple nodo de nuestra red. El color que le asignaremos es la media del color de la lente de este grupo. El nodo en su representación gráfica tiene un tamaño proporcional al numero de puntos que tenga el cluster.

Habiendo hecho lo pasos anteriores tendremos distintos nodos en nuestra red, con diferentes tamaños y colores. Los nodos se conectaran entre si cuando tengan puntos en común. Estos links generaran la red topológica final.

Tenemos que tener en cuenta que esta implementación tiene dos parámetros. Uno es la resolución que indica el numero de contenedores en los cuales vamos a partir los datos. Una baja resolución genera unos pocos nodos gruesos sintetizando la información generada por el algoritmo. Contrariamente si la incrementamos genera muchísimos nodos pero de un tamaño mas pequeño perdiendo similitud entre nodos incluso generando clusters aislados. El segundo parámetro se llama ganancia y controla las regiones que se solapan entre contenedores. Como mas grande sea la ganancia mas aristas (conexiones entre nodos) vas a obtener el tu red. Este parámetro resalta las relaciones entre los elementos de tus datos.

No hay unos valores óptimos para la resolución y la ganancia. Cada red es singular y sus parámetros tienen que ser escogidos acordemente. También depende de lo que se quiera observar en la red. Por lo que cada análisis requerire una afinación (tuning). Tened en cuenta que una resolución alta no siempre es lo mejor, ya que al final lo que puede producir un resultado muy similar al observar los datos directamente

Ya hemos explicado todas las ventajas ahora toca exponer algunas de sus desventajas. No es ninguna “magic bullet” puede funcionar para muchos casos pero hay otros en los que este algoritmo no sea el mejor para nuestros datos. No hay una sola solución que sea buena para todos los casos. Parte del problema es que es una ciencia con un alto componente matemático. Como los principios del deep learning, hasta que no haya implementaciones eficientes y fáciles de usar, la “gente normal” se va a abstener de usarlo. Finalmente, el coste computacional. Calcular todos los pasos es extremadamente costoso ya que se tienen que hacer distintos barridos sobre los datos e incluso calcular las distancias entre pares.

Para los que os vaya la marcha os dejo un vídeo de youtube. Se trata de un seminario en Standford donde se explica extremadamente bien el concepto (en ingles). Luego os dejo una presentación en slideshare donde se explica el concepto detalladamente. Y para terminar os dejo tres referencias que he usado para escribir este post y que si entendéis inglés las recomiendo encarecidamente que les echéis un vistazo.

 

 

Archivos multimedia para profundizar en el TDA

 

Referencias:

 

  1. Offroy, M., & Duponchel, L. (2016). Topological data analysis: A promising big data exploration tool in biology, analytical chemistry and physical chemistry. Analytica chimica acta910, 1-11.
  2. Nielson, J. L., Paquette, J., Liu, A. W., Guandique, C. F., Tovar, C. A., Inoue, T., … & Lum, P. Y. (2015). Topological data analysis for discovery in preclinical spinal cord injury and traumatic brain injury. Nature communications6, 8581.
  3. Chazal, F., & Michel, B. (2017). An introduction to Topological Data Analysis: fundamental and practical aspects for data scientists. arXiv preprint arXiv:1710.04019.

Como calcular distancias entre dos arrays con variables binarias

El computo de distancias es un procedimiento básico para poder procesar datos. Las distancias nos sirven en el mundo real para poder desplazarnos con efectividad pero también podemos usar las distancias en el mundo no-físico para medir la similitud entre dos entidades. Cuando hablamos de entidades no-físicas nos referirnos por ejemplo a palabras, objetos o conceptos abstractos. Por ejemplo, ¿Cual es la similitud entre dos palabras? Dependiendo del enfoque podemos obtener resultados muy distintos. En este caso estoy interesado en los distintos métodos para calcular distancias entre dos vectores binarios por ejemplo [0,1,0,0,0,1,1] y [0,0,1,0,0,1,0]. Si fueran vectores normales los podríamos tratar en el plano euclidiano calculando distancias como lo haríamos sobre un mapa pero usando 7 dimensiones, pero al ser binarios cada dimensión solo puede ser 0 ó 1 (y ningún otro valor intermedio). La solución no pasa por asignar otros números a las variables porque substituyendo el “uno” por un “tres” no cambia nada. Por ejemplo, las palabras binarias pueden servir para codificar si eres hombre (0) o mujer (1). ¿Cual es la distancia entre un hombre y una mujer? Lo mismo pasa con palabras, cual es la distancia entre “hola” y “guacamole” No hay un solo método universal que nos sirva para todos los problemas, por esta razón he hecho esta lista para que os pueda servir en un futuro. Los métodos de esta lista calculan la distancia entre vectores con elementos binarios. Cada método – o algoritmo – tiene sus ventajas e inconvenientes obligando al usuario a entender el problema y escoger la solución más adecuada para cada caso.

Todas las formulas siguen el mismo patrón. En la siguiente tabla hay todas las opciones que las variables pueden tomar:

. y = 1 y = 0 Total
x = 1 n11 n10 n1•
x = 0 n01 n00 n0•
Total n•1 n•0 N

Coeficiente de Jaccard

El coeficiente de Jaccard o el índice de Jaccard es una de las distancias mas intuitivas. Computa la cardinalidad de la intersección de los dos conjuntos (el numero de elementos que están en los dos grupos a la vez) dividido por su unión (todos los elementos que forman parte de un grupo o del otro). Dividiendo usando la unión de los conjuntos evita que conjuntos grandes con poca similitud dominen el espacio.

$$ Coeficente de Jaccard = \frac{n11}{n1•+n•1}$$

Coeficiente de Sørensen–Dice

Este método fue originalmente desarrollado para la botánica. Sørensen y Diece lo desarrollaron de forma independiente con 3 años de diferencia. Muy parecido al anterior, este se basa en dos veces la intersección dividido por la cardinalidad de los conjuntos. El numerador es multiplicado por dos porque en el denominador la unión de estos conjuntos contiene la intersección de los conjuntos duplicada, hay un conjunto de elementos que están en el grupo A y el grupo B.

$$ Sørensen-Diece = \frac{2*n11}{n•1+n1•}$$

Coeficiente de correlación de pearson

Quizás esta sea la métrica más avanzada de este post. A pesar de que algunos estadistas la han usado no tengo tan claro que sea una buena métrica para comparar arrays binarios. A pesar de esto lo voy a dejar al gusto del lector comprobar su validez con los datos.

$$ Coef pearson = \frac{ (n11-\frac{n01*n10}{N})}{sqrt(n10-N*n10/n^2)*sqrt(n01-N*n01/n^2)}$$

Coeficiente de Phi

El coeficiente Phi o coeficiente de correlación de Matthews es una medida para la asociación de dos variables binarias. En teoría si calculamos el coeficiente de correlación pearson para dos variables binarias nos dará el mismo resultado que con el coeficiente Phi.

$$Phi = \frac{n11*n00 – n10*n01}{sqrt(n0•*n1•*n•0*n•1)} $$

Distancia de Yule

Con la distancia distancia de yule no es extrapolable a otras métricas. Como estamos pudiendo ver todas las métricas se parecen mucho. Se busca lo común entre los conjuntos y se divide por el computo global o similar para corregir para el tamaño de los grupos.

$$ Yule distance = \frac{2*(n10+n01)}{n11+n01+n10+n01} $$

Russell-rao

En este caso la métrica es algo distinta. Las otras métricas miran lo que tienen en común los grupos, este algoritmo hace lo contrario. Rusell-rao buscan lo que no tienen en común. Aunque siguen normalizando el resultado para conseguir valores relativos.

$$Russel-Rao = \frac{N-n11}{N}$$

Sokal-Michener

Por esta distancia y la siguiente no encontré mucha información, por lo que usé los detalles de implementación de la libreria de python scipy.

$$ Skoal-Michener = \frac{2*(n1•+n•1)}{(2*(n1•+n•1)+n11+n00)}$$

Rogers-Tanmoto

Al igual que el anterior aquí os dejo el link a la implementación de scipy.

$$ Rogers-Tanmoto = \frac{n11+n00}{n11+n00+2*(n10+n01)} $$

Mutual information

O en español información mutua mide la interconexión entre dos variables. Puesto de otra forma, mide la incertidumbre de una variable habiendo observado otra (conocido como entropía). Esta métrica también es avanzada y aunque no se como funciona en comparación a pearson me da mejores vibraciones. Me ha resultado difícil/ineficiente implementarlo yo mismo completamente así que os dejo un snippet con el código en python.

[code language=”python”]

from sklearn.metrics import mutual_info_score

def calc_MI(x, y, bins):
c_xy = np.histogram2d(x, y, bins)[0]
mi = mutual_info_score(None, None, contingency=c_xy)
return mi

[/code]

Kulczynski-2

En teoría Kulczynski consiguió mejorar la facilidad de crear clusters. Lo mismo que hace Jaccard y que Russell-Rao mejoraron. Este es la segunda versión, más sofisticada.

$$ Kulczynski-2 = \frac{\frac{n11^2}{(n11+n01)*(n11+n10)}}{2} $$

Ochiai

En teoría ochiai – también conocido como cosine similarity– consigue mejorar Kulczynski-2 y consecuentemente Jaccard y Rusell-Rao.

$$ Ochiai = sqrt(\frac{a^2}{(n11+n10)*(n11+01)} $$

Yo lo dejo aquí pero podéis encontrar más métricas en los siguientes enlaces:

Search Results Binary Vector Dissimilarity Measures for Handwriting Identification consta de varias métricas, algunas ya señaladas en los anteriores apartados. Tengo que decir que las formulas que exponen me parecen algo raras, no se si las han adaptado al caso en concreto.

Para una descripción en profundidad de Kulczynski y Ochiai

Spearman’s rank correlation coefficient or Spearman’s rho para vuestro disfrute.

Optimizadores de tensor flow

Continuando el anterior post dónde introducí tensor flow hoy vengo con los optimizadores de funciones. Tensor flow ofrece optimizadores que cambian las variables para minimizar la funcion de perdida (loss function). El más simple es el de gradiente descendiente. Computan las derivadas simbólicas (symbolic derivatives) simplemente usando el modelo y la función tf.gradients. Por ejemplo:

[code language=”python”]
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
sess.run(init) # reset values to incorrect defaults.
for i in range(1000):
sess.run(train, {x:[1,2,3,4], y:[0,-1,-2,-3]})
print(sess.run([W, b]))
los resultados finales
[array([-0.9999969], dtype=float32), array([ 0.99999082],
dtype=float32)]
[/code]

El modelo completo para la regresión linal es:

[code language=”python”]
import numpy as np
import tensorflow as tf
# Model parameters
W = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
# Model input and output
x = tf.placeholder(tf.float32)
linear_model = W * x + b
y = tf.placeholder(tf.float32)
# loss
loss = tf.reduce_sum(tf.square(linear_model – y)) # suma de los cuadrados
# optimizer
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
# training data
x_train = [1,2,3,4]
y_train = [0,-1,-2,-3]
# training loop
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # reset values to wrong
for i in range(1000):
sess.run(train, {x:x_train, y:y_train})
# evaluate training accuracy
curr_W, curr_b, curr_loss  = sess.run([W, b, loss], {x:x_train, y:y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))
# When run, it produces
#W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11
[/code]
tf.contrib.learn te simplifica la vida con las funciones: ejecución, entrenamiento, iteraciones, evaluaciones entre otros

[code language=”python”]
import tensorflow as tf
import numpy as np
features = [tf.contrib.layers.real_valued_column("x", dimension=1)]
estimator = tf.contrib.learn.LinearRegressor(feature_columns=features)
x = np.array([1., 2., 3., 4.])
y = np.array([0., -1., -2., -3.])
input_fn = tf.contrib.learn.io.numpy_input_fn({"x":x}, y, batch_size=4,
num_epochs=1000)
estimator.fit(input_fn=input_fn, steps=1000)
print(estimator.evaluate(input_fn=input_fn))
# Result: {‘global_step’: 1000, ‘loss’: 1.9650059e-11}
[/code]

Introducción a TensorFlow

La web oficial de TensorFlow tiene muy buenos recursos. En esencia lo que hay en este post proviene del “get started” de la web oficial.

En el primer ejemplo importaremos TensorFlow. Crearemos dos constantes y las imprimiremos en pantalla.

[code language=”python”]
import tensorflow as tf
node1 = tf.constant(3.0, tf.float32)
node2 = tf.constant(4.0) # También tf.float32 de forma implícita
sess = tf.Session()
print(sess.run([node1, node2]))
node3 = tf.add(node1, node2)
print("node3: ", node3) #Esta linea muestra las propiedades del tensor
print("sess.run(node3): ",sess.run(node3)) # Aquí se imprime el resultado[/code]

También podemos aplicar operaciones a los tensors. Las operaciones producen más tensores. En el siguiente ejemplo sumamos dos variables (tensores) y luego las sumamos. Un tensor es capaz de procesar listas también como veremos.

[code language=”python”]
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b
print(sess.run(adder_node, {a: 3, b:4.5})) # 7.5
print(sess.run(adder_node, {a: [1,3], b: [2, 4]})) # Itera sobre la lista: 3 y 7
[/code]

Podemos multiplicar

[code language=”python”]
add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b:4.5}))
[/code]

E incluso podemos crear modelos lineales

[code language=”python”]
W = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b
[/code]

Las constantes son inicializadas con tf.constant, y su valor no puede ser cambiado. Contrariamente las variables son creadas usando tf.Variable y no son inicializadas en el inicio. Para inicializar las variables  tenemos que usar una función especial como en el siguiente ejemplo:

[code language=”python”]
init = tf.global_variables_initializer()
sess.run(init)
[/code]

Lo importante es usar init. Es un “handle” que inicia el grafo, inicializando las variables que hasta entonces habían permanecido sin inicializar.

Ya que la X es la variable podemos evaluar el modelo usando distintos valores simultáneamente de la siguiente manera:

[code language=”python”]
print(sess.run(linear_model, {x:[1,2,3,4]}))
# Output: [ 0, 0.30000001, 0.60000002, 0.90000004]
[/code]

La función de pérdida (loss function) puede medir la distancia entre el modelo actual y los datos proporcionados. Usaremos la función de pérdida estándar para hacer una regresión lineal que sume los cuadrados de las distancias entre el modelo actual y los datos. El modelo crea un vector en el que cada posición corresponde a una distancia de error. Cuando usamos tf.square estamos elevando al cuadrado el error. Luego sumamos los errores para crear un simple escalar que abstrae el error de todos los puntos usando tf.reduce_sum:

[code language=”python”]
y = tf.placeholder(tf.float32)
squared_deltas = tf.square(linear_model – y)
loss = tf.reduce_sum(squared_deltas)
print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))
[/code]

El valor producido es:  23.66

Podríamos mejorar el modelo manualmente asignando nuevos valores a W para obtener resultados perfectos de -1 y 1. Una variables es inicializada por el valor proporcionado por tf.Variable pero puede ser cambiada si usamos operaciones como tf.assign. Por ejemplo, W=-1 y b=1 son los parámetros óptimos de nuestro modelo. Podemos cambiar W y b acordemente:

[code language=”python”]
fixW = tf.assign(W, [-1.])
fixb = tf.assign(b, [1.])
sess.run([fixW, fixb])
print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]})
#resultado: 0
[/code]

Hemos adivinado el valor perfecto para W i b aunque este no es el objetivo de  machine learning. El objetivo es encontrar los parámetros correctos para el modelo automáticamente. Pero esto lo vais a encontrar en la próxima entrega 😉

Bonus: En matemáticas y en física, un tensor es cierta clase de entidad algebraica de varias componentes, que generaliza los conceptos de escalar, vector y matriz de una manera que sea independiente de cualquier sistema de coordenadas elegido. ( wikipedia )

Reducción de dimensiones: Principal Component Analysis (PCA)

Principal Component Analysis o PCA en corto es un método de reducción de dimensiones bastante conocido y comúnmente usado. Este método transforma ortogonalmente las observaciones (quizás relacionadas) en un conjunto de puntos linealmente no relacionados. De esta forma se consigue que el primer componente tenga la varianza mayor. El siguiente componente será el que tendrá la varianza mayor de los restantes y es ortogonal al anterior componente, y así sucesivamente. Este método es sensible a la escala de las variables. Para evitar que los valores sean un problema tendremos que escalar las variables estandardizándolos antes de usar PCA.

Reducción de dimensiones: Self-organizing feature map (SOFM)

Self-organizing map (SOM) o self-organizing feature map (SOFM) es un método que usa redes neuronales (neuronal networks) para reducir las dimensiones de un vector de datos. Para reducir las dimensiones lo que hace es usar los vecinos de un punto en concreto para moverlo al nuevo espacio dimensional manteniendo la misma topografía que en el espacio original.

Una de las ventajas de SOFM es que es un método unsupervised, esto quiere decir que no necesitamos un training dataset para entrenar nuestra red neuronal. Normalmente para la inteligencia artificial (y el machine learning) se requiere que el training dataset esté etiquetado. Un data set etiquetado son puntos del input que ya se sabe cual tiene que ser el resultado. De este modo la maquina es capaz de identificar que resultado tiene que producir.

Para explicar con más detalle este método voy a usar la foto de la wikipedia que lo hace más visual.

Somtraining
SOMF training

 

En la imagen vemos la malla que representa el input en un espacio multidimensional y la zona azul que representa un espacio 2D al que queremos extrapolar nuestros puntos. El primer paso es seleccionar nuestro punto en el espacio de origen que se acerque mas al espacio 2D. El segundo paso es mover ese punto en concreto al espacio 2D. El tercer paso, y ultimo, consiste en mantener las distancias entre puntos en el nuevo plano. Si se consigue mantener las distancias entre los puntos conseguiremos una reducción de dimensiones satisfactoria.

El paper original lo podéis encontrar aquí. Pero si no tenéis ninguna afiliación académica quizás os interese checkear este otro post.

Reducción de dimensiones: T-SNE

Como ya explicamos en el post anterior los ordenadores si que pueden procesar grandes cantidades de datos multidimensionales. Pero los humanos a veces necesitamos “ver” y entender los datos. Cuando estamos trabajando en un espacio multidimensional no podemos imaginarnos nuestro dataset. Para solventar este problema se ha desarrollado T-SNE. Éste es un algoritmo pensado especialmente en reducir dimensiones (a 2 o 3) para que podamos visualizar los datos. En el paper original se expresa de forma explícita que el algoritmo está pensado para la visualización de datos. Usar T-SNE para la reducción de dimensiones puede causar efectos desconocidos. Así que si lo usas para evitar “la maldición de la dimensionalidad”  allá tu 😉

El concepto principal consiste en que los puntos cercanos (en el espacio multidimensional) se atraen y los distantes se repelen. Para conseguir este objetivo el algoritmo tiene unos cuantos parámetros que se permiten alterar. La “perplexity” es la cantidad de vecinos que un simple punto puede afectar. Por lo que he visto hasta ahora un valor entre 30-50 suele ser el óptimo. Luego tenemos epsilon que nos sirve para determinar el tamaño de los pasos de aprendizaje. Valor pequeño el algoritmo le cuesta más a encontrar el óptimo. Con un valor grande te lo puedes pasar. Finalmente la cantidad de iteraciones o steps para conseguir la convergencia. A más iteraciones en teoría más cerca del valor óptimo, pero como es evidente como más iteraciones más tiempo de computación requieres.

Para los que queráis visualizar como funciona y un poco sus efectos cambiando los parámetros podéis verlo en vuestro navegador. Si por el contrario queréis implementarlo en Javascript aquí podéis encontrar una versión oficial del desarrollador principal (es la que estoy usando). Pero si sois tan malotes que queréis implementarlo vosotros mismos mejor que os leáis el paper original.

Bonus: En el paper para computar las distancias se usa la distancia euclidiana (la “normal”) quizás otro tipo de distancias puede ir mejor para vuestro problema.

Reducción de dimensiones: Introducción a los espacios multidimensionales

En inteligencia artificial y machine learning en la mayoría de ocasiones se usan espacios multidimensionales. Los espacios multidimensionales son espacios en los que los datos requieren más de un valor. Los espacios multidimensionales son espacios con puntos repartidos por el espacio. Un espacio 2D tiene dos dimensiones, las típicas X, Y. Un espacio 3D tiene tres dimensiones X, Y, Z. Las dimensiones las puedes llamar X, Y, Z pero también perro, gato, conejo. Como seres humanos estamos limitados a poder visualizar espacios a 3D máximo. Aunque no puedas visualizar dimensiones superiores a tres, puedes llegar a entenderlo. Imagínate que quieres ir a un restaurante a 10km máximo de tu casa. Esto en un mapa son dos dimensiones norte/sur y este/oeste. Ahora si decides que quieres ir a un restaurante italiano ya hemos añadido otra dimensión. Si no quieres pagar más de 10€ por la cena ya has añadido otra dimensión. Por lo que ya tenemos un espacio de 4D. Dos para las dimensiones del mapa norte/sur, este/oeste, otra para que tipo de restaurante y la cuarta para los precios. Se le podría sumar otra dimensión si añadiéramos en que planta esta el restaurante. Virtualmente podríamos añadir infinidad de dimensiones.

Un vector o un punto en nuestro espacio es un conjunto de valores para todas las dimensiones. Un valor (o dato) puede ser indefinido o ausente, no tiene porque tener un valor concreto. Un punto es asociado a la persona o el elemento de la acción. Tu puedes ser ese vector/punto. Con el ejemplo anterior nuestro punto sería (23, 31, italiano, 10) que hacen referencia a norte/sur, este/oeste, tipo de comida y precio máximo. Las variables pueden ser categóricas y cuantitativas. Las categóricas es “italiano” no tiene un valor númerico asociado. Otros ejemplos de variables categóricas pueden ser el sexo de una persona o su color preferido. Las variables cuantitativas son los números.

La pregunta del millón es: cómo podemos pensar en un espacio de más de tres dimensiones en el que una de ellas es “italiano”? Simplemente no podemos. Nuestro cerebro no puede visualizar más de tres dimensiones. Estos espacios sólo tienen sentido matemáticamente. Por lo que para trabajar en este tipo de espacios si queremos visualizarlos de algún modo tenemos que pensar en tres dimensiones máximo y extrapolarlo. Otra opción también puede ser usar distintas técnicas de reducción de dimensiones. En los próximos posts describiré distintos métodos para la reducción de dimensiones.

Que formato es el mejor para guardar números con decimales (float)?

Hace ya algunos días que le estoy dando vueltas al crear un script que me cogiera determinados datos y los fuera guardando en un archivo. Como quiero guardar muchos datos durante un largo periodo de tiempo he pensado que quizás debería empezar por lo básico. Que formato de archivo es mejor para almacenar este tipo de datos.

Para averiguar que formato es el ideal para tal propósito he ideado un script en python que lo que hace es generar cuatro números aleatorios entre -10 y 10 por cada una de las 100.000 hileras disponibles (en total 400.000 valores). Luego, usando el mismo data set, he almacenado esta información usando distintos formatos. Los formatos que he usado son texto plano, CSV, TSV, JSON, SQLite y HDF5. Estos formatos son los que me han parecido adecuados para este tipo de tarea. He dejado fuera XML porque me pareció que tiene gran similitud con JSON y realmente no necesito la jerarquía ni flexibilidad que este formato me ofrece.

Véase que el mismo script indica el tamaño de cada fichero. El tiempo de ejecución es de unos 65 segundos en mi laptop.

El script:

[code language=”python”]

import numpy as np
import os
from os import listdir
from os.path import isfile, join

import json
import csv
import sqlite3
import h5py #pip install h5py

#generated 4 rows with number_of_floats data
def data_generation(number_of_floats):
ret = np.ndarray((number_of_floats, 4))
for i in range(number_of_floats):
ret[i] = np.random.uniform( -10, 10, 4 )
return ret

#standard text saving
def save_text_file(data):
f = open(‘text.txt’, ‘w’)
for el in data:
f.write(str(el).strip(‘[]’))
f.write(‘\n’)
f.close()
return True

#saving with json files
def save_json(data):
f = open(‘json.json’, ‘w’)
j=json.dumps(data.tolist())
json.dump(j, f)
f.close()
return True

#saving numbers on csv
def save_csv(data):
with open(‘csv.csv’, ‘w’) as csvfile:
fieldnames = [‘Col_A’, ‘Col_B’, ‘Col_C’, ‘Col_D’]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
for el in data:
writer.writerow({‘Col_A’: str(el[0]), ‘Col_B’: str(el[1]),’Col_C’: str(el[2]),’Col_D’: str(el[3])})
return True

#Tab Separated Values (TSV)
def save_tsv(data):
with open(‘tsv.tsv’, ‘w’) as tsvfile:
writer = csv.writer(tsvfile, delimiter=’\t’)
for el in data:
writer.writerow(el)
return True

#save data in sqlite
def save_sqlite(data):
conn = sqlite3.connect(‘data.sqlite3’)
cur = conn.cursor()
cur.execute(‘DROP TABLE IF EXISTS Data ‘)
cur.execute(‘CREATE TABLE Data (Col_A REAL, Col_B REAL, Col_C REAL, Col_D REAL)’)
for el in data:
cur.execute(‘INSERT INTO Data VALUES (‘+str(el[0])+’, ‘+str(el[1])+’, ‘+str(el[2])+’, ‘+str(el[3])+’)’)
conn.commit()
conn.close()

#save the data in a hdf file
def save_hdf(data):
h = h5py.File(‘data.hdf5’, ‘w’)
dset = h.create_dataset(‘data’, data=data)

#check the file size
def show_file_size():
mypath = ‘.’
onlyfiles = [ f for f in listdir(mypath) if isfile(join(mypath,f)) ]
for fil in onlyfiles:
statinfo = os.stat(fil)
print ‘name: ‘+str(fil)
print ‘size: ‘+str(statinfo.st_size)
print ‘ ‘
print onlyfiles

##############################
#
# Main
#
##############################

data = data_generation(100000)
save_text_file(data)
save_csv(data)
save_json(data)
save_csv(data)
save_tsv(data)
save_sqlite(data)
save_hdf(data)
show_file_size()
print ‘Done’

[/code]

Finalmente los resultados:

data-format-comparsion-plot

Formato Tamaño (Bytes)
Texto plano 4806060
CSV 5900742
TSV 7901330
JSON 8109034
SQLite 4468736
HDF5 3202144

Como se puede observar HDF5 es el ganador claramente siendo casi un 30% menor en tamaño que Sqlite que está ocupando el segundo lugar. No es de extrañar puesto que HDF es un formato de fichero diseñado especialmente para organizar y almacenar grandes cantidades de datos (ideado para supercomputadores). Para nuestra suerte las librerías tienen licencia BSD permitiendo mejoras y creación aplicaciones por parte de terceros. Lo que no me esperaba es que TSV obtuviera un tamaño similar a JSON y no a CSV. Sinceramente pensaba que CSV y TSV eran básicamente lo mismo.

Bonus: Para los interesados el script está en github.

Instalar MongoDB en Ubuntu

Uno de los propósitos de año nuevo, como ya visteis, ya me he puesto manos a la obra en aprender MongoDB. Para esto necesito tenerlo instalado en el ordenador (con SO Ubuntu) para poder trastear. Así que al turrón!

Primero de todo MongoDB nos recomienda importar la “public key” usada por el gestor de paquetes.

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10

Luego crearemos una lista en un fichero para MongoDB

echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list

Seguidamente actualizaremos la base local de paquetes con:

sudo apt-get update

Finalmente instalaremos la última versión estable de MongoDB

sudo apt-get install -y mongodb-org

Y así se instala MongoDB en nuestro ordenador local con Ubuntu! 🙂

Para iniciar MongoDB tendremos que ejecutar en la consola “mongod”. Pero para acceder a la consola y poder ejecutar queries en la base de datos tendremos que usar el comando “mongo”.

Bonus: Para los curiosos, la versión de 32bits permite un límite teórico de 4,3GB de datos (2^32). Teniendo en cuenta padding, espacios vacíos y otras ineficiencias la empresa estima que el espacio disponible para datos es de entre 2GB y 4GB.