PyTables
Procesando y analizando
enormes cantidades de datos
en Python
Francesc Alted
[email protected]
iParty 5, 13 de Marzo de 2003, Castelló
Esquema
¿Qué es PyTables, qué ofrece y porqué existe?
Introducción a las bases de datos jerárquicas
Demostración interactiva
Algunos "benchmarks"
Notas finales
Motivación
Muchas aplicaciones necesitan guardar y leer grandes
cantidades de datos --> desafío
Los ordernadores actuales son suficientemente potentes para
manejar esas cantidades de datos. El problema es:
podemos procesarlos los humanos?
Requisitos:
El análisis es un proceso iterativo: interactividad
Releer múltiples veces los datos: eficiencia
Buen entorno para dotar a los datos de una estructura
Fácil manejo
PyTables es un paquete Python diseñado con estos requisitos en
mente.
¿Qué es PyTables?
Es una base de datos jerárquica para Python
Permite trabajar con tablas y matrices multimensionales
Pensada para que sea fácil de usar
Optimizada para trabajar con grandes cantidades de datos
¿Qué ofrece PyTables?
Interactividad
El usuario puede tomar acciones inmediatas dependiendo del resultado de las
operaciones anteriores
Esto acelera enormemente el proceso de extración de información ("data
mining")
Eficiencia
Mejora la productividad
Muy importante cuando la interactividad es necesaria
Estructura jerárquica de los datos
Permite organizar los datos en grupos pequeños y relacionados y en un sólo
fichero
Ofrece una forma intuitiva y compacta de clasificar los datos
Interface orientada al objeto
Los conjuntos de datos son objetos fácilemente manipulables
En una estructura jerárquica, facilita el acceso a los datos
Modelo de datos jerárquico
Los datos se organizan en una estructura arbórea
En la cúspide de la estructura se encuentra la raíz
Cada nivel (excepto la raíz) tiene un sólo nivel por encima
(padre), pero puede tener muchos niveles por debajo (hijos)
Cada nivel sólo tiene un campo clave ("key field")
¿Por qué jerarquizar los datos?
Aparece de manera natural en muchos casos:
Dispersión geográfica
Dispersión temporal
Categorización de la información (LDAP)
La misma estructura arbórea da mucha información
/eu/es/uji/exp
El acceso a la información se hace más intuitivo
La velocidad de acceso a datos es normalmente mayor que en
bases de datos relacionales (tiempo de acceso de log(N) con una
base de datos de tamaño N)
Caché (Intersystems)
Google
Web semántica (XML)
Ejemplo de dispersión geográfica
Ejemplo de categorización de materias
Maquinaria detrás de PyTables
PyTables aprovecha diferente software para conseguir sus
objetivos:
Python -- lenguaje interpretado (fundamental para lograr la
interactividad)
HDF5 -- libreria y formato de propósito general para
almacenamiento de datos de carácter científico
numarray -- la siguiente generación del paquete Numeric
Pyrex -- herramienta que permite hacer extensiones Python con
una sintaxis muy parecida a la de Python
¿Qué es HDF5?
Es una libreria y un formato de fichero diseñado para guardar datos
de carácter científico de una manera jerárquica. Está desarrollado y
mantenido por el NCSA en EEUU.
Puede guardar dos objectos principales: "datasets" y grupos
Grupo -- estructura para organizar los objectos
"Dataset" -- array multidimensional de datos
Muy flexible y bien testeado en entornos científicos
API’s soportadas oficialmente: C, Fortran y Java
Se usa en: Metereología, Oceanografía, Astronomía, Astrofísica,
Simulación Numérica, ...
¿Qué es numarray?
Es la próxima generación del paquete Numeric Python
Dota de un potente lenguaje de manejo de matrices a Python
Los cálculos con las matrices són muy rápidos
Las matrices se guardan en memoria de manera eficiente
El número de dimensiones de la matrices es prácticamente
ilimitado (32)
Principales caracterísiticas de PyTables
Soporte de objectos Numeric Python y numarray
Puede leer ficheros genéricos HDF5 y trabajar con ellos
Soporta compresión de datos de manera transparente (y eficiente)
Puede trabajar con objectos que no caben en memoria
Soporta ficheros más grandes que 2 GB
Independiente de arquitectura (big/little endian)
Un primer ejemplo
Root
group
array1
0.1 0.2 0.3 0.4
table
array2
idnumber
identity
speed
1 2 3 4
0
1
2
3
4
5
6
7
8
9
Particle id: 0
Particle id: 1
Particle id: 2
Particle id: 3
Particle id: 4
Particle id: 5
Particle id: 6
Particle id: 7
Particle id: 8
Particle id: 9
0
2
4
6
8
10
12
14
16
18
El código PyTables
from tables import *
class Particula(IsDescription):
identity = Col("CharType", 16, " ", pos = 0) # cadena de caracteres
speed = Col("Float32", 1, pos = 2) # precisión simple
idnumber = Col("Int16", 1, pos = 1) # entero corto
fileh = openFile("example.h5", mode = "w")
group = fileh.createGroup(fileh.root, "group", "un grupo")
array = fileh.createArray(fileh.root, "array1", [.1,.2,.3,.4], "array de floats")
array = fileh.createArray(group, "array2", [1,2,3,4], "array de enteros")
table = fileh.createTable(group, "table", Particula, "Tabla con 3 campos")
row = table.row
for i in xrange(10):
row[’identity’] = ’Particle id: %3d’ % (i)
row[’idnumber’] = i
row[’speed’] = i * 2.
row.append()
fileh.close()
Fichero resultante del primer ejemplo
$ h5ls -rd example.h5
/array1 Dataset {4}
Data:
(0) 0.1, 0.2, 0.3, 0.4
/group Group
/group/array2 Dataset {4}
Data:
(0) 1, 2, 3, 4
/group/table Dataset {10/Inf}
Data:
(0) {0, "Particle id: 0", 0}, {1, "Particle id: 1", 2},
(2) {2, "Particle id: 2", 4}, {3, "Particle id: 3", 6},
(4) {4, "Particle id: 4", 8}, {5, "Particle id: 5", 10},
(6) {6, "Particle id: 6", 12}, {7, "Particle id: 7", 14},
(8) {8, "Particle id: 8", 16}, {9, "Particle id: 9", 18}
El árbol de objectos
fileObject(File)
+name: string = "example.h5"
+root: Group = groupRootObject
+open(filename:string)
+newGroup(where:Group,name:string): Group
+newTable(where:Group,name:string,description:IsDescription): Table
+newArray(where:Group,name:string,object:array): Array
+close()
groupRootObject(Group)
+_v_name: string = root
+group: Group = groupObject
+array1: Array = arrayObject1
groupObject(Group)
+_v_name: string = group2
+table: Table = tableObject
+array2: Array = arrayObject2
arrayObject1(Array)
+name: string = array1
+read(): Array
tableObject(Table)
+name: string = table1
+row: Row = rowObject
+read(): Table
arrayObject2(Array)
+name: string = array2
+read(): Array
rowObject(Row)
+identity: CharType
+idnumber: Int16
+speed: Float32
+append()
+nrow()
¿PyTables es rápido, pero cuánto?
Se han efectuado varios benchmarks para saber si PyTables es
competitivo con herramientas ya existentes para guardar datos
en disco
Se han hecho comparaciones cPickle, struct, shelve y SQLite
Se ha testeado la escritura y la lectura (con filtros) de datos
Los parámetros básicos que se han cambiado en cada test son:
El tamaño de fila
El número de filas en cada tabla
Las descripciones de las filas
Los tamaños de fila utilizados son de dos longitudes diferentes:
16 Bytes
class Small(IsDescription):
var1 = Col("CharType", 4, "")
var2 = Col("Int32", 1, 0)
var3 = Col("Float64", 1, 0)
56 bytes
class Medium(IsDescription):
name = Col("CharType", 16, "")
float1 = Col("Float64", 2, NA.arange(2))
ADCcount = Col("Int32", 1, 0)
grid_i = Col("Int32", 1, 0)
grid_j = Col("Int32", 1, 0)
pressure = Col("Float32", 1, 0)
energy = Col("Float64", 1, 0)
El mecanismo de selección
PyTables:
e = [ p[’var1’] for p in table.iterrows()
if p[’var2’] < 20 ]
cPickle:
while rec:
record = cPickle.loads(rec[1])
if record[’var2’] < 20:
e.append(record[’var1’])
struct:
while rec:
record = struct.unpack(isrec._v_fmt, rec[1])
if record[1] < 20:
e.append(record[0])
SQLite:
cursor.execute("select var1 from table where var2 < 20")
Nota: los tests con cPickle y struct usan una BBDD Berkeley (4.1.3) en su variedad
RECNO, con el fin de emular la fila de manera eficiente.
Descripción de la plataforma de benchmark
Portátil con Pentium IV @ 2 GHz and 256 MB RAM
Disco IDE @ 4200 RPM
PyTables 0.4
HDF5 1.4.5
numarray 0.4
Linux Debian 3.0
GCC 2.95
Comparación con cPickle y struct
Conclusiones del primer benchmark (cPickle y
struct)
PyTables resulta en:
Escritura
Entre 20 y 30 veces más rápido que cPickle
Entre 3 y 10 veces más rápido que struct
Lectura
Alrededor de 100 veces más rápido que cPickle
Alrededor de 10 veces más rápido que struct
PyTables es muy superior a cPickle y struct para cualquier cantidad
de datos (!)
Comparación entre SQLite y PyTables
Comparación con SQLite (escritura)
Writing with small record size (16 bytes)
PyTables & psyco
PyTables & no psyco
sqlite
800
700
600
500
400
300
200
100
s
/
w
o
r
K
0
2
3
4
5
6
log(nrows)
7
8
9
Writing with medium record size (56 bytes)
PyTabl
Comentarios de: PyTables - Procesando y analizando enormes cantidades de datos en Python (0)
No hay comentarios