如何以优雅高效的方式将python callable映射到numpy数组?

abu*_*kaj 5 python numpy python-2.7 python-3.x

规范方法(使用np.vectorize())在空数组的情况下不起作用 - 它以以下结尾IndexError: index 0 is out of bounds for axis 0 with size 0:

>>> def f(x):
...     return x + 1
...
>>> F = np.vectorize(f)
>>> F(np.array([]))
[Traceback removed]
IndexError: index 0 is out of bounds for axis 0 with size 0
Run Code Online (Sandbox Code Playgroud)

目前我使用

>>> np.array([f(x) for x in X])
Run Code Online (Sandbox Code Playgroud)

但我正在寻找更优雅的解决方案(和高效).在Python 2中,我可以选择

>>> np.array(map(f, X))
Run Code Online (Sandbox Code Playgroud)

但它在Python 3中失败了.

[编辑]

问题在NumPy阵列的每个单元的函数的有效评估中没有答案,因为:

  • vectorise 失败,
  • OP要求的解决方案正常运作:A(i, j) := f(A(i, j)).

hpa*_*ulj 7

np.vectorize应该与f期望标量的 一起使用。但是,它确实有一个空输入的问题:

In [364]: def f(x):
     ...:     return 2*x
     ...: 
In [365]: fv = np.vectorize(f)
In [366]: fv(np.array([1,2,3]))
Out[366]: array([2, 4, 6])
In [367]: fv(np.array([]))
....
ValueError: cannot call `vectorize` on size 0 inputs unless `otypes` is set
Run Code Online (Sandbox Code Playgroud)

我的错误与你的不同,但也许这是一个版本问题。 vectorize, 无需otypes进行测试计算以确定返回类型。如果输入为空,则会出现问题。解决方法是指定otypes.

In [368]: fv1 = np.vectorize(f, otypes=[int])
In [369]: fv1(np.array([]))
Out[369]: array([], dtype=int32)
Run Code Online (Sandbox Code Playgroud)

vectorize用途np.frompyfunc; 主要区别在于frompyfunc返回一个对象数组。两者都有一个很大的优势,那就是他们负责广播。输入可以是任何形状和维度的数组。更好的是,它们可以处理多个输入,相互广播。但vectorize警告说它仍然是迭代的,所以不承诺任何速度改进。

阅读链接问题中已接受答案的评论。

但是如果数组(或列表)总是一维的,你就不需要额外的权力。一个简单的 Python 迭代和任何东西一样好。它可能是map(或list(map在 py3 中),但我更喜欢列表理解的清晰度。

ret = [f(x) for x in X]  # works with list or array
np.array(ret)    # if you want an array 
Run Code Online (Sandbox Code Playgroud)

需要注意的一件事是type各种迭代方法产生的元素

数组上的迭代产生数组元素,或 numpy dtypes:

In [387]: [type(x) for x in np.arange(3)]
Out[387]: [numpy.int32, numpy.int32, numpy.int32]
Run Code Online (Sandbox Code Playgroud)

列表上的迭代返回元素,无论它们是什么:

In [388]: [type(x) for x in [1,2,3]]
Out[388]: [int, int, int]
Run Code Online (Sandbox Code Playgroud)

迭代frompyfunc产生“标量”

In [389]: ff=np.frompyfunc(type,1,1)
In [390]: ff(np.arange(3))
Out[390]: array([<class 'int'>, <class 'int'>, <class 'int'>], dtype=object)
In [391]: ff([1,2,3])
Out[391]: array([<class 'int'>, <class 'int'>, <class 'int'>], dtype=object)
In [393]: list(map(type,np.arange(3)))
Out[393]: [numpy.int32, numpy.int32, numpy.int32]
Run Code Online (Sandbox Code Playgroud)

vectorize解析的部分otypes是:

    if isinstance(otypes, str):
        for char in otypes:
            if char not in typecodes['All']:
                raise ValueError("Invalid otype specified: %s" % (char,))
    elif iterable(otypes):
        otypes = ''.join([_nx.dtype(x).char for x in otypes])
    elif otypes is not None:
        raise ValueError("Invalid otype specification")
    self.otypes = otypes
Run Code Online (Sandbox Code Playgroud)

In [423]: np.typecodes['All']
Out[423]: '?bhilqpBHILQPefdgFDGSUVOMm'
Run Code Online (Sandbox Code Playgroud)