Удаление пар элементов из массивов 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)]