用 np.savez 存储字典会产生意想不到的结果?

Posted

技术标签:

【中文标题】用 np.savez 存储字典会产生意想不到的结果?【英文标题】:Storing a dict with np.savez gives unexpected result? 【发布时间】:2014-05-04 21:36:44 【问题描述】:

我可以使用 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 维数组中的字典,让我无法通过按键取回我的数据。还是我错过了什么?

所以我的问题是:

    这里发生了什么?如果我仍然可以通过密钥访问我的数据,该怎么做? 存储此类数据的最佳方式是什么? (以 str 为键,其他 dicts 为值的字典)

谢谢!

【问题讨论】:

【参考方案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)

而且数组中只有一项。该项目是 Python 字典!

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

您可以使用item() 方法检索该值(注意:这是不是 items() 用于字典的方法,也不是 NpzFile 固有的任何东西 类,但是是numpy.ndarray.item() method 将数组中的值复制到标准Python scalars。在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])

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])

【讨论】:

感谢 unutbu,这很清楚。尽管在脚本中以这种方式实际存储和恢复我的数据似乎过于复杂,但我仍然有兴趣了解您/其​​他人将如何存储这种类型的数据。也许是泡菜? 我认为首先要考虑的是你是否真的需要一个字典。这真的是最好的数据结构吗?一个缺点是它会破坏你的 numpy 数组。每当您想对每个数组执行操作时,小型或许多 NumPy 数组都需要 Python 循环。当您可以在一个大的 numpy 数组上执行 NumPy 操作时,您会从 NumPy 中获得更好的性能,因为这会将更多的工作推到快速的底层 C/Fortran 函数中,而将更少的工作推到相对较慢的 Python 循环中。 您可能想要调查Pandas DataFrames,而不是。您可以使用具有多索引的 DataFrame 来替换两级 dict 键。您可以将 DataFrame 存储为 hdf5 等高性能压缩格式。 由于 Pandas 是在 NumPy 之上构建的,因此如果将所有数据都放在一个大 DataFrame 中,它的性能也会最佳。由于您的数组大小不同,您可以将一维数组加载到列中,使用 NaN 表示缺失或不存在的数据。如果一维数组的大小大致相同,那么这只会浪费一点内存,并且可能会为您提供更好的性能、更方便的语法以及将整个数据集存储为一个 DataFrame 的能力。 @zhermes:如果你追踪source code,你会发现_savez calls np.asanyarray(val) 所以,当val 是一个字典时,_savez 将它转换为一个数组。例如,np.asanyarray('a':'b')array('a': 'b', dtype=object)【参考方案2】:

基于此答案:recover dict from 0-d numpy array

之后

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']

不使用关键字参数也可以,但我认为这也值得分享。

【讨论】:

以上是关于用 np.savez 存储字典会产生意想不到的结果?的主要内容,如果未能解决你的问题,请参考以下文章

numpy如何保存(存储)和读取数据?(.npy/.npz)np.save() np.savez() np.savetxt()

Numpy savez 异常

R 用 lubridate 在 DST 上添加月份会产生意想不到的结果

模拟单元测试的 Vuex getter 会产生意想不到的结果

用perl替换正则表达式EOL会产生意想不到的结果

流星空格键:#each 内的 #if 会产生意想不到的结果