4

Haven't been able to find any information on this. If I have two m x n matrices of identical dimension, is there a way to apply an element-wise function in numpty on them? To illustrate my meaning:

Custom function is F(x,y)

First Matrix:

array([[ a, b],
       [ c, d],
       [ e, f]])

Second Matrix:

array([[ g, h],
       [ i, j],
       [ k, l]])

Is there a way to use the above two matrices in numpy to get the desired output below

array([[ F(a,g), F(b,h)],
       [ F(c,i), F(d,j)],
       [ F(e,k), F(f,l)]])

I know I could just do nested for statements, but I'm thinking there may be a cleaner way

cyclobster
  • 419
  • 3
  • 12
  • 1
    Does this answer your question? [How to get element-wise matrix multiplication (Hadamard product) in numpy?](https://stackoverflow.com/questions/40034993/how-to-get-element-wise-matrix-multiplication-hadamard-product-in-numpy) – pink spikyhairman May 19 '20 at 20:13
  • `numpy.meshgrid()` combines your matrices element-wise, but i don't know about the function call part. for common mathematical functions, numpy provides clones which operate element-wise – Aemyl May 19 '20 at 20:15
  • 2
    As long as `F` only accepts scalar `x,y` values there isn't much else that you can do. It has to be evaluated once for each element of the output. `loops`, `map`, `vectorize`, `frompyfunc` all do that in one way of other. – hpaulj May 19 '20 at 20:37
  • What you really need to do is learn enough `numpy` so you can rewrite `F` to use the two matrices directly. That's the true numpy `vectorization`. Look for example how `numpy` does elementwise addition, multiplication, or any of the many `ufunc`. Those are tools you should be using! – hpaulj May 19 '20 at 20:40
  • Could you please post your F function so we can help better? And how big is your matrix? – Ehsan May 19 '20 at 22:44
  • This post pretty much answers your question and compares all possible approaches: https://stackoverflow.com/questions/35215161/most-efficient-way-to-map-function-over-numpy-array – Ehsan May 19 '20 at 22:51

2 Answers2

5

For a general function F(x,y), you can do:

out = [F(x,y) for x,y in zip(arr1.ravel(), arr2.ravel())]
out = np.array(out).reshape(arr1.shape)

However, if possible, I would recommend rewriting F(x,y) in such a way that it can be vectorized:

# non vectorized F
def F(x,y):
    return math.sin(x) + math.sin(y)

# vectorized F
def Fv(x,y):
    return np.sin(x) + np.sin(y)

# this would fail - need to go the route above
out = F(arr1, arr2)

# this would work
out = Fv(arr1, arr2)
Quang Hoang
  • 146,074
  • 10
  • 56
  • 74
2

You can use numpy.vectorize function:

import numpy as np

a = np.array([[ 'a', 'b'],
       [ 'c', 'd'],
       [ 'e', 'f']])

b = np.array([[ 'g', 'h'],
       [ 'i', 'j'],
       [ 'k', 'l']])

def F(x,y):
    return x+y

F_vectorized = np.vectorize(F)

c = F_vectorized(a, b)

print(c)

Output:

array([['ag', 'bh'],
       ['ci', 'dj'],
       ['ek', 'fl']], dtype='<U2')
Karol Żak
  • 2,158
  • 20
  • 24
  • 2
    `vectorize` is pretty, but generally slower than more explicit loops. – hpaulj May 19 '20 at 20:38
  • @hpaulj true, even numpy docs mention that: `The vectorize function is provided primarily for convenience, not for performance. The implementation is essentially a for loop.` – Karol Żak May 19 '20 at 20:43
  • Is there an option with faster performance for a large amount of 2D arrays, e.g, 20000 files of 3600x7200 dimension? So far, all I have tested (vectorize, etc) are slow. – PDash Sep 22 '22 at 20:56