Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array elementwise operations

I have two input arrays x and y of the same shape. I need to run each of their elements with matching indices through a function, then store the result at those indices in a third array z. What is the most pythonic way to accomplish this? Right now I have four four loops - I'm sure there is an easier way.

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]]

I am getting confused since my function will only work on individual data pairs. I can't simply pass the x and y arrays to the function.

like image 210
user1764386 Avatar asked Nov 25 '12 23:11

user1764386


People also ask

Do operations on NumPy array?

Using Arithmetic Operators with NumpyYou can perform arithmetic operations on these arrays. For example, if you add the arrays, the arithmetic operator will work element-wise. The output will be an array of the same dimension. You can run an arithmetic operation on the array with a scalar value.

What is an element-wise operation?

An element-wise operation is an operation between two tensors that operates on corresponding elements within the respective tensors. An element-wise operation operates on corresponding elements between tensors. Two elements are said to be corresponding if the two elements occupy the same position within the tensor.

Can operations be carried out between scalars and arrays?

Operations between Arrays and ScalarsArrays are important because they enable you to express batch operations on data without writing any for loops. This is usually called vectorization. Any arithmetic operations between equal-size arrays applies the operation elementwise: In [45]: arr = np.


3 Answers

One "easier way" is to create a NumPy-aware function using numpy.vectorize. A "ufunc" is NumPy terminology for an elementwise function (see documentation here). Using numpy.vectorize lets you use your element-by-element function to create your own ufunc, which works the same way as other NumPy ufuncs (like standard addition, etc.): the ufunc will accept arrays and it will apply your function to each pair of elements, it will do array shape broadcasting just like standard NumPy functions, etc. The documentation page has some usage examples that might be helpful.

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])
like image 95
illya Avatar answered Oct 06 '22 13:10

illya


(I'm guessing your talking about simple python list, not numpy.array)

Recursion always making our life easier:

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)

Usage:

>>> 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]]

It will work in any other kind of dimensional array:

>>> operate_on_Narray([1, 2, 3], [4, 5, 6], lambda a, b: a*b)
[4, 10, 18]
like image 20
juliomalegria Avatar answered Oct 06 '22 13:10

juliomalegria


The following transcript from a python 2.7.3 interpreter session illustrates use of builtin function map to apply an elementwise operation to 2D-matrix elements. (Note: operator.add is equivalent to the elementwise_function specified in question, and also equivalent to the lambda expression in the second use of 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]]

Note, the above has x, y as follows:

x=[[2, 2, 1], [2, 2, 2], [3, 2, 2]]
y=[[3, 3, 1], [3, 2, 3], [3, 3, 3]]

As mentioned before, the transcript above is from a python 2.7.3 interpreter session. If this code is run in python 3, it will instead return map objects. One can use a function like the following to see the numbers:

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

With that function in place, the statement

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

returns

[[5, 5, 2], [5, 4, 5], [6, 5, 5]]
like image 3
James Waldby - jwpat7 Avatar answered Oct 06 '22 14:10

James Waldby - jwpat7