1

I am trying to populate a 2D numpy array. In my experience, the following is not going to scale up well with array sizes.

x=np.array([2,3,4])
y=np.array([1,3,9,13])
mat=np.zeros((x.size,y.size))
for i in range(nx):
 for j in range(ny):
   if x[i] > y[j]:
        mat[i,j] = 1
   else:
        mat[i,j] = -1

Ideally, I would like to use list comprehension like It would be simple if it was 1D only

mat=np.asarray([foo(x_) for x_ in x])

but how to generalize this to 2D np.arrays? Other numpy based solutions are also suitable, but efficiency is the key metric here

2
  • Are you looking for a general solution or specifically like in the example to populate triangular parts of the matrix? Commented Dec 13, 2017 at 8:01
  • my application case is the one of the example. However, a general solution would be probably useful to more SO users... It would be nice to have something which works with a generic foo(x_,y_) with two inputs similarly to the last code line Commented Dec 13, 2017 at 8:04

4 Answers 4

2

Your mat:

In [352]: mat
Out[352]: 
array([[ 1., -1., -1., -1.],
       [ 1., -1., -1., -1.],
       [ 1.,  1., -1., -1.]])

broadcasting x against y:

In [353]: x[:,None]>y
Out[353]: 
array([[ True, False, False, False],
       [ True, False, False, False],
       [ True,  True, False, False]], dtype=bool)

turn that boolean mask into 1/-1 array with where:

In [354]: np.where(x[:,None]>y,1,-1)
Out[354]: 
array([[ 1, -1, -1, -1],
       [ 1, -1, -1, -1],
       [ 1,  1, -1, -1]])

Or you could turn the boolean into a 0/1 array, and scale that to fit

(x[:,None]>y).astype(float)*2-1

A double loop over two 1d arrays or lists can often be cast as an outer operation like this.

Sign up to request clarification or add additional context in comments.

Comments

2

It is possible to build 2 dimensional nested list comprehensions:

mat = np.array([[1 if x_ > y_ else -1 for y_ in y] for x_ in x])

However, this can become pretty unreadable, and is not much different from for loops as far performance scaling is concerned. Broadcasting and vectorization will usually work better with larger arrays:

mat = (x[:, None] > y[None, :]) * 2 - 1

Comments

1

try:

x=np.array([2,3,4])
y=np.array([1,3,9,13])
a = (x.reshape(x.shape[0], 1) - y) > 0  # a=(x.reshape(-1, 1) - y) > 0
a = a.astype(int)*2 -1 

1 Comment

You can also pass -1 to reshape instead of x.shape[0].
1

If using numpy:

import numpy as np
nx = x.size
ny = y.size
mat = np.sign(x * np.atleast_2d(np.ones(ny)).T - np.ones(nx) * np.atleast_2d(y).T)
mat[np.where(mat==0)] = -1

numpy will take care regarding efficiency (whatever it means here).

1 Comment

in the end, you answer (without the last line) was the solution to my actual problem. However, since I made a mistake in the question by describing incorrectly the desired behavior with when x==y, I cannot accept it. but thanks :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.