Удаление пар элементов из массивов numpy, которые являются NaN (или другое значение) в Python
У меня есть массив с двумя столбцами в numpy. Например:
a = array([[1, 5, nan, 6],
[10, 6, 6, nan]])
a = transpose(a)
Я хочу эффективно перебирать два столбца: [:, 0] и [:, 1] и удалять любые пары, которые удовлетворяют определенному условию, в этом случае, если они являются NaN. Очевидным способом я могу подумать:
new_a = []
for val1, val2 in a:
if val2 == nan or val2 == nan:
new_a.append([val1, val2])
Но это кажется неуклюжим. Какой способ pythonic numpy сделать это?
спасибо.
Ответы
Ответ 1
Если вы хотите брать только строки, у которых нет NAN, это выражение, которое вам нужно:
>>> import numpy as np
>>> a[~np.isnan(a).any(1)]
array([[ 1., 10.],
[ 5., 6.]])
Если вам нужны строки, которые не имеют определенного числа среди своих элементов, например. 5:
>>> a[~(a == 5).any(1)]
array([[ 1., 10.],
[ NaN, 6.],
[ 6., NaN]])
Последнее, очевидно, эквивалентно
>>> a[(a != 5).all(1)]
array([[ 1., 10.],
[ NaN, 6.],
[ 6., NaN]])
Объяснение:
Пусть сначала создайте свой пример ввода
>>> import numpy as np
>>> a = np.array([[1, 5, np.nan, 6],
... [10, 6, 6, np.nan]]).transpose()
>>> a
array([[ 1., 10.],
[ 5., 6.],
[ NaN, 6.],
[ 6., NaN]])
Это определяет, какие элементы являются NAN
>>> np.isnan(a)
array([[False, False],
[False, False],
[ True, False],
[False, True]], dtype=bool)
Это указывает, какие строки имеют любой элемент True
>>> np.isnan(a).any(1)
array([False, False, True, True], dtype=bool)
Поскольку мы не хотим этого, мы отрицаем последнее выражение:
>>> ~np.isnan(a).any(1)
array([ True, True, False, False], dtype=bool)
И, наконец, мы используем логический массив для выбора нужных строк:
>>> a[~np.isnan(a).any(1)]
array([[ 1., 10.],
[ 5., 6.]])
Ответ 2
Вы можете преобразовать массив в массив masked array и использовать compress_rows
:
import numpy as np
a = np.array([[1, 5, np.nan, 6],
[10, 6, 6, np.nan]])
a = np.transpose(a)
print(a)
# [[ 1. 10.]
# [ 5. 6.]
# [ NaN 6.]
# [ 6. NaN]]
b=np.ma.compress_rows(np.ma.fix_invalid(a))
print(b)
# [[ 1. 10.]
# [ 5. 6.]]
Ответ 3
Не отвлекать от ответа ig0774, что является вполне допустимым и Pythonic, и на самом деле является обычным способом выполнения этих действий на простом Python, но: numpy поддерживает булевскую систему индексирования, которая также может выполнять эту работу.
new_a = a[(a==a).all(1)]
Я не уверен, что путь был бы более эффективным (или быстрее выполняться).
Если вы хотите использовать другое условие для выбора строк, это должно быть изменено и точно зависит от условия. Если это может быть оценено для каждого элемента массива независимо, вы можете просто заменить a==a
на соответствующий тест, например, чтобы устранить все строки с номерами более 100, которые вы могли бы сделать
new_a = a[(a<=100).all(1)]
Но если вы пытаетесь сделать что-то фантастическое, которое включает в себя все элементы в строке (например, исключение всех строк, сумма которых превышает 100), это может быть сложнее. Если это случай, я могу попытаться отредактировать в более конкретном ответе, если вы хотите поделиться своим точным условием.
Ответ 4
Я думаю, что список понятий должен сделать это. Например.
new_a = [(val1, val2) for (val1, val2) in a if math.isnan(val1) or math.isnan(val2)]