用 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()
R 用 lubridate 在 DST 上添加月份会产生意想不到的结果