4

When I create a view of a Numpy masked array (via slicing) the mask is copied to the view -- so that updates to the view will not change the mask in the original (but will change the data in the original array).

What I want is to change both the original data and the original mask when updating the view.

From the Numpy documentation:

When accessing a slice, the output is a masked array whose data attribute is a view of the original data, and whose mask is either nomask (if there was no invalid entries in the original array) or a copy of the corresponding slice of the original mask. The copy is required to avoid propagation of any modification of the mask to the original.

Example

import numpy.ma as ma

orig_arr = ma.array([[11,12],[21,22]])
orig_arr[1,:] = ma.masked

print orig_arr
## Prints: [[11 12]
##          [-- --]]

view_arr = orig_arr[1,:]
print view_arr
## Prints: [-- --]

view_arr[:] = [31,32]
print view_arr
## Prints: [31 32]

print orig_arr
## Prints: [[11 12]
##          [-- --]]
print orig_arr.data[1,:]
## Prints: [31 32]

As you can see the data in the original array has been updated, but the mask hasn't.

How do I make updates in the view affect the mask in the original array?

qff
  • 5,524
  • 3
  • 37
  • 62

1 Answers1

3

Try turning off the mask in the view before changing the value

orig_arr = ma.array([[11,12],[21,22]])
orig_arr[1,:] = ma.masked

print orig_arr
## Prints: [[11 12]
##          [-- --]]

view_arr = orig_arr[1,:]
print view_arr
## Prints: [-- --]

view_arr.mask=False # or [True, False] 


view_arr[:] = [31,32] 
print view_arr
## Prints: [31 32] #or [-- 32]

print orig_arr
## Prints: [[11 12]
##          [31 32]] # or [-- 32]
M.T
  • 4,917
  • 4
  • 33
  • 52
  • I was a little doubtful about this working, but it does. But my tests also showed some unpredicatible changes/non-changes. I'd have to look more at the `ma` code to properly understand why this works. – hpaulj Dec 11 '15 at 20:39
  • I agree, it seems somewhat inconsistent. – M.T Dec 11 '15 at 20:59
  • It's worth keeping in mind that the actual mask is in `arr._mask`, while `arr.mask` is property, with a `.__setmask__` method. So there is 'magic' going on when you do `arr.mask=[...]`. – hpaulj Dec 12 '15 at 00:58
  • Apparently `view_arr._mask` is initially a `view`, and `view_arr.mask=...` changes it with `[...]` (preserving the link). But `var_arr[:]=[]` creates a new `_mask`, breaking the link. So the view mask is a 'lazy' copy, not an actual one, until you modify the `view`. I tested this by looking at `x._mask.__array_interface__`. – hpaulj Dec 12 '15 at 01:08
  • This seems to work contrary to the way the documentation describes it: isn't this likely to break in later versions of Numpy? Very weird behaviour – thank you for the workaround though! :) – qff Dec 12 '15 at 03:05
  • My guess is that the documentation needs refinement. But I'd suggest searching the github issues for any relevant discussions. – hpaulj Dec 12 '15 at 05:09