Creando una referencia al conjunto de datos HDF en H5py usando astype

De los documentos h5py , veo que puedo lanzar un conjunto de datos HDF como otro tipo utilizando el método astype para los conjuntos de datos. Esto devuelve un administrador de contexto que realiza la conversión sobre la marcha.

Sin embargo, me gustaría leer un conjunto de datos almacenado como uint16 y luego convertirlo en el tipo float32 . A partir de entonces, me gustaría extraer varios segmentos de este conjunto de datos en una función diferente como el tipo de float32 . La documentación explica el uso como

 with dataset.astype('float32'): castdata = dataset[:] 

Esto haría que todo el conjunto de datos se leyera y se convirtiera a float32 , que no es lo que quiero. Me gustaría tener una referencia al conjunto de datos, pero emitido como un float32 equivalente a numpy.astype . ¿Cómo creo una referencia al objeto .astype('float32') para poder pasarlo a otra función para su uso?

Un ejemplo:

 import h5py as HDF import numpy as np intdata = (100*np.random.random(10)).astype('uint16') # create the HDF dataset def get_dataset_as_float(): hf = HDF.File('data.h5', 'w') d = hf.create_dataset('data', data=intdata) print(d.dtype) # uint16 with d.astype('float32'): # This won't work since the context expires. Returns a uint16 dataset reference return d # this works but causes the entire dataset to be read & converted # with d.astype('float32'): # return d[:] 

Además, parece que el contexto astype solo se aplica cuando se accede a los elementos de datos. Esto significa que

 def use_data(): d = get_data_as_float() # this is a uint16 dataset # try to use it as a float32 with d.astype('float32'): print(np.max(d)) # --> output is uint16 print(np.max(d[:])) # --> output is float32, but entire data is loaded 

Entonces, ¿no hay una forma numpy de usar astype?

d.astype() devuelve un objeto AstypeContext . Si mira la fuente de AstypeContext , tendrá una mejor idea de lo que está pasando:

 class AstypeContext(object): def __init__(self, dset, dtype): self._dset = dset self._dtype = numpy.dtype(dtype) def __enter__(self): self._dset._local.astype = self._dtype def __exit__(self, *args): self._dset._local.astype = None 

Cuando ingresa el AstypeContext , el atributo ._local.astype de su conjunto de datos se actualiza al nuevo tipo deseado, y cuando sale del contexto, vuelve a su valor original.

Por lo tanto, puede obtener más o menos el comportamiento que está buscando de esta manera:

 def get_dataset_as_type(d, dtype='float32'): # creates a new Dataset instance that points to the same HDF5 identifier d_new = HDF.Dataset(d.id) # set the ._local.astype attribute to the desired output type d_new._local.astype = np.dtype(dtype) return d_new 

Cuando ahora leas desde d_new , obtendrás arrays float32 numpy en lugar de uint16 :

 d = hf.create_dataset('data', data=intdata) d_new = get_dataset_as_type(d, dtype='float32') print(d[:]) # array([81, 65, 33, 22, 67, 57, 94, 63, 89, 68], dtype=uint16) print(d_new[:]) # array([ 81., 65., 33., 22., 67., 57., 94., 63., 89., 68.], dtype=float32) print(d.dtype, d_new.dtype) # uint16, uint16 

Tenga en cuenta que esto no actualiza el atributo d_new de d_new (que parece ser inmutable). Si también desea cambiar el atributo dtype , probablemente necesite subclase h5py.Dataset para hacerlo.

Los documentos de astype parecen implicar que leer todo en una nueva ubicación es su propósito. Por lo tanto, su return d[:] es lo más razonable si va a reutilizar el casting flotante con muchas funciones en ocasiones separadas.

Si sabe para qué necesita el casting y solo lo necesita una vez, puede cambiar las cosas y hacer algo como:

 def get_dataset_as_float(intdata, *funcs): with HDF.File('data.h5', 'w') as hf: d = hf.create_dataset('data', data=intdata) with d.astype('float32'): d2 = d[...] return tuple(f(d2) for f in funcs) 

En cualquier caso, desea asegurarse de que hf esté cerrado antes de abandonar la función o, de lo contrario, tendrá problemas más adelante.

En general, sugeriría separar la conversión y la carga / creación del conjunto de datos por completo y pasar el conjunto de datos como uno de los parámetros de la función.

Arriba se puede llamar de la siguiente manera:

 In [16]: get_dataset_as_float(intdata, np.min, np.max, np.mean) Out[16]: (9.0, 87.0, 42.299999)