5

I am a naive numpy user, need your help for the following problem: I want to replace some elements of a multidimensional array which are less than a second array by a third array; e.g.:

x = np.arange(16).reshape((2, 8)) 
# x = np.array([[ 0,  1,  2,  3,  4,  5,  6,  7],
#               [ 8,  9, 10, 11, 12, 13, 14, 15]])

And

y = np.array([[2], [13]])
# y = np.array([[ 2], [13]])

Now, find out where x is greater than y, and if there is at least one True in x > y array, count these instances, create another array (z) and replace x in these elements with z:

x > y 
# = [[False, False, False, True,  True,  True,  True, True],
#    [False, False, False, False, False, False, True, True]]

In this case 5 elements of x (x[:,3:]) should be replaced, so we create a (5, 2) array:

z = np.array([[20,21],[22,23],[24,25],[26,27],[28,29]])

The result I want is

x == np.array([[ 0,  1,  2, 20, 22, 24, 26, 28],
               [ 8,  9, 10, 21, 23, 25, 27, 29]])

1 Answer 1

4

A numpy function that does almost exactly what you want is numpy.where:

x = np.arange(16).reshape((2, 8))
y = np.array([[2], [13]])
z = np.arange(16, 32).reshape((2, 8))
numpy.where(~(x > y).any(axis=0), x, z)

Result:

array([[ 0,  1,  2, 19, 20, 21, 22, 23],
       [ 8,  9, 10, 27, 28, 29, 30, 31]])

The only difference between this and what you asked for is that z has to be broadcastable to the same shape as x. Unless you absolutely need to use a z value with only as many columns as there are True values in ~(x > y).any(axis=0), I think this is the best approach.

However, given your comments, it seems that you do need to use a z value as described above. It sounds like the function guarantees that the shapes will match up, so you can probably just do this:

x[:,(x > y).any(axis=0)] = z.T

Tested:

>>> z = np.arange(20, 30).reshape((5, 2))
>>> x[:,(x > y).any(axis=0)] = z.T
>>> x
array([[ 0,  1,  2, 20, 22, 24, 26, 28],
       [ 8,  9, 10, 21, 23, 25, 27, 29]])
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks @sederle; this returns an error: ValueError: 'shape mismatch: objects cannot be broadcast to a single shape' ; I should mention that I don't know shape of the array z ahead.
@AsoAgile, ok -- but in that case, we need more information about how z should be aligned with respect to x for purposes of replacement. Is z simply a mask as it's treated here? Or is there some kind of sequential logic?
@sederle; in above example z is (5,2) array created by another function, with first dimension from the number of True (at least one True in x>y), here 5, and second dimention as the first dimension of x, here 2.
@sederle, your approach worked perfectly for my original question with following modification: 'x[:,(x > y).any(axis=0)] = z.T'; the unknown dimension of z is obtained with: 'np.sum((x > y).any(axis=0))'
@AsoAgile, ah, I wasn't paying attention to the shape of z as you described it. I'll fix it then.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.