удаление пар элементов из числовых массивов, которые имеют NaN (или другое значение) в Python - PullRequest
11 голосов
/ 23 апреля 2010

У меня есть массив с двумя столбцами в NumPy. Например:

a = array([[1, 5, nan, 6],
           [10, 6, 6, nan]])
a = transpose(a)

Я хочу эффективно выполнить итерацию по двум столбцам a [:, 0] и a [:, 1] и удалить все пары, которые удовлетворяют определенному условию, в данном случае, если они являются NaN. Я могу придумать очевидный способ:

new_a = []
for val1, val2 in a:
  if val2 == nan or val2 == nan:
    new_a.append([val1, val2])

Но это кажется неуклюжим. Что это за питонский тупой способ сделать это?

спасибо.

Ответы [ 4 ]

30 голосов
/ 23 апреля 2010

Если вы хотите взять только те строки, которые не имеют 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.]])
3 голосов
/ 23 апреля 2010

Вы можете преобразовать массив в масочный массив и использовать метод 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 голосов
/ 23 апреля 2010

Не отвлекает от ответа ig0774, который является вполне допустимым и Pythonic и фактически является обычным способом сделать все это на простом Python, но: numpy поддерживает систему булевой индексации, которая также может выполнять эту работу.

new_a = a[(a==a).all(1)]

Я не уверен, какой путь будет более эффективным (или более быстрым для выполнения).

Если вы хотите использовать другое условие для выбора строк, это должно быть изменено,и как именно зависит от состояния.Если это что-то, что может быть оценено для каждого элемента массива независимо, вы можете просто заменить a==a на соответствующий тест, например, чтобы исключить все строки с числами больше 100, которые вы могли бы сделать

new_a = a[(a<=100).all(1)]

Ноесли вы пытаетесь сделать что-то необычное, включающее все элементы подряд (например, исключить все строки, сумма которых превышает 100), это может оказаться более сложным.Если это так, я могу попытаться отредактировать более конкретный ответ, если вы хотите поделиться своим точным состоянием.

2 голосов
/ 23 апреля 2010

Я думаю список понимания должен сделать это. Например.,

new_a = [(val1, val2) for (val1, val2) in a if math.isnan(val1) or math.isnan(val2)]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...