Сохранение dict с np.savez дает неожиданный результат?

Могу ли я хранить словарь с помощью np.savez? Результаты удивляют (по крайней мере, для меня), и я не могу найти способ вернуть мои данные по ключевым словам.

In [1]: a = {'0': {'A': array([1,2,3]), 'B': array([4,5,6])}}
In [2]: a
Out[2]: {'0': {'A': array([1, 2, 3]), 'B': array([4, 5, 6])}}

In [3]: np.savez('model.npz', **a)
In [4]: a = np.load('model.npz')
In [5]: a
Out[5]: <numpy.lib.npyio.NpzFile at 0x7fc9f8acaad0>

In [6]: a['0']
Out[6]: array({'B': array([4, 5, 6]), 'A': array([1, 2, 3])}, dtype=object)

In [7]: a['0']['B']
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-16-c916b98771c9> in <module>()
----> 1 a['0']['B']

ValueError: field named B not found

In [8]: dict(a['0'])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-17-d06b11e8a048> in <module>()
----> 1 dict(a['0'])

TypeError: iteration over a 0-d array

Я точно не понимаю, что происходит. Похоже, что мои данные становятся словарем внутри 0-мерного массива, и я не могу вернуть мои данные заново. Или я чего-то не хватает?

Поэтому мои вопросы:

  1. Что здесь происходит? Если я могу получить доступ к моим данным по ключам, как?
  2. Каков наилучший способ хранения данных этого типа? (a dict с str как ключ, а другой - как значение)

Благодарю!

Ответы

Ответ 1

Можно восстановить данные:

In [41]: a = {'0': {'A': array([1,2,3]), 'B': array([4,5,6])}}

In [42]: np.savez('/tmp/model.npz', **a)

In [43]: a = np.load('/tmp/model.npz')

Обратите внимание, что dtype является "объектом".

In [44]: a['0']
Out[44]: array({'A': array([1, 2, 3]), 'B': array([4, 5, 6])}, dtype=object)

И в массиве есть только один элемент. Этот элемент является питоном-питомцем!

In [45]: a['0'].size
Out[45]: 1

Вы можете получить значение с помощью метода item() (NB: это не метод items() для словарей, ни что-либо, что является неотъемлемой NpzFile класса NpzFile, но является numpy.ndarray.item() который копирует значение в массив в стандартные скаляры Python. В массиве object dtype любое значение, хранящееся в ячейке массива (даже словаря), является скаляром Python:

In [46]: a['0'].item()
Out[46]: {'A': array([1, 2, 3]), 'B': array([4, 5, 6])}

In [47]: a['0'].item()['A']
Out[47]: array([1, 2, 3])

In [48]: a['0'].item()['B']
Out[48]: array([4, 5, 6])

Чтобы восстановить как Dict из dicts: a

In [84]: a = np.load('/tmp/model.npz')

In [85]: a = {key:a[key].item() for key in a}

In [86]: a['0']['A']
Out[86]: array([1, 2, 3])

Ответ 2

На основе этого ответа: восстановить dict из массива 0-d numpy

После

a = {'key': 'val'}
scipy.savez('file.npz', a=a) # note the use of a keyword for ease later

вы можете использовать

get = scipy.load('file.npz')
a = get['a'][()] # this is crazy maybe, but true
print a['key']

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