Когда расширенная индексация структурированных маскированных массивов *действительно* возвращает копию?

Когда у меня есть структурированный маскированный массив с булевой индексацией, при каких условиях я получаю представление и когда я получаю копию? В документации говорится, что расширенное индексирование всегда возвращает копировать, но это неверно, так как что-то вроде X[X>0]=42 это технически продвинутая индексация, но присваивание работает. У меня ситуация сложнее:

Я хочу установить маску определенного поля на основе критерия из другого поля, поэтому мне нужно получить поле, применить логическое индексирование и получить маску. Есть 3! = 6 заказов.

Подготовка:

In [83]: M = ma.MaskedArray(random.random(400).view("f8,f8,f8,f8")).reshape(10, 10)

In [84]: crit = M[:, 4]["f2"] > 0.5
  1. Поле - индекс - маска (сбой):

    In [85]: M["f3"][crit, 3].mask = True
    
    In [86]: print(M["f3"][crit, 3].mask)
    [False False False False False]
    
  2. Индекс-поле-маска (сбой):

    In [87]: M[crit, 3]["f3"].mask = True
    
    In [88]: print(M[crit, 3]["f3"].mask)
    [False False False False False]
    
  3. Индекс - маска - поле (сбой):

    In [94]: M[crit, 3].mask["f3"] = True
    
    In [95]: print(M[crit, 3].mask["f3"])
    [False False False False False]
    
  4. Маска - индекс - поле (сбой):

    In [101]: M.mask[crit, 3]["f3"] = True
    
    In [102]: print(M.mask[crit, 3]["f3"])
    [False False False False False]
    
  5. Поле - маска - индекс (успешно):

    In [103]: M["f3"].mask[crit, 3] = True
    
    In [104]: print(M["f3"].mask[crit, 3])
    [ True  True  True  True  True]
    
    # set back to False so I can try method #6
    
    In [105]: M["f3"].mask[crit, 3] = False
    
    In [106]: print(M["f3"].mask[crit, 3])
    [False False False False False]
    
  6. Маска - поле - индекс (успешно):

    In [107]: M.mask["f3"][crit, 3] = True
    
    In [108]: print(M.mask["f3"][crit, 3])
    [ True  True  True  True  True]
    

Таким образом, похоже, что индексирование должно быть последним.


person gerrit    schedule 15.06.2016    source источник
comment
Дубликат, stackoverflow .com/questions/15691740/ решает проблему __setitem__ v __getitem__. Но я думаю, что здесь есть нюансы, которые требуют дальнейшего изучения — это структурированный массив и замаскированный. Итак, возникает вопрос о том, как индексация полей взаимодействует с индексацией элементов и как можно установить mask. Я предлагаю возобновить это.   -  person hpaulj    schedule 15.06.2016


Ответы (2)


Вопрос __setitem__ против __getitem__ важен, но со структурированным массивом и маскированием немного сложнее разобраться, когда __getitem__ впервые делает копию.

Что касается структурированных массивов, не должно иметь значения, идет ли первым индекс поля или элемент. Однако некоторые выпуски, похоже, имеют ошибку в этом отношении. Я попытаюсь найти недавний вопрос SO, где это было проблемой.

С маскированным массивом возникает вопрос, как правильно изменить маску. .mask — это свойство, которое обращается к базовому массиву ._mask. Но это извлекается с помощью __getattr__. Таким образом, простое различие setitem и getitem не применяется напрямую.

Давайте сначала пропустим структурированный бит

In [584]: M = np.ma.MaskedArray(np.arange(4))

In [585]: M
Out[585]: 
masked_array(data = [0 1 2 3],
             mask = False,
       fill_value = 999999)

In [586]: M.mask
Out[586]: False

In [587]: M.mask[[1,2]]=True
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-587-9010ee8f165e> in <module>()
----> 1 M.mask[[1,2]]=True

TypeError: 'numpy.bool_' object does not support item assignment

Изначально mask является скалярным логическим значением, а не массивом.

Это работает

In [588]: M.mask=np.zeros((4,),bool)  # change mask to array

In [589]: M
Out[589]: 
masked_array(data = [0 1 2 3],
             mask = [False False False False],
       fill_value = 999999)

In [590]: M.mask[[1,2]]=True

In [591]: M
Out[591]: 
masked_array(data = [0 -- -- 3],
             mask = [False  True  True False],
       fill_value = 999999)

Это не

In [592]: M[[1,2]].mask=True

In [593]: M
Out[593]: 
masked_array(data = [0 -- -- 3],
             mask = [False  True  True False],
       fill_value = 999999)

M[[1,2]], очевидно, является копией, и присваивается его атрибуту mask, а не M.mask.

....

Маскированный массив имеет метод .__setmask__. Вы можете изучить это в np.ma.core.py. И свойство маски определяется с помощью

mask = property(fget=_get_mask, fset=__setmask__, doc="Mask")

Итак, M.mask=... использует это.

Таким образом, похоже, что проблемный случай делает

M.__getitem__(index).__setmask__(values)

отсюда и копия. M.mask[]=... делает

M._mask.__setitem__(index, values)

так как _getmask просто делает return self._mask.


M["f3"].mask[crit, 3] = True

работает, потому что M['f3'] — это представление. (M[['f1','f3']] подходит для получения, но не работает для настройки).

M.mask["f3"] тоже вид. Я не совсем уверен в порядке получения и установки соответствующих элементов. __setmask__ имеет код, специально предназначенный для составного dtype (структурированного).

=========================

Глядя на структурированный массив без сложностей с маскировкой, порядок индексации имеет значение.

In [607]: M1 = np.arange(16).view("i,i")

In [609]: M1[[3,4]]['f1']=[3,4]          # no change   
In [610]: M1[[3,4]]['f1']
Out[610]: array([7, 9], dtype=int32)

In [611]: M1['f1'][[3,4]]=[1,2]    # change
In [612]: M1
Out[612]: 
array([(0, 1), (2, 3), (4, 5), (6, 1), (8, 2), (10, 11), (12, 13), (14, 15)], dtype=[('f0', '<i4'), ('f1', '<i4')])

Таким образом, у нас все еще есть __getitem__, за которым следует __setitem__, и мы должны обратить внимание на то, возвращает ли get представление или копию.

person hpaulj    schedule 15.06.2016

Это связано с тем, что хотя расширенное индексирование возвращает копию, назначение расширенному индексированию по-прежнему работает. Только метод, в котором расширенное индексирование является последней операцией, назначается расширенному индексированию (через __setitem__).

person gerrit    schedule 15.06.2016