检查多维列表的一致性

时间:2018-11-04 22:47:53

标签: python list numpy multidimensional-array

在我的other question之后,我惊讶地发现Numpy在array_like对象的定义上非常宽松。基本上np.array(1)是形状为()且尺寸为0的有效numpy ndarray! np.array([[1,2],[3]])也是形状为(2,)且尺寸为1的有效ndarray。基本上np.array会挖掘尽可能多的尺寸,直到达到不均匀或零尺寸值为止。此实现可能非常快,但不一定安全。实际上,这很容易出错。如果有人忘记了输入列表中的一个元素,则该函数将不返回任何错误,从而导致代码中出现其他更容易混淆的错误。

我在考虑是否可以编写checkArr函数,以最小的开销检查多维列表的均匀性和均匀性。经过几次其他的SO搜集工作,我最终得到了这种递归解决方案:

def checkArr(A):
    assert isinstance(A, (list,tuple,range)), 
             "input must be iterable (list, tuple, range)"
    assert all(isinstance(a, type(A[0])) for a in A[1:]), 
             "elements of the input must of a the same type, input must be homogeneous"
    if isinstance(A[0], (list,tuple,range)):
        assert all(len(a)==len(A[0]) for a in A[1:]),
             "elements of the input must of a the same size, input must be uniform"
        [checkArr(a) for a in A]

现在我的问题是这是否是最快的解决方案,还是可能实现更高性能/ Python的实现?

2 个答案:

答案 0 :(得分:1)

在创建数组时指定dtype argument避免了从锯齿状矩阵无意中创建对象数组,而无需编写任何其他代码。

np.array([[1, 2], [3, 4]], dtype=int)  # okay
np.array([[1, 2], [3]], dtype=int)     # ValueError
np.array([[1, "b"]], dtype=int)        # ValueError

(关于最后一个,如果未设置数据类型,np.array([1, "b"])会自动将“ 1”转换为字符串。)

答案 1 :(得分:1)

Python所说的是,请求宽恕比允许许可容易。因此,如果您只调用np.array然后检查object dtype,则可能会减少开销。

您还需要注意的另一件事是何时引发错误。例如:

In [273]: np.array((np.zeros((2,3)), np.ones((2,4))))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-273-70f6273e3371> in <module>()
----> 1 np.array((np.zeros((2,3)), np.ones((2,4))))

ValueError: could not broadcast input array from shape (2,3) into shape (2)

如果不均匀性在第一维中,它将产生一个对象dtype数组,例如np.array((np.zeros((2,3)), np.ones((1,4))))。但是,当它处于更深层次时,似乎会分配结果数组,然后在将一个或多个组件数组复制到该数组时遇到问题。这是一个棘手的案例。

或考虑:

In [277]: np.array([[1,2,3],[4,5,'6']])
Out[277]: 
array([['1', '2', '3'],
       ['4', '5', '6']], dtype='<U21')

嵌套列表中的最后一个元素将强制字符串dtype。如果最后一个元素是其他PYthon对象,则我们可能是对象dtype:

In [279]: np.array([[1,2,3],[4,5,{}]])
Out[279]: 
array([[1, 2, 3],
       [4, 5, {}]], dtype=object)

但是如果对象是列表,我们会得到广播错误的变体:

In [280]: np.array([[1,2,3],[4,5,['6']]])
ValueError: setting an array element with a sequence

但是,如果您要先检查,np.stack可能是一个很好的模型。如果指定了数组或列表,则axis = 0时,其行为就像np.array