2011-03-20 49 views
11

Estoy usando PyTables 2.2.1 w/Python 2.6, y me gustaría crear una tabla que contenga matrices anidadas de longitud variable.En PyTables, ¿cómo crear una matriz anidada de longitud variable?

He buscado la documentación de PyTables, y el ejemplo tutorial (PyTables Tutorial 3.8) muestra cómo crear una matriz anidada de longitud = 1. Pero para este ejemplo, ¿cómo agregaría un número variable de filas a los datos 'info2/info3/x 'e' info2/info3/y '?

Por tal vez una estructura de tabla para entender más fácil, aquí está mi ejemplo de cosecha propia:

"""Desired Pytable output: 

DIEM TEMPUS Temperature    Data 
5  0  100   Category1 <--||--> Category2 
         x <--| |--> y   z <--| 
         0   0   0 
         2   1   1 
         4   1.33  2.67 
         6   1.5   4.5 
         8   1.6   6.4 
5  1  99 
         2   2   0 
         4   2   2 
         6   2   4 
         8   2   6 
5  2  96 
         4   4   0 
         6   3   3 
         8   2.67  5.33 


Note that nested arrays have variable length. 
""" 

import tables as ts 

tableDef =  {'DIEM': ts.Int32Col(pos=0), 
       'TEMPUS': ts.Int32Col(pos=1), 
       'Temperature' : ts.Float32Col(pos=2), 
       'Data': 
        {'Category1': 
         { 
         'x': ts.Float32Col(), 
         'y': ts.Float32Col() 
         }, 
        'Category2': 
         { 
         'z': ts.Float32Col(), 
         } 
        } 
       } 

# create output file 
fpath = 'TestDb.h5' 
fh = ts.openFile(fpath, 'w') 
# define my table 
tableName = 'MyData' 
fh.createTable('/', tableName, tableDef) 
tablePath = '/'+tableName 
table = fh.getNode(tablePath) 

# get row iterator 
row = table.row 
for i in xrange(3): 
    print '\ni=', i 
    # calc some fake data 
    row['DIEM'] = 5 
    row['TEMPUS'] = i 
    row['Temperature'] = 100-i**2 

    for j in xrange(5-i): 
     # Note that nested array has variable number of rows 
     print 'j=', j, 
     # calc some fake nested data 
     val1 = 2.0*(i+j) 
     val2 = val1/(j+1.0) 
     val3 = val1 - val2 

     ''' Magic happens here... 
     How do I write 'j' rows of data to the elements of 
     Category1 and/or Category2? 

     In bastardized pseudo-code, I want to do: 

     row['Data/Category1/x'][j] = val1 
     row['Data/Category1/y'][j] = val2 
     row['Data/Category2/z'][j] = val3 
     ''' 

    row.append() 
table.flush() 

fh.close() 

no he encontrado ninguna indicación en los documentos PyTables que tal estructura no es posible ... pero en tal caso una la estructura de hecho no es posible, ¿cuáles son mis alternativas a las columnas anidadas de longitud variable?

  • EArray? VLArray? De ser así, ¿cómo integrar estos tipos de datos en la estructura descrita anteriormente?
  • alguna otra idea?

¡Cualquier ayuda es muy apreciada!

EDITAR w/Información adicional: Parece que los gurús PyTables ya han abordado la "es una estructura de este tipo es posible" pregunta: ¿

PyTables Mail Forum - Hierachical Datasets

Así que alguien ha encontrado una manera de crear un análogo Estructura de datos PyTable?

¡Gracias nuevamente!

Respuesta

4

Esto es algo común que las personas que comienzan con PyTables quieren hacer. Ciertamente, fue lo primero que I intenté hacer. A partir de 2009, no creo que esta funcionalidad sea compatible. Usted puede mirar aquí por una solución "siempre recomiendo":

http://www.mail-archive.com/[email protected]/msg01207.html

En resumen, sólo hay que poner cada VLArray en un lugar separado. Si haces eso, tal vez no termines necesitando VLArrays. Si almacena VLArrays por separado para cada prueba (o lo que sea), puede mantener los metadatos en esas VLArrays (garantizados para permanecer sincronizados con la matriz entre renombrados, movimientos, etc.) o ponerlos en una tabla (más fácil de buscar).

Pero también puede seleccionar cualquier punto de tiempo para el átomo de columna, luego simplemente agregue otra columna para una marca de tiempo. Esto permitiría una matriz "irregular" que todavía tiene una estructura regular, repetida (tabular) en la memoria. Por ejemplo:

Trial Data 
1  0.4, 0.5, 0.45 
2  0.3, 0.4, 0.45, 0.56 

convierte

Trial Timepoint Data 
1  1   0.4 
1  2   0.5 
... 
2  4   0.56 

de datos anterior es un solo número, pero podría ser, por ejemplo, un átomo 4x5x3.

Si VLArrays anidados son compatibles con PyTables ahora, ¡me encantaría saberlo!

Alternativamente, creo que h5py es compatible con el conjunto completo de funciones de HDF5, por lo que si está realmente comprometido con el diseño de datos anidados, puede tener más suerte allí. ¡Sin embargo, perderás muchas características bonitas! Y en mi experiencia, los neurocientíficos ingenuos terminan con un rendimiento bastante pobre, ya que no obtienen opciones inteligentes para el diseño de los datos, fragmentación, etc. ¡Por favor, informe si va por esa ruta!

+0

Gracias por las sugerencias! Además, el enlace de la lista de correo tiene otros interesantes "pepitas" de sabiduría de Francesc. Al final, como me preocupaba la velocidad y el mantenimiento de la simplicidad, opté por el tamaño de matriz fijo con espacio adicional acolchado. – plmcw

0

También encontré esto y terminé usando un tamaño de matriz fijo. Las matrices que estaba tratando de guardar eran de len variable, de modo que he creado otros nuevos desde el fijo con la longitud correcta

que hice algo en la línea de

def filled_list(src_list, targ_len): 
    """takes a varible len() list and creates a new one with a fixed len()""" 
    for i in range(targ_len): 
     try: 
      yield src_list[i] 
     except IndexError: 
      yield 0 

src_list = [1,2,3,4,5,6,7,8,9,10,11] 
new_list = [x for x in filled_list(src_list, 100)] 

que hizo el truco para mí.

9

Tengo una tarea similar: volcar datos de tamaño fijo con matrices de longitud variable.

Intenté por primera vez el uso de campos de tamaño fijo StringCol (64 * 1024) para almacenar mis datos de longitud variable (siempre son < 64K). Pero era bastante lento y desperdiciaba mucho espacio en disco, a pesar de la compresión blosc.

Después de días de investigación que terminó con la siguiente solución:

(alerón: almacenamos campos de matriz en casos eArray separados, uno eArray por un array de campo) tamaño

  1. almaceno fijo datos en una tabla de pytables regular.
  2. I añadido 2 campos adicionales a estas tablas: arrFieldName_Offset y arrFieldName_Length:

    class Particle(IsDescription): 
        idnumber = Int64Col() 
        ADCcount = UInt16Col() 
        TDCcount = UInt8Col() 
        grid_i = Int32Col() 
        grid_j = Int32Col() 
        pressure = Float32Col() 
        energy = FloatCol() 
        buffer_Offset = UInt32() # note this field! 
        buffer_Length = UInt32() # and this one too! 
    
  3. I también crean una instancia eArray por cada campo de matriz:

    datatype = StringAtom(1) 
    buffer = h5file.createEArray('/detector', 'arr', datatype, (0,), "") 
    
  4. Entonces agregar filas correspondientes a datos de tamaño fijo:

    row['idnumber'] = ... 
    ... 
    row['energy'] = ... 
    row['buffer_Offset'] = buffer.nrows 
    # my_buf is a string (I get it from a stream) 
    row['buffer_Length'] = len(my_buf) 
    table.append(row) 
    
  5. Ta-dah! Agregue el búfer a la matriz.

    buffer.append(np.ndarray((len(my_buf),), buffer=my_buf, dtype=datatype)) 
    
  6. Ese es el truco. En mis experimentos, este enfoque es 2-10 veces más rápido que almacenar matrices de tamaño fijo (como StringAtom (HUGE_NUMBER)) y el DB resultante es pocas veces más pequeño (2-5x)

  7. Obtener los datos del buffer es fácil. Supongamos que fila es una sola fila se lee de su base de datos:

    # Open array for reading 
    buffer = h5file.createEArray('/detector', 'Particle.buffer', datatype, (0,), "") 
    ... 
    row = ... 
    ... 
    bufferDataYouNeed = buffer[ row['buffer_Offset'] : row['buffer_Offset'] + row['buffer_Length']] 
    
Cuestiones relacionadas