NumPy matrices con SQLite

La interfaz SQLite más común que he visto en Python es sqlite3 , pero ¿hay algo que funcione bien con las matrices NumPy o las nuevas versiones? Me refiero a uno que reconoce los tipos de datos y no requiere insertar fila por fila, y extrae en una matriz NumPy (rec) …? Algo así como las funciones SQL de R en las bibliotecas RDB o sqldf , si alguien está familiarizado con ellas (importan / exportan / agregan tablas enteras o subconjuntos de tablas sqldf desde tablas de datos R).

¿Por qué no intentar redis ?

Los controladores para sus dos plataformas de interés están disponibles: python ( redis , a través del índice del paquete] 2 ) y R ( rredis , CRAN ).

El genio de redis no es que reconozca mágicamente el tipo de datos NumPy y le permita insertar y extraer arreglos NumPy multidimensionales como si fueran tipos de datos redis nativos, sino que su genio es la extraordinaria facilidad con la que puede crear tal Interfaz con unas pocas líneas de código.

Hay (al menos) varios tutoriales sobre redis en python; El que está en el blog de DeGizmo es particularmente bueno.

 import numpy as NP # create some data A = NP.random.randint(0, 10, 40).reshape(8, 5) # a couple of utility functions to (i) manipulate NumPy arrays prior to insertion # into redis db for more compact storage & # (ii) to restre the original NumPy data types upon retrieval from redis db fnx2 = lambda v : map(int, list(v)) fnx = lambda v : ''.join(map(str, v)) # start the redis server (eg from a bash prompt) $> cd /usr/local/bin # default install directory for 'nix $> redis-server # starts the redis server # start the redis client: from redis import Redis r0 = Redis(db=0, port=6379, host='localhost') # same as: r0 = Redis() # to insert items using redis 'string' datatype, call 'set' on the database, r0, and # just pass in a key, and the item to insert r0.set('k1', A[0,:]) # row-wise insertion the 2D array into redis, iterate over the array: for c in range(A.shape[0]): r0.set( "k{0}".format(c), fnx(A[c,:]) ) # or to insert all rows at once # use 'mset' ('multi set') and pass in a key-value mapping: x = dict([sublist for sublist in enumerate(A.tolist())]) r0.mset(x1) # to retrieve a row, pass its key to 'get' >>> r0.get('k0') '63295' # retrieve the entire array from redis: kx = r0.keys('*') # returns all keys in redis database, r0 for key in kx : r0.get(key) # to retrieve it in original form: A = [] for key in kx: A.append(fnx2(r0.get("{0}".format(key)))) >>> A = NP.array(A) >>> A array([[ 6., 2., 3., 3., 9.], [ 4., 9., 6., 2., 3.], [ 3., 7., 9., 5., 0.], [ 5., 2., 6., 3., 4.], [ 7., 1., 5., 0., 2.], [ 8., 6., 1., 5., 8.], [ 1., 7., 6., 4., 9.], [ 6., 4., 1., 3., 6.]]) 

La sugerencia de Doug con Redis es bastante buena, pero creo que su código es un poco complicado y, como resultado, bastante lento. Para mis propósitos, tuve que serializar + escribir y luego agarrar + deserializar una matriz cuadrada de aproximadamente un millón de flotadores en menos de una décima de segundo, así que hice esto:

Para la escritura:

 snapshot = np.random.randn(1024,1024) serialized = snapshot.tobytes() rs.set('snapshot_key', serialized) 

Entonces para leer:

 s = rs.get('snapshot_key') deserialized = np.frombuffer(s).astype(np.float32) rank = np.sqrt(deserialized.size).astype(int) snap = deserialized(rank, rank) 

Puede hacer algunas pruebas básicas de rendimiento con ipython usando% time, pero ni los tobytes ni el buffer de la fuente tardan más de unos pocos milisegundos.

Esto parece un poco más antiguo, pero ¿hay alguna razón por la que no pueda simplemente hacer un fetchall () en lugar de iterar y luego simplemente inicializar numpy en la statement?

Encontré al menos tres paquetes de Python para interactuar con SQLite y NumPy :

  • esutil.sqlite_util , que es parte de esutil
  • hydroclimpy.io.sqlite
  • mi propio RecSQL (disponible en github.com/orbeckst/RecSQL )

Cada uno de estos paquetes tiene que lidiar con el problema de que SQLite (de manera predeterminada) solo entiende los tipos de Python estándar y no los tipos de datos NumPy como numpy.int64.

RecSQL 0.7.8+ funciona para mí (la mayoría de las veces), pero considero que es un truco bastante malo y echar un vistazo al código, esutil.sqlite_util parece ser más maduro.