0

I've been stuck for quite some time on this problem.

I have an array of shape (4,3,3). In my real case, the shape is much bigger.

a = np.array([
    [[1,2,3], [3,4,2], [1,3,4]],
    [[1,2,3], [3,6,2], [1,4,4]],
    [[1,2,3], [3,6,2], [1,4,4]],
    [[1,2,3], [3,6,2], [1,2,4]]
])

I want to use the np.where function to replace some of the list inside the array. For example, each time I have the list [1,2,3], I want to replace it by the list [99,99,99].

Without using np.where, to check if the list is completely equal to [1,2,3], I would use some function like all().

Using np.where:

np.where(a == [1,2,3], 99, a)

Will result in:

array([[[99, 99, 99],
    [ 3,  4,  2],
    [99,  3,  4]],

   [[99, 99, 99],
    [ 3,  6,  2],
    [99,  4,  4]],

   [[99, 99, 99],
    [ 3,  6,  2],
    [99,  4,  4]],

   [[99, 99, 99],
    [ 3,  6,  2],
    [99, 99,  4]]])

As you can see on the 3rd row, a part of the list has been replaced by 99.

I only want to replace the full list (never a part of the list) when it's exactly [1,2,3] and in the right order.

But I cannot solve this problem. I've been looking a lot online, with no luck.

6
  • 2
    a[(a == [1,2,3]).all(-1)] = 99, IIUC. Please include your desired result. Commented Feb 28, 2022 at 14:30
  • 1
    Is this for an assignment? The "Without using np.where, ..., i would use some function like all(). is very peculiar phrasing ^^ Commented Feb 28, 2022 at 14:34
  • @michael Is there an easy solution without using all() ? I'm interested in. Commented Feb 28, 2022 at 14:53
  • @Marie np.where works at the element level. I think you have to use .all() at some point to tell np to look at a whole row, now just a single element. @Michael's solution is very elegant imho. It doesn't get much more concise than that! Commented Feb 28, 2022 at 15:11
  • Does this answer your question? Identify and replace rows in a ndarray Commented Feb 28, 2022 at 16:20

1 Answer 1

0

The cond array is central to the workings of where:

In [167]: a == [1, 2, 3]
Out[167]: 
array([[[ True,  True,  True],
        [False, False, False],
        [ True, False, False]],

       [[ True,  True,  True],
        [False, False, False],
        [ True, False, False]],

       [[ True,  True,  True],
        [False, False, False],
        [ True, False, False]],

       [[ True,  True,  True],
        [False, False, False],
        [ True,  True, False]]])

You get 99 everywhere there's a True. We can use all to identify rows:

In [168]: (a == [1, 2, 3]).all(axis=-1)
Out[168]: 
array([[ True, False, False],
       [ True, False, False],
       [ True, False, False],
       [ True, False, False]])

But we can't use that in the where because it is 2d, and a is 3d:

In [169]: np.where(_, 99, a)
Traceback (most recent call last):
  Input In [169] in <module>
    np.where(_, 99, a)
  File <__array_function__ internals>:180 in where
ValueError: operands could not be broadcast together with shapes (4,3) () (4,3,3) 

But we can adjust the shape of the cond so it works:

In [171]: np.where(Out[168][...,None], 99, a)
Out[171]: 
array([[[99, 99, 99],
        [ 3,  4,  2],
        [ 1,  3,  4]],

       [[99, 99, 99],
        [ 3,  6,  2],
        [ 1,  4,  4]],

       [[99, 99, 99],
        [ 3,  6,  2],
        [ 1,  4,  4]],

       [[99, 99, 99],
        [ 3,  6,  2],
        [ 1,  2,  4]]])

Michael Szczesny's suggestion also works, because the 2d mask selects the desired rows from a:

In [172]: a[Out[168]]
Out[172]: 
array([[1, 2, 3],
       [1, 2, 3],
       [1, 2, 3],
       [1, 2, 3]])
Sign up to request clarification or add additional context in comments.

Comments

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.