17

我有两个相同形状的输入数组 x 和 y。我需要通过函数运行具有匹配索引的每个元素,然后将结果存储在第三个数组 z 中的这些索引处。完成此任务的最蟒蛇方式是什么?现在我有四个四个循环 - 我确信有一个更简单的方法。

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 数组传递给函数。

4

3 回答 3

21

一种“更简单的方法”是使用numpy.vectorize. “ufunc”是元素函数的 NumPy 术语(请参阅此处的文档)。Usingnumpy.vectorize允许您使用逐个元素的函数来创建自己的 ufunc,其工作方式与其他 NumPy ufunc(如标准添加等)相同: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])
于 2012-11-25T23:45:10.353 回答
4

(我猜你在谈论简单的python list,而不是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]
于 2012-11-25T23:48:54.530 回答
3

以下来自 python 2.7.3 解释器会话的记录说明了使用内置函数map将元素操作应用于 2D 矩阵元素。(注:operator.add等同于elementwise_function指定的问题,也等同于第二次使用中的lambda表达式applier。)

>>> 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 中运行,它将改为返回地图对象。可以使用如下函数来查看数字:

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]]
于 2012-11-26T00:02:08.240 回答