1

Say when we have a randomly generated 2D 3x2 Numpy array a = np.array(3,2) and I want to change the value of the element on the first row & column (i.e. a[0,0]) to 10. If I do

a[0][0] = 10

then it works and a[0,0] is changed to 10. But if I do

a[np.arange(1)][0] = 10

then nothing is changed. Why is this?

I want to change some columns values of a selected list of rows (that is indicated by a Numpy array) to some other values (like a[row_indices][:,0] = 10) but it doesn't work as I'm passing in an array (or list) that indicates rows.

1
  • 1
    It's advised not to chain index for assignment. Do a[np.arange(1), 0] = 10. Commented Sep 1, 2022 at 17:09

2 Answers 2

5

a[x][y] is wrong. It happens to work in the first case, a[0][0] = 10 because a[0] returns a view, hence doing resul[y] = whatever modifies the original array. However, in the second case, a[np.arange(1)][0] = 10, a[np.arange(1)] returns a copy (because you are using array indexing).

You should be using a[0, 0] = 10 or a[np.arange(1), 0] = 10

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks! Follow-up: do you know the reason for a[np.arange(1)] returning a copy instead of a view and a[np.arange(1), 0] returns the view instead?
@JackShi because that is how numpy is designed, see here for the relevant documentation. Essentially, creating a view is easy in the former case, and cases involving slicing, because you just manipulate the strides and dimensions. See this question for some information on how numpy.ndarray objects are actually represented in memory
Are you sure a[np.arange(1), 0] is a view?
@hpaulj no, it is not, I did not mean to imply that it is. But assignment to a[x, y, ...] = whatever will modify the array in-place.
@JackShi a[np.arange(1), 0] of a[np.arange(1), 0] = 10 does not return anything, because you use assignment instead of getting values here. If you want to get value, you will also get a copy.
2

Advanced indexing always returns a copy as a view cannot be guaranteed.

Advanced indexing always returns a copy of the data (contrast with basic slicing that returns a view).

If you replace np.arange(1) with something that returns a view (or equivalent slicing) then you get back to basic indexing, and hence when you chain two views, the change is reflected into the original array.

For example:

import numpy as np


arr = np.arange(2 * 3).reshape((2, 3))
arr[0][0] = 10
print(arr)
# [[10  1  2]
#  [ 3  4  5]]

arr = np.arange(2 * 3).reshape((2, 3))
arr[:1][0] = 10
print(arr)
# [[10 10 10]
#  [ 3  4  5]]

arr = np.arange(2 * 3).reshape((2, 3))
arr[0][:1] = 10
print(arr)
# [[10  1  2]
#  [ 3  4  5]]

etc.


If you have some row indices you want to use, to modify the array you can just use them, but you cannot chain the indexing, e.g:

arr = np.arange(5 * 3).reshape((5, 3))
row_indices = (0, 2)
arr[row_indices, 0] = 10
print(arr)
# [[10  1  2]
#  [ 3  4  5]
#  [10  7  8]
#  [ 9 10 11]
#  [12 13 14]]

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.