Необычное индексирование Python с помощью массива с логической маской

python numpy indexing masked-array

963 просмотра

3 ответа

125 Репутация автора

У меня есть массивный массив данных:

data = masked_array(data = [7 -- 7 1 8 -- 1 1 -- -- 3 -- -- 3 --],
                    mask = [False True False False False True False False True True False True True False True])

У меня есть флаг определенного типа данных, который является массивом с логической маской:

flag = masked_array(data = [True False False True -- -- -- False -- True -- -- -- -- True],
                    mask = [False False False False True True True False True False True True True True False])

Я хочу сделать что-то вроде data[flag]и получить следующий вывод:

output_wanted = [7 1 -- --]

что соответствует элементам данных, где флаг равен True. Вместо этого я получаю это:

output_real = [7 -- 7 1 8 -- 1 1 -- -- 3 -- -- 3 --]

Я не копировал маски выводов для лучшей наглядности.

Я не против иметь вывод с размером флага, пока он выбирает данные, которые я хочу (те, которые соответствуют истинным значениям флага). Но я не могу понять, почему это дает значения тезисов в реальном выводе!

Автор: JoVe Источник Размещён: 19.07.2016 09:46

Ответы (3)


2 плюса

23061 Репутация автора

Как насчет чего-то вроде:

import numpy as np
from numpy.ma import masked_array

data = masked_array(data = [7,     0,     7,     1,     8,     0,    1,     1,     0,    0,     3,     0,    0,    3,     0],
                    mask = [False, True,  False, False, False, True, False, False, True, True,  False, True, True, False, True])
flag = masked_array(data = [True,  False, False, True,  0,     0,    0,     False, 0,    True,  0,     0,    0,    0,     True],
                    mask = [False, False, False, False, True,  True, True,  False, True, False, True,  True, True, True,  False])

print(repr(data))
print(repr(flag))

indices = np.where(flag & ~flag.mask)
print(data[indices])

Обратите внимание, что вы можете столкнуться с проблемами, если замаскированные значения flagне могут быть сопоставлены &, но это не похоже на то, что это для вас.

Выход:

masked_array (data = [7 - 7 1 8 - 1 1 - - 3 - - 3 -],
             mask = [False True False False False True False False True True False True True False True],
       fill_value = 999999)

masked_array (data = [1 0 0 1 - - - 0 - 1 - - - - 1],
             mask = [False False False False True True True False True False True True True True False],
       fill_value = 999999)

[7 1 - -]

Редактировать:

Альтернативный способ получения индексов также может быть:

indices = np.where(flag.filled(False))

Обновление (Редактировать 2):

Остерегайтесь тонкостей индексации массивов с использованием массивов.

Рассмотрим следующий код:

import numpy as np

data = np.array([1,2,3,4,5])
mask = np.array([True, False, True, False, True])

res  = data[mask]
print(res)

Как и следовало ожидать (или нет), здесь маска служит «фильтром», отфильтровывая элементы данных, для которых соответствующее положение в маске равно False. Из-за значений, которые я выбираю для dataи mask, эффект заключается в том, что индексирование служит для фильтрации четных dataзначений, оставляя только нечетные.

Выход здесь: [1 3 5].

Теперь рассмотрим очень похожий код:

import numpy as np

data = np.array([1,2,3,4,5])
mask = np.array([1, 0, 1, 0, 1])

res  = data[mask]
print(res)

Здесь единственное, что изменилось, - это тип данных элементов маски, их логическое значение одинаково. Давайте назовем первую маску (состоящую из True/ Falsevalues) mask1и вторую маску (состоящую из 1/ 0values) mask2.

Вы можете проверить тип данных массивов через dtypeатрибут (например print(mask.dtype)). mask1имеет тип d bool, а mask2тип d int32.

Здесь, однако, выход отличается: [2 1 2 1 2] .

Что тут происходит?

Фактически, индексирование ведет себя по-разному в зависимости от типа данных массива, используемого для индексации. Как уже упоминалось, когда тип данных «маска» является логическим, он выполняет функцию фильтрации. Но когда тип данных «mask» является интегральным, он выполняет функцию «selection», используя элементы индекса в качестве индексов исходного массива.

Итак, во втором примере, поскольку data[1] = 2и data[0] = 1, результатом data[mask2]является массив длиной 5, а не 3 (в логическом случае).

Поместите другой путь, учитывая следующий код:

res = data[mask]

Если mask.dtype == intдлина res будет равна длине маски.

Если mask.dtype == boolдлина res будет равна количеству Trueзначений в маске.

Разница

И наконец, вы можете привести массив одного типа данных к другому, используя astypeметод.

Демонстрационный фрагмент:

import numpy as np

data = np.array([1,2,3,4,5])

# Create a boolean mask
mask1 = np.array([True, False, True, False, True])

# Create an integer "mask", using the same logical values 
mask2 = np.array([1,0,1,0,1])

# Coerce mask2 into a boolean mask
mask3 = mask2.astype(bool)

print(data)         # [1 2 3 4 5]
print("-" * 80)
print(mask1)        # [True  False  True  False  True]
print(mask1.dtype)  # bool
print(data[mask1])  # [1 3 5]
print("-" * 80)
print(mask2)        # [1 0 1 0 1]
print(mask2.dtype)  # int32
print(data[mask2])  # [2 1 2 1 2]
print("-" * 80)
print(mask3)        # [True  False  True  False  True]
print(mask3.dtype)  # bool
print(data[mask3])  # [1 3 5]
Автор: jedwards Размещён: 19.07.2016 10:17

0 плюса

125 Репутация автора

Я выяснил, как работает индексация с помощью маскированных массивов.

На самом деле, Python не имеет дело с этим видом индексации.

Когда вы делаете что-то вроде массива data[flag]с flagлогической маской, python получает базовые данные flag. Другими словами, он принимает значения маскированных значений до того, как они были маскированы.

Так что будьте осторожны: если замаскированные значения явно не заполнены их fill_value, индексация может выглядеть случайной.

Пример:

>>> arr = np.array([0, 1, 2, 3, 4])
>>> flag = np.ma.masked_array([True, False, False, True, True],
                              [False, True, False, False, True])

>>> arr[flag])
array([0, 3, 4])

Один из способов сделать это - ответ Джедвардса.

Но я думаю, что маскированные массивы следует избегать для пометки данных, это не дает достаточного понимания.

В случае массива флагов, который используется для доступа к определенному типу данных, маскированные значения должны быть установлены в False. Например, если вы хотите интерполировать данные, которые не помечены.

Если массив флагов используется для маскирования определенного типа данных, маскируемые значения должны быть установлены в True.

Автор: JoVe Размещён: 19.07.2016 12:29

1 плюс

131011 Репутация автора

Решение

Если я восстановлю ваши массивы с:

In [28]: d=np.ma.masked_equal([7,0,7,1,8,0,1,1,0,0,3,0,0,3,0],0)

In [29]: f=np.ma.MaskedArray([True,False,False,True, False,False,False,False,True,True,True,True,True,True,True],[False, False, False, False, True, True, True, False, True, False, True, True, True, True, False])

In [30]: d
Out[30]: 
masked_array(data = [7 -- 7 1 8 -- 1 1 -- -- 3 -- -- 3 --],
             mask = [False  True False False False  True False False  True  True False  True
  True False  True],
       fill_value = 0)

In [31]: f
Out[31]: 
masked_array(data = [True False False True -- -- -- False -- True -- -- -- -- True],
             mask = [False False False False  True  True  True False  True False  True  True
  True  True False],
       fill_value = True)

Маскированные дисплеи совпадают, но я предполагаю, что это замаскированные значения.

In [32]: d[f]
Out[32]: 
masked_array(data = [7 1 -- -- 3 -- -- 3 --],
             mask = [False False  True  True False  True  True False  True],
       fill_value = 0)

In [33]: d[f.data]
Out[33]: 
masked_array(data = [7 1 -- -- 3 -- -- 3 --],
             mask = [False False  True  True False  True  True False  True],
       fill_value = 0)

Индексирование - fэто то же самое, что индексирование с его dataатрибутом. Его маска ничего не делает. Очевидно, мои маскированные значения отличаются от ваших.

Но если я индексирую filledмассив, я получаю нужный массив:

In [34]: d[f.filled(False)]
Out[34]: 
masked_array(data = [7 1 -- --],
             mask = [False False  True  True],
       fill_value = 0)

filledв np.maкоде используется много , с разными значениями заполнения в зависимости от npоперации (например, 0 для суммы v 1 для продукта). Маскированные массивы обычно не перебирают свои значения, пропуская маскированные; вместо этого они преобразуют замаскированные значения в безобидные значения и используют обычные операции с пустыми значениями. Другая стратегия - удалить маскированные значения с помощью compressed.

indices = np.where(flag.filled(False)) упоминается в другом ответе, но простая логическая форма работает так же хорошо.

Маскарад массив имеет dataи maskатрибут. Маскировка не меняет dataзначения напрямую. Эта задача оставлена ​​таким методам, как filled.

Автор: hpaulj Размещён: 19.07.2016 08:06
Вопросы из категории :
32x32