【问题标题】:Why numpy can save and load objects different than numpy arrays为什么 numpy 可以保存和加载与 numpy 数组不同的对象
【发布时间】:2018-06-13 18:22:27
【问题描述】:

我试图提出另一点,但不小心使用 numpy np.save() 保存了 dict。令我惊讶的是,这种方法似乎完全没有问题。我用另一个对象尝试了上述方法,它不是np.array,就像list,它似乎工作正常。

例如下面的代码,使用np.save()np.load()保存和加载一个对象:

list_file = 'random_list.npy'
random_list = [x*2 for x in range(20)]
np.save(list_file, random_list)

# load numpy array
random_list2 = np.load(list_file)
set(random_list) == set(random_list2)

是的

所以,我的问题是:

  1. 既然在documentation 中只提到了数组,为什么还是会成功?
  2. 同样,如果要处理其他对象,可以处理哪些对象?

我知道泡菜有一些限制,可能会影响可以处理的对象的性质,但仍然存在很多不清楚的地方。

编辑:
我认为np.save() 只是试图将作为参数传递的对象转换为 numpy 数组,但这在某些情况下没有任何意义,例如dict

例如,传递给 np.array 的 dict 似乎根本不起作用:

a = {1: 0, 2: 1, 3: 2}
b = np.array(a)
type(b)

numpy.ndarray

b.shape

()

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    numpy.save() 将其参数记录为 "array-like"。

    根据numpy: formal definition of "array_like" objects?,底层numpy/core/src/multiarray/ctors.c:PyArray_FromAny() 接受:

    /* op is an array */
    
    /* op is a NumPy scalar */
    
    /* op is a Python scalar */
    
    /* op supports the PEP 3118 buffer interface */
    
    /* op supports the __array_struct__ or __array_interface__ interface */
    
    /* op supplies the __array__ function. */
    
    /* Try to treat op as a list of lists */
    

    专门针对dict,执行路径如下:

    numpy/npyio.py -> numpy/core/numeric.py:asanyarray() -> numpy/core/src/multiarray/multiarraymodule.c:_array_fromobject() -> numpy/core/src/multiarray/ctors.c:PyArray_CheckFromAny() -> 上述PyArray_FromAny。那里:

    <...>
    PyArray_GetArrayParamsFromObject(op, newtype,
                            0, &dtype,
                            &ndim, dims, &arr, context)
    <...>
            else {
                if (newtype == NULL) {
                    newtype = dtype;    #object dtype
    <...>
                ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, newtype,
                                             ndim, dims,
                                             NULL, NULL,
                                             flags&NPY_ARRAY_F_CONTIGUOUS, NULL);
        return (PyObject *)ret;
    

    【讨论】:

    • 特别是调用函数np.asanyarray将参数转换为NumPy对象。对于dicts,它只会产生一个数据类型为object的NumPy标量。
    • A dict 似乎不是“类数组”,但在这种情况下,numpy 已成功使用它。
    【解决方案2】:

    一个演示:

    In [507]: np.savez('test', a = [x*2 for x in range(3)], b=dict(a=1,b=np.arange(3)))
    
    In [510]: d = np.load('test.npz')
    In [511]: d['a']
    Out[511]: array([0, 2, 4])
    

    此列表已转换为数组并保存。

    In [512]: d['b']
    Out[512]: array({'a': 1, 'b': array([0, 1, 2])}, dtype=object)
    In [513]: d['b'].shape
    Out[513]: ()
    In [514]: d['b'].item()   # or d['b'][()]
    Out[514]: {'a': 1, 'b': array([0, 1, 2])}
    

    字典被包装在一个 0d 对象 dtype 数组中,并以pickle 保存。字典中的数组是pickledsave

    np.save 在需要处理非数组对象的地方使用pickle,pickle 使用save 处理数组对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-06
      • 2012-09-24
      • 1970-01-01
      • 2019-07-24
      • 2015-07-31
      • 1970-01-01
      • 2010-12-14
      • 2022-01-26
      相关资源
      最近更新 更多