【问题标题】:Storing a dict with np.savez gives unexpected result?用 np.savez 存储字典会产生意想不到的结果?
【发布时间】: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 维数组中的字典,让我无法通过按键取回我的数据。还是我错过了什么?

所以我的问题是:

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

谢谢!

【问题讨论】:

    标签: python arrays numpy dictionary save


    【解决方案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']
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-05
      • 1970-01-01
      • 2023-01-18
      • 2017-03-19
      • 2021-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多