如何使用numpy数组numpy数组对象执行numpy函数?

时间:2018-02-18 15:14:14

标签: python arrays numpy

假设我们有一个用于创建numpy数组numpy数组的函数:

randarr = lambda shape: np.random.randint(0, 10, shape)
get_numpy_array_obj = lambda shapes: \
    np.array([randarr(shape) for shape in shapes])

以及数组的已定义大小:

shapes = [(2, 3), (3, 4), (4, 2)]

因为数组的形状不相同,所以numpy将其他数组视为对象。

现在,如果我们创建其中两个数组

A = get_numpy_array_obj(shapes)
B = get_numpy_array_obj(shapes)

进行+, - ,**等简单操作不是问题,例如:

C = A * B - (A + B)**2

当我想在像tanh,exp等这些数组上应用numpy函数时会出现问题。

D = np.tanh(A)

这会给我带来以下错误:

AttributeError: 'numpy.ndarray' object has no attribute 'tanh'

我可以像这样逐个在每个数组上应用该函数

D = np.array([np.tanh(a) for a in A])

我的想法是编写更少的代码并且更具可读性。

此外np.vectorize(np.tanh)(A)无效。这将返回:

ValueError: setting an array element with a sequence.

是否有其他可能的方法在numpy数组对象数组上应用numpy函数?

1 个答案:

答案 0 :(得分:2)

In [99]: arr = np.array([np.ones(ij) for ij in [(1,3),(2,4),(3,2)]])
In [100]: arr
Out[100]: 
array([array([[1., 1., 1.]]),
       array([[1., 1., 1., 1.],
       [1., 1., 1., 1.]]),
       array([[1., 1.],
       [1., 1.],
       [1., 1.]])], dtype=object)

运营商喜欢' +'因为数组具有相应的方法而起作用:

In [101]: arr[0].__add__
Out[101]: <method-wrapper '__add__' of numpy.ndarray object at 0xb64897a0>
In [102]: arr+arr
Out[102]: 
array([array([[2., 2., 2.]]),
       array([[2., 2., 2., 2.],
       [2., 2., 2., 2.]]),
       array([[2., 2.],
       [2., 2.],
       [2., 2.]])], dtype=object)

但像np.tanh这样的函数没有数组方法。

frompyfunc将数组的元素传递给函数并返回一个对象dtype数组。通常这很痛苦,但在这种情况下,它正是我们想要的:

In [103]: np.frompyfunc(np.tan,1,1)(arr)
Out[103]: 
array([array([[1.55740772, 1.55740772, 1.55740772]]),
       array([[1.55740772, 1.55740772, 1.55740772, 1.55740772],
       [1.55740772, 1.55740772, 1.55740772, 1.55740772]]),
       array([[1.55740772, 1.55740772],
       [1.55740772, 1.55740772],
       [1.55740772, 1.55740772]])], dtype=object)

vectorize也使用frompyfunc,但尝试将结果转换为数字数组。我们可以通过指定otypes

来跳过这一点
In [104]: np.vectorize(np.tan,otypes='O')(arr)
Out[104]: 
array([array([[1.55740772, 1.55740772, 1.55740772]]),
       array([[1.55740772, 1.55740772, 1.55740772, 1.55740772],
       [1.55740772, 1.55740772, 1.55740772, 1.55740772]]),
       array([[1.55740772, 1.55740772],
       [1.55740772, 1.55740772],
       [1.55740772, 1.55740772]])], dtype=object)

对象数组的迭代是在列表迭代和数值迭代之间的速度。它有一些数组开销,但不是全部。元素是指针,就像在列表中一样。

frompyfunc可以比显式迭代更快(最多2倍)。 vectorize有点慢,因为它有一些开销。这些功能的最大优点是它们可以处理广播。做自己的时间,看看他们是否有所帮助。