сравнение неравенства массива numpy с nan со скаляром

Я пытаюсь установить элементы массива ниже порогового значения nan. Это часть процесса ОК/КК, и входящие данные могут уже иметь слоты, которые являются нан.

Так, например, мой порог может быть -1000, и, следовательно, я хотел бы установить -3000 на nan в следующем массиве

x = np.array([np.nan,1.,2.,-3000.,np.nan,5.])

Это следующее:

x[x < -1000.] = np.nan

производит правильное поведение, но также и RuntimeWarning, но накладные расходы на отключение предупреждения

warnings.filterwarnings("ignore")
...
warnints.resetwarnings()

довольно тяжелый и потенциально немного небезопасный.

Попытка проиндексировать дважды с причудливой индексацией следующим образом не дает никакого эффекта:

nonan = np.where(~np.isnan(x))[0]
x[nonan][x[nonan] < -1000.] = np.nan

Я предполагаю, что это связано с тем, что копия создается из-за целочисленного индекса или использования двойного индексирования.

У кого-нибудь есть относительно простое решение? Было бы неплохо использовать в процессе маскированный массив, но конечным продуктом должен быть ndarray, и я не могу вводить новые зависимости. Спасибо.


person Eli S    schedule 17.08.2014    source источник


Ответы (5)


Любое сравнение (кроме !=) значения NaN со значением, отличным от NaN, всегда будет возвращать False:

>>> x < -1000
array([False, False, False,  True, False, False], dtype=bool)

Таким образом, вы можете просто игнорировать тот факт, что в вашем массиве уже есть NaN, и сделать:

>>> x[x < -1000] = np.nan
>>> x
array([ nan,   1.,   2.,  nan,  nan,   5.])

РЕДАКТИРОВАТЬ Я не вижу никаких предупреждений, когда выполняю приведенное выше, но если вам действительно нужно держаться подальше от NaN, вы можете сделать что-то вроде:

mask = ~np.isnan(x)
mask[mask] &= x[mask] < -1000
x[mask] = np.nan
person Jaime    schedule 17.08.2014
comment
Я согласен с логикой, и я рад, что вы указали, что это не обычная проблема «нан-не-равно-нан». Проблема для меня, когда я пытаюсь это сделать, заключается в том, что он выдает предупреждение во время выполнения. Один из вариантов — импортировать предупреждения и перехватывать их, но это требует большого количества ввода и накладных расходов. Надеюсь на экономичный вариант. - person Eli S; 18.08.2014
comment
Кто-нибудь знает, почему np.nan вообще допускает сравнение (всегда оценивая False, а не вызывая TypeError или что-то в этом роде, как None < x)? Это вызывает всевозможные головные боли, если некоторые nans убегают из массивов numpy в обычные переменные Python, и вы начинаете использовать их с обычными методами и выражениями Python. - person Bill; 09.06.2019
comment
Это то, что NaN должен делать в соответствии с IEEE 754, вы получите такое же поведение, например. из float('nan'): en.wikipedia.org/wiki/NaN#Comparison_with_NaN - person Jaime; 12.06.2019

Один из вариантов — отключить соответствующие предупреждения с помощью numpy.errstate:

with numpy.errstate(invalid='ignore'):
    ...

Чтобы отключить соответствующие предупреждения глобально, используйте numpy.seterr.

person user2357112 supports Monica    schedule 18.08.2014
comment
Спасибо. Я думаю, что может быть более безопасный способ использования фильтра предупреждений в предупреждениях: - person Eli S; 18.08.2014
comment
warnings.filterwarnings(игнорировать), а потом - person Eli S; 18.08.2014
comment
Это тоже глобальное изменение... возможно, довольно безопасное, если сбросить сразу. Однако, как намекает моя записка Джейми, я знал о методе диаблинга. Я искал что-то без этих накладных расходов. Однако я думаю, что ваш ответ может помочь многим людям. - person Eli S; 18.08.2014
comment
Вы можете использовать errstate для предпочтения. - person Mad Physicist; 08.08.2016

np.less() имеет аргумент where, который определяет, где будет применяться операция. Итак, вы можете сделать:

x[np.less(x, -1000., where=~np.isnan(x))] = np.nan
person mikewatt    schedule 07.02.2019
comment
Вы можете просто использовать where=np.isfinite(x) - person Chris; 16.08.2020

Лично я игнорирую предупреждения с использованием диспетчера контекста np.errstate в уже данном ответе, поскольку ясность кода стоит дополнительного времени, но вот альтернатива.

# given
x = np.array([np.nan, 1., 2., -3000., np.nan, 5.])

# apply NaNs as desired
mask = np.zeros(x.shape, dtype=bool)
np.less(x, -1000, out=mask, where=~np.isnan(x))
x[mask] = np.nan

# expected output and comparison
y = np.array([np.nan, 1., 2., np.nan, np.nan, 5.])
assert np.allclose(x, y, rtol=0., atol=1e-14, equal_nan=True)

numpy less ufunc принимает необязательный аргумент where, и оценивает его только там, где оно истинно, в отличие от функции np.where, которая оценивает оба варианта, а затем выбирает соответствующий. Затем вы устанавливаете желаемый вывод, если он не соответствует действительности, используя аргумент out.

person DStauffman    schedule 01.11.2017
comment
Обратите внимание, что для этого требуется аргумент ключевого слова out=mask. В противном случае np.less вернет True в пропущенной позиции. - person Will Holmgren; 15.02.2018

Немного поздно, но я бы сделал так:

x = np.array([np.nan,1.,2.,-3000.,np.nan,5.]) 

igood=np.where(~np.isnan(x))[0]
x[igood[x[igood]<-1000.]]=np.nan
person Vincenzooo    schedule 12.09.2018