hdf5 h5py строки в Python 3: правильный способ установки или кодирования кортежа с помощью (float, string) атрибутов - PullRequest
0 голосов
/ 23 сентября 2019

Я понимаю, что обработка строк в hdf5 кажется сложной задачей - я ищу правильный способ установки атрибутов для набора данных, в котором значение атрибута имеет форму кортежа (float / number / numpyarray, string).

Кроме того, мне нужно, чтобы оно было таким же при чтении обратно как введено, так как я затем сравниваю атрибуты набора данных с упорядоченным словарем требуемых атрибутов.

Каков правильный способ справиться с этим?

До сих пор я устанавливал атрибуты, используя

    def setallattributes(dataset, dictattributes):
        for key, value in dictattributes.items():
            tup0 = value[0]
            tup1 = value[1].encode('utf-8')
            value = (tup0, tup1)
            dataset.attrs[key] = value

, и я пытаюсь проверить соответствие атрибутов нужным атрибутам, используя

    for datasetname in list(group.keys()):
            dataset = f[datasetname]
            if dataset.size != 0:
                saved_attributes = dataset.attrs.items() #Get (name, value) tuples for all attributes attached to this object. On Py3, it’s a collection or set-like object.
                if dict(saved_attributes) == input_attributes: #check attributes match -- both dicts, one ordered one not
                    datasetnamelist.append(datasetname)

В настоящее время это приводит кпытаясь сравнить такие вещи, как

{'Rmax': array([b'200.0', b'ld'], dtype='|S32'), 'fracinc': array([b'0.5', b'$\\pi$'], dtype='|S32')} == OrderedDict([('Rmin', (0, 'ld')), ('Rmax',(1, 'ld')), ('fracinc',(0.5, r'$\pi$'))])

, который возвращает False.

Ответы [ 2 ]

0 голосов
/ 23 сентября 2019

Я угадал ваше словарное определение и воссоздал ваш процесс как мог.Когда вы сохраняете свой словарь с кортежами, значения сохраняются (и извлекаются) как строковый массив (отраженный в dtype в ваших выходных данных выше).

Вам придется деконструировать массив и конвертировать каждый элемент, чтобы он соответствовал исходным данным.Таким образом, этот процесс будет специфичным для сохраненных типов данных - я не думаю, что возможно иметь универсальный метод для извлечения и тестирования кортежей, преобразованных в строковые массивы.

Решение:

import h5py

def setallattributes(dataset, dictattributes):
    for key, value in dictattributes.items():
        tup0 = value[0]
        tup1 = value[1].encode('utf-8')
        value = (tup0, tup1)
        dataset.attrs[key] = value

with h5py.File('SO_58064282.h5', 'w') as h5f:   

    ds = h5f['/']
    input_attributes =  { 'Rmin': (0, 'ld'), 
    'Rmax': (1, 'ld'), 'fracinc': (0.5, r'$\pi$') }
    print ('Input:\n:',input_attributes)
    setallattributes (ds, input_attributes)

    saved_attributes = ds.attrs.items() 
    saved_attrs_dict = {}
    print ('Saved Attributes:')
    for item in saved_attributes:
        print (item)
        saved_attrs_dict.update( {item[0] : 
                     (float(item[1][0]), item[1][1].decode('utf-8')) })

    print ('Converted to Dict:\n:',dict(saved_attrs_dict))
    if saved_attrs_dict == input_attributes: 
    #check attributes match -- both dicts, one ordered one not
        print ('Saved = Input')
    else:
        print ('mismatched dictionaries')

    print ('Done')   
0 голосов
/ 23 сентября 2019

http://docs.h5py.org/en/stable/high/attr.html

They may be created from any scalar or NumPy array

data – Value of the attribute; will be put through numpy.array(data)

Создание массива из вашего кортежа:

In [115]: np.array((0, 'ld'))                                                   
Out[115]: array(['0', 'ld'], dtype='<U21')
In [116]: np.array((0, b'ld'))                  # for bytestring                                
Out[116]: array([b'0', b'ld'], dtype='|S21')    

Получить атрибут как кортеж смешанного типа будет непросто.

Создание структурированногомассив (составной dtype) может работать:

In [122]: np.array((0, 'ld'), dtype='i,S10')                                    
Out[122]: array((0, b'ld'), dtype=[('f0', '<i4'), ('f1', 'S10')])
In [123]: print(_)                                                              
(0, b'ld')
In [124]: __.tolist()                                                                   
Out[124]: (0, b'ld')

Сохранение словаря в группу:

In [126]: dd = dict([('Rmin', (0, 'ld')), ('Rmax',(1, 'ld')), ('fracinc',(0.5, r'$\pi$'))])     
In [131]: f = h5py.File('attrs.h5','w')                                         
In [132]: g = f.create_group('group')    
In [137]: for key in dd: 
     ...:     value = list(dd[key]) 
     ...:     value[1] = value[1].encode('utf-8') 
     ...:     value = np.array(tuple(value), dtype='int,S10') 
     ...:     g.attrs[key] = value 
     ...:                                                                       
In [138]: g.attrs                                                               
Out[138]: <Attributes of HDF5 object at 140472104481960>
In [139]: list(g.attrs.items())                                                 
Out[139]: [('Rmin', (0, b'ld')), ('Rmax', (1, b'ld')), ('fracinc', (0, b'$\\pi$'))]
In [140]: g.attrs['fracinc']                                                    
Out[140]: (0, b'$\\pi$')

Отображается как кортеж, но на самом деле это просто numy void.Нам нужно tolist() или item(), чтобы получить кортеж, который можно сравнить с другим кортежем:

In [142]: g.attrs['Rmin'].tolist()==(0,b'ld')                                   
Out[142]: True

Для сравнения с dd['Rmin'] потребуется преобразовать одно строковое значение в / из строки байтов.

In [146]: def foo(value): 
     ...:     value = list(value) 
     ...:     value[1] = value[1].encode('utf-8') 
     ...:     return tuple(value) 
     ...:                                                                       
In [147]: dd1 = {key:foo(value) for key,value in dd.items()}                    
In [148]: dd1                                                                   
Out[148]: {'Rmin': (0, b'ld'), 'Rmax': (1, b'ld'), 'fracinc': (0.5, b'$\\pi$')}
In [149]: g.attrs['Rmin'].tolist()==dd1['Rmin']                                 
Out[149]: True

Это не соответствует dd1, потому что я сохранил его с полем int (у 'fracint' есть число с плавающей точкой):

In [155]: {key:value.item() for key,value in g.attrs.items()}                   
Out[155]: {'Rmin': (0, b'ld'), 'Rmax': (1, b'ld'), 'fracinc': (0, b'$\\pi$')}

Если я изменю foo наint(value[0]) словари совпадают.

Так что если вам нужно выполнить такой тип сопоставления, вам нужно пройти тестовый пример через тот же тип обработки, который вы (и h5py) выполняете для сохраненного значения.

...