0

Was experimenting with numpy and found this strange behavior. This code works ok:

>>> a = np.array([[1, 2, 3], [4, 5, 6]])    
>>> a[:, 1].flat[:] = np.array([-1, -1])
>>> a 
array([[ 1, -1,  3],
       [ 4, -1,  6]])

But why this code doesn't change to -1 elements of 0 and 2 column?

>>> a[:, [0, 2]].flat[:] = np.array([-1, -1])
>>> a 
array([[ 1, -1,  3],
       [ 4, -1,  6]])

And how to write the code so that would change to -1 elements of 0 and 2 columns like this?

UPD: use of flat or smt similar is necessarily in my example

UPD2: I made example in question basing on this code:

img = imread(img_name)
xor_mask = np.zeros_like(img, dtype=np.bool)
# msg_bits looks like array([ True, False, False, ..., False, False,  True], dtype=bool)
xor_mask[:, :, channel].flat[:len(msg_bits)] = np.ones_like(msg_bits, dtype=np.bool)

And after assignment to xor mask with channel == 0 or 1 or 2 code works ok, but if channel == [1,2] or smt like this, assignment does not happen

4
  • It's not clear why you need to use flat. As already answered below, flat may create a copy therefore your updates may not change the original array. Explain why you need flat at all and maybe you can get a solution. Commented Oct 12, 2016 at 10:14
  • @lbolla updated question Commented Oct 12, 2016 at 10:27
  • 1
    @ЮраМахоткин Seems you are stuck in an XY problem. Commented Oct 12, 2016 at 11:00
  • @Divakar yeah, you right. I will post question again but with correct problem formulation Commented Oct 12, 2016 at 11:04

3 Answers 3

2

In first example by flattening the slice you don't change the shape and actually the python Numpy doesn't create a new object. so assigning to flattened slice is like assigning to actual slice. But by flattening a 2d array you're changing the shape and hence numpy makes a copy of it.

also you don't need to flatten your slice to add to it:

In [5]: a[:, [0, 2]] += 100

In [6]: a
Out[6]: 
array([[101,   2, 103],
       [104,   5, 106]])
Sign up to request clarification or add additional context in comments.

2 Comments

This example from other problem, there is necessarily to use flat. Can you explain how to do with flat?
@ЮраМахоткин Pleas add the use case to question, it's hard to answer like this.
1

As others has pointed out .flat may create a copy of the original vector, so any updates to it would be lost. But flattening a 1D slice is fine, so you can use a for loop to update multiple indexes.

import numpy as np

a = np.array([[1, 2, 3], [4, 5, 6]])
a[:, 1].flat = np.array([-1, -1])
print a

# Use for loop to avoid copies
for idx in [0, 2]:
     a[:, idx].flat = np.array([-1, -1])
print a

Note that you don't need to use flat[:]: just flat is enough (and probably more efficient).

6 Comments

What's not to like about it?
Nothing, but i'm learning numpy and expected some numpy construction for this situation
Well, you seem to be fixed on using flat, but flat must create a copy in your situation, so it can't be used. I think you simply have to "tune" your expectations...
But wait. For-loop doesn't fit to my needs: xor_mask[:, :, channel].flat[:len(msg_bits)] = np.ones_like(msg_bits, dtype=np.bool) and for ch in channel: xor_mask[:, :, ch].flat[:len(msg_bits)] = np.ones_like(msg_bits, dtype=np.bool) logically does different process
You've got to break msg_bits accordingly. I don't know why you are fixated with using flat, so I can't give you a meaningful recommendation.
|
0

You could just remove the flat[:] from a[:, [0, 2]].flat[:] += 100:

>>> import numpy as np
>>> a = np.array([[1, 2, 3], [4, 5, 6]])
>>> a[:, 1].flat[:] += 100
>>> a
array([[  1, 102,   3],
       [  4, 105,   6]])
>>> a[:, [0, 2]] += 100
>>> a
array([[101, 102, 103],
       [104, 105, 106]])

But you say it is necessary... Can't you just reshape whatever you are trying to add to the initial array instead of using flat?

The second index call makes a copy of the array while the first returns a reference to it:

>>> import numpy as np
>>> a = np.array([[1, 2, 3], [4, 5, 6]])
>>> b = a[:,1].flat
>>> b[0] += 100
>>> a
array([[  1, 102,   3],
       [  4,   5,   6]])
>>> b =a[:,[0,2]].flat
>>> b[0]
1
>>> b[0] += 100
>>> a
array([[  1, 102,   3],
       [  4,   5,   6]])
>>> b[:]
array([101,   3,   4,   6])

It appears that when the elements you wish to iterate upon in a flat maner are not adjacent numpy makes an iterator over a copy of the array.

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.