4

When using numpy named arrays I observe a different behaviour in the following two cases:

  1. case: first using an index array for advanced slicing and then selecting a subarray by name
  2. case: first selecting a subarray by name and then using an index array for advanced slicing

The follwing code presents an example

import numpy as np

a = np.ones(5)
data = np.array(zip(a, a, a), dtype=[("x", float), ("y", float), ("z", float)])

# case 1
# does not set elements 1, 3 and 4 of data to 22
data[[1, 3, 4]]["y"] = 22    
print data["y"]  # -> [ 1.  1.  1.  1.  1.]

# case 2
# set elements 1, 3 and 4 of data to 22
data["y"][[1, 3, 4]] = 22
print data["y"]  # -> [  1.  22.   1.  22.  22.]

The output of the two print commands is [ 1. 1. 1. 1. 1.] and [ 1. 22. 1. 22. 22.]. Why does changing the order of the selections lead to different results when setting the elements?

ali_m
  • 71,714
  • 23
  • 223
  • 298
murban
  • 47
  • 1
  • 5

1 Answers1

3

Indexing with a list or array always returns a copy rather than a view:

In [1]: np.may_share_memory(data, data[[1, 3, 4]])
Out[1]: False

Therefore the assignment data[[1, 3, 4]]["y"] = 22 is modifying a copy of data[[1, 3, 4]], and the original values in data will be unaffected.

On the other hand, referencing a field of a structured array returns a view:

In [2]: np.may_share_memory(data, data["y"])
Out[2]: True

so assigning to data["y"][[1, 3, 4]] will affect the corresponding elements in data.

ali_m
  • 71,714
  • 23
  • 223
  • 298
  • As you said indexing with a list or array always returns a copy rather than a view. This explains why `data[[1, 3, 4]]["y"] = 22` is working on a copy of `data`. But for the same reason `data["y"][[1, 3, 4]]` should work only on a copy of `data["y"]`. This shows also `np.may_share_memory(data, data["y"][[1, 3, 4]])` which turns out to be `False`. So I don't understand why this asignment works. – murban Sep 30 '16 at 10:46
  • It's fine to assign to elements using an indexing expression that would return a copy as long as you do the assignment directly, without chaining any other indexing operations afterwards. For example, `x[[1, 2, 3]] = 4, 5, 6` will work, but `x[[1, 2, 3]][:] = 4, 5, 6` will not affect `x` since the first indexing expression returns a copy. – ali_m Sep 30 '16 at 10:59