输入/输出验证/铸造numpy计算

时间:2014-12-07 12:27:43

标签: python arrays numpy input-sanitization

这种情况在我的代码中经常发生。假设我有一个函数do_sth(a,b),只是为了这个例子,只需计算a+ba,b或者1D numpy数组或标量。在许多情况下,我需要函数来广播操作,因此如果a,b都是1D数组,则结果将是2D数组。我的意思的一个例子如下:

do_sth(1,2) -> 3
do_sth([1,2],0) -> array([1, 2])
do_sth(0,[3,4]) -> array([3, 4])
do_sth([1,2],[3,4]) -> array([[4, 5], [5, 6]])

这有点类似于n ufunc的行为。可能的实现如下:

from numpy import newaxis, atleast_1d

def do_sth(a, b):
    "a,b should be either 1d numpy arrays or scalars"
    a, b = map(atleast_1d, [a, b])
    # the line below mocks a more complicated calculation
    res = a[:, newaxis] + b[newaxis]

    conds = [a.size == 1, b.size == 1]

    if all(conds):
        return res[0, 0]
    elif any(conds):
        return res.ravel()
    else:
        return res

正如您所看到的,有很多样板。第一个问题是:这是进行此输入/输出转换的正确方法吗?有没有理由不使用装饰器来处理这样的情况?有没有关于此事的指导原则?

此外,如果ab是具有2D,3D形状的numpy数组,则通过添加模拟的更复杂的计算通常会严重失败。我说计算失败的意义不明显,或者可能在代码的不同版本中随时间变化,并且很难看出错误和输入形状错误之间的联系。我认为不建议将复杂的计算放在try/except块中(在python EAFP之后)。在这种情况下,检查函数开头的2个数组的形状是否正确?还有其他选择吗?是否有一个numpy函数允许同时将输入转换为numpy数组,并检查输入是否与一定数量的维度兼容,如asarray_withdim(arr,ndim=5)

1 个答案:

答案 0 :(得分:1)

关于装饰器的使用 - 我在numpy代码中没有看到很多装饰器的使用,但我认为这是因为大多数功能是在装饰器在Python中变得普遍之前开发的。如果你可以使它工作,不应该有任何缺点(但我不是装饰者或ufunc的专家。)

非编译的numpy函数通常有很多代码可以将输入按摩到方便的维度。然后他们做核心动作,然后进行最终重塑和打包。他们可能会使用像np.atleast_2d这样的函数来确保有足够的尺寸,并使用.reshape(-1,1,1)来压缩多余的尺寸。

np.tensordot是一个在输入上执行轴转置和重新整形的示例,因此它可以应用已编译的np.dotnp.insert从一系列ndimisinstance测试开始。特殊情况要尽早处理,而一般情况则留到最后。编译了np.einsum,但是在最终创建nditer对象并进行计算之前,在C代码中进行了大量的预处理。