Home > Blockchain >  array copy and view in numpy python
array copy and view in numpy python

Time:06-13

I am new to numpy.Recently only I started learning.I am doing one practice problem and getting error. Question is to replace all even elements in the array by -1.

import numpy as np
np.random.seed(123)
array6 = np.random.randint(1,50,20)
slicing_array6 = array6[array6 %2==0]
print(slicing_array6)
slicing_array6[:]= -1
print(slicing_array6)
print("Answer is:")
print(array6)

I am getting output as :

[46 18 20 34 48 10 48 26 20]
[-1 -1 -1 -1 -1 -1 -1 -1 -1]
Answer is:
[46  3 29 35 39 18 20 43 23 34 33 48 10 33 47 33 48 26 20 15]

My doubt is why original array not replaced? Thank you in advance for help

CodePudding user response:

In [12]: np.random.seed(123)
    ...: array6 = np.random.randint(1,50,20)
    ...: slicing_array6 = array6[array6 %2==0]

In [13]: array6.shape
Out[13]: (20,)

In [14]: slicing_array6.shape
Out[14]: (9,)

slicing_array6 is not a view; it's a copy. It does not use or reference the array6 data:

In [15]: slicing_array6.base

Modifying this copy does not change array6:

In [16]: slicing_array6[:] = -1

In [17]: slicing_array6
Out[17]: array([-1, -1, -1, -1, -1, -1, -1, -1, -1])

In [18]: array6
Out[18]: 
array([46,  3, 29, 35, 39, 18, 20, 43, 23, 34, 33, 48, 10, 33, 47, 33, 48,
       26, 20, 15])

But if the indexing and modification occurs in the same step:

In [19]: array6[array6 %2==0] = -1

In [20]: array6
Out[20]: 
array([-1,  3, 29, 35, 39, -1, -1, 43, 23, -1, 33, -1, -1, 33, 47, 33, -1,
       -1, -1, 15])

slicing_array6 = array6[array6 %2==0] has actually done

 array6.__getitem__(array6%2==0)

array6[array6 %2==0] = -1 does

 array6.__setitem__(array6 %2==0, -1)

A __setitem__ applied to a view does change the original, the base.

An example with view that works:

In [32]: arr = np.arange(10)    
In [33]: arr
Out[33]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [34]: x =  arr[::3]  # basic indexing, with a slice
In [35]: x
Out[35]: array([0, 3, 6, 9])
In [36]: x.base          # it's a `view` of arr
Out[36]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [37]: x[:] = -1
In [38]: arr
Out[38]: array([-1,  1,  2, -1,  4,  5, -1,  7,  8, -1])

CodePudding user response:

Explanation

Let's move step by step. We start with

array6 = np.array([46,  3, 29, 35, 39, 18, 20, 43, 23, 34, 33, 48, 10, 33, 47, 33, 48, 26, 20, 15])
print(array6 %2==0)

# array([ True, False, False, False, False,  True,  True, False, False,
#         True, False,  True,  True, False, False, False,  True,  True,
#         True, False])

You just made a mask (%2==0) to array6. Then you apply the mask to it and assign to a new variable:

slicing_array6 = array6[array6 %2==0]
print(slicing_array6)

# [46 18 20 34 48 10 48 26 20]

Note that this returns a new array:

print(id(array6))
# 2643833531968

print(id(slicing_array6))
# 2643833588112

print(array6)
# [46  3 29 35 39 18 20 43 23 34 33 48 10 33 47 33 48 26 20 15]
# unchanged !!

Final step, you assign all elements in slicing_array6 to -1:

slicing_array6[:]= -1
print(slicing_array6)
# [-1 -1 -1 -1 -1 -1 -1 -1 -1]

Solution

Instead of assigning masked array to a new variable, you apply new value directly to the original array:

array6[array6 %2==0] = -1
print(array6)
print(id(array6))

# [-1  3 29 35 39 -1 -1 43 23 -1 33 -1 -1 33 47 33 -1 -1 -1 15]
# 2643833531968
# same id !!

CodePudding user response:

Numpy's slicing functionality directly modifies the array, but you have to assign the value you want to it. Not to completely ruin your learning, here is a similar example to what you are trying to achieve:

import numpy as np
a = np.arange(10)**3
print(f"start:  {a}")
#start:  [  0   1   8  27  64 125 216 343 512 729]

# to assign every 3rd item as -99
a[2::3] = -99

print(f"answer: {a}")
#answer: [  0   1 -99  27  64 -99 216 343 -99 729]
  • Related