Numpy Array Assignment with Copy

Numpy array assignment with copy

All three versions do different things:

  1. B = A

    This binds a new name B to the existing object already named A. Afterwards they refer to the same object, so if you modify one in place, you'll see the change through the other one too.

  2. B[:] = A (same as B[:]=A[:]?)

    This copies the values from A into an existing array B. The two arrays must have the same shape for this to work. B[:] = A[:] does the same thing (but B = A[:] would do something more like 1).

  3. numpy.copy(B, A)

    This is not legal syntax. You probably meant B = numpy.copy(A). This is almost the same as 2, but it creates a new array, rather than reusing the B array. If there were no other references to the previous B value, the end result would be the same as 2, but it will use more memory temporarily during the copy.

    Or maybe you meant numpy.copyto(B, A), which is legal, and is equivalent to 2?

Strange numpy array assignment after copy

LAC = label does NOT copy label into a new array. It is simply assigning the same object to LAC. Thus, when you change one, the other also changes. Think of it as both being the same array with different names.

If you wish to make a new copy of your array, use np.copy. Here is an example to make it clear:

label = np.array([0., 1., 2., 3., 4., 0., 1., 2., 3., 4.])
print(np.unique(label))
#[0. 1. 2. 3. 4.]

#LAC and label point to the same object
LAC = label
#this changes both LAC and label
LAC[LAC != 4] = 0

print(np.unique(LAC))
#[0. 4.]

print(np.unique(label))
#[0. 4.]

label = np.array([0., 1., 2., 3., 4., 0., 1., 2., 3., 4.])
#make a new copy of label
LAC = label.copy()
#this changes ONLY LAC
LAC[LAC != 4] = 0

print(np.unique(LAC))
#[0. 4.]

print(np.unique(label))
#[0. 1. 2. 3. 4.]

how to create a new numpy array by masking another numpy array with a single assignment

I must preface this by saying any attempt in doing so massively decreases readability. Just use two lines if you don't want to other people (or yourself) to ever work with that code again. This answer is just supposed to demonstrate what could be done, not what should be done.

The expression A=B=x assigns x to both A and B. If you really want to squeeze everything onto one line you could try something like

import numpy as np
a = np.arange(5)
(b:=a.copy())[a!=0]=1

The := (walrus) operator actually evaluates to the assigned value, unlike the assignment (=) operator. (Note that A=B=x works because it is basically a shorthand for t=x; A=t; B=t, but A=(B=x) will not work as the assignment does not evaluate to anything. You chould write A=(B:=x) though.) Then a remains unchanged, which corresponds to your first version, so

>>> b
array([0, 1, 1, 1, 1])
>>> a
array([0, 1, 2, 3, 4])

Python - array copying/assign, unexpected '=array[:]' behaviour for numpy

EDITED - see @juanpa.arrivillaga's comments below.

In all of your examples, values of the ndarrays are

numpy.int32 objects, which are mutable.

So from your 3rd example, both e and ArrayE point to the same numpy.int32 objects.

That's why the changes are reflected on both.

You can verify that by checking their ids.

print(id(e[0]) == id(ArrayE[0]))

Numpy variable assignment is by reference?

This is in general python behaviour and not specific to numpy. If you have an object such as list you will see a similar behaviour.

a = [1]
b = a
b[0] = 7
print a
print b

will output

[7]
[7]

This happens because variable a is pointing to a memory location where the array [1] is sitting and then you make b point to the same location. So if the value at that location changes, both the variables are still pointing there. If you want to get around this behaviour you'll need to use the .copy() function like this.

A = np.zeros((2,2))
B = A.copy()
A[0,0] = 2
print A
print B

which outputs..

[[2. 0.]
[0. 0.]]
[[0. 0.]
[0. 0.]]

Using the copy() function will spawn a whole new object instead of pointing to the old one.
Caution: This may not be the ideal way to do it since copying a huge numpy array can be computationally expensive

EDIT: Removed the word mutable since the behaviour is also applicable to immutables.

NumPy array loses dimension upon assignment/copy, why?

Looking at the openCV script mentioned in the comments, the reshape to three dimensions is necessary because a dimension is being lost via Boolean indexing, and not by the assignment alone.

The names of the arrays in that script which motivated the question are p0 and good_new.

Here is a breakdown of the operations in that script:

  1. p0 is a 3D array with shape (17, 1, 2).

  2. The line:

    p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)

    creates new arrays, with array p1 having shape (17, 1, 2) and array st having shape (17, 1).

  3. The assignment good_new = p1[st==1] creates a new array object by a Boolean indexing operation on p1. This is a 2D array has shape (17, 2). A dimension has been lost through the indexing operation.

  4. The name p0 needs to be assigned back to the array data contained in good_new, but p0 also needs to be 3D. To achieve this, the script uses p0 = good_new.reshape(-1, 1, 2).


For completeness, it is worth summarising why the Boolean indexing operation in step (3) results in a dimension disappearing.

The Boolean array st == 1 has shape (17, 1) which matches the initial dimensions of p1, (17, 1, 2).

This means that the selection occurs in the second dimension of p1: the indexer array st == 1 is determining which arrays of shape (2,) should be in the resulting array. The final array will be of shape (n, 2), where n is the number of True values in the Boolean array.

This behaviour is detailed in the NumPy documentation here.

Numpy array assignment by boolean indices array

If IDX is a NumPy array of Boolean type, and X and Y are NumPy arrays then your intuition works:

X = np.array(X)
Y = np.array(Y)
IDX = np.array(IDX).astype(bool)

X[IDX] = Y[IDX]

This changes X in place.

If you don't want to do all this type casting, or don't want to overwrite X, then np.where() does what you want in one go:

np.where(IDX==1, Y, X)


Related Topics



Leave a reply



Submit