数组逐元素操作

20

我有两个形状相同的输入数组x和y。 我需要将它们每个元素与匹配的索引一起通过函数运行,然后将结果存储在第三个数组z的这些索引处。 实现这一目标最符合Python风格的方法是什么? 我现在有四个循环 - 我相信有更简单的方法。

x = [[2, 2, 2],
     [2, 2, 2],
     [2, 2, 2]]

y = [[3, 3, 3],
     [3, 3, 3],
     [3, 3, 1]]

def elementwise_function(element_1,element_2):
    return (element_1 + element_2)

z = [[5, 5, 5],
     [5, 5, 5],
     [5, 5, 3]]

我感到困惑,因为我的函数只能处理单个数据对,不能直接将x和y数组传递给函数。


2
NumPy数组默认按元素进行操作。也就是说,x+y=z。 - user1767344
1
你能否在矩阵层面上进行操作呢?例如,z = x + y 在你上面的例子中可以工作。也许你可以展示一下你的函数,我们可以帮助你在矩阵上使其正常工作? - mathematical.coffee
3个回答

27

创建一个NumPy感知函数是一种“更简单的方法”,可以使用numpy.vectorize。 "ufunc"是NumPy术语,用于表示逐元素函数(请参见此处的文档)。使用numpy.vectorize让你能够使用你的逐元素函数来创建自己的ufunc,这与其他NumPy ufuncs(如标准加法等)的工作方式相同:ufunc将接受数组,并将你的函数应用于每对元素,它将执行类似于标准NumPy函数的数组形状广播等操作。 文档页面中有一些有用的用例示例。

In [1]: import numpy as np
   ...: def myfunc(a, b):
   ...:     "Return 1 if a>b, otherwise return 0"
   ...:     if a > b:
   ...:         return 1
   ...:     else:
   ...:         return 0
   ...: vfunc = np.vectorize(myfunc)
   ...: 

In [2]: vfunc([1, 2, 3, 4], [4, 3, 2, 1])
   ...: 
Out[2]: array([0, 0, 1, 1])
In [3]: vfunc([1, 2, 3, 4], 2)
   ...: 
Out[3]: array([0, 0, 1, 1])

4
(我猜你说的是简单的Python列表,而不是numpy.array)
递归总是让我们的生活更轻松:
def operate_on_Narray(A, B, function):
    try:
        return [operate_on_Narray(a, b, function) for a, b in zip(A, B)]
    except TypeError as e:
        # Not iterable
        return function(A, B)

使用方法:

>>> x = [[2, 2, 2],
...      [2, 2, 2],
...      [2, 2, 2]]
>>> 
>>> y = [[3, 3, 3],
...      [3, 3, 3],
...      [3, 3, 1]]
>>> operate_on_Narray(x, y, lambda a, b: a+b)
[[5, 5, 5], [5, 5, 5], [5, 5, 3]]

它将适用于任何其他类型的多维数组:

>>> operate_on_Narray([1, 2, 3], [4, 5, 6], lambda a, b: a*b)
[4, 10, 18]

3
以下是一个来自Python 2.7.3解释器会话的文字记录,展示了使用内置函数map对2D矩阵元素进行逐元素操作的过程。 (注意:operator.add等同于问题中指定的elementwise_function,也等同于第二次使用applier的lambda表达式。)
>>> import operator
>>> def applier(a, b, op):
...     return map(lambda ro: map(op, ro[0], ro[1]), zip(a,b))
... 
>>> applier(x, y, operator.add)
[[5, 5, 2], [5, 4, 5], [6, 5, 5]]
>>> x; y
[[2, 2, 1], [2, 2, 2], [3, 2, 2]]
[[3, 3, 1], [3, 2, 3], [3, 3, 3]]
>>> applier(x, y, lambda p,q: p+q)
[[5, 5, 2], [5, 4, 5], [6, 5, 5]]
>>> applier(x, y, lambda p,q: p-q)
[[-1, -1, 0], [-1, 0, -1], [0, -1, -1]]
>>> applier(x, y, lambda p,q: p*q)
[[6, 6, 1], [6, 4, 6], [9, 6, 6]]

请注意,上述内容的x和y如下:
x=[[2, 2, 1], [2, 2, 2], [3, 2, 2]]
y=[[3, 3, 1], [3, 2, 3], [3, 3, 3]]

如前所述,上面的转录是从Python 2.7.3解释器会话中得出的。如果在Python 3中运行此代码,则会返回map对象。可以使用以下函数查看数字:

def itemize(m):
    return [itemize(e) for e in m] if hasattr(m, '__iter__') else m

有了这个函数,语句变成:

itemize(applier(x, y, operator.add))

返回值

[[5, 5, 2], [5, 4, 5], [6, 5, 5]]

该方法返回 "<map object at 0x10eebc438>"。 - Our
@onurcanbektas,这是Python 3与2之间的后果。请参见编辑获取更多信息,并当然点赞该编辑! - James Waldby - jwpat7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接