Удаление значений Nan из массива


223

Я хочу выяснить, как удалить значения Nan из моего массива. Мой массив выглядит примерно так:

x = [1400, 1500, 1600, nan, nan, nan ,1700] #Not in this exact configuration

Как я могу удалить nanзначения из x?


Для ясности, под «удалить NaN» вы подразумеваете отфильтровать только подмножество ненулевых значений . Не «заполняйте NaN каким-либо значением (ноль, константа, среднее значение, медиана и т. Д.)»
smci

Ответы:


362

Если вы используете NumPy для своих массивов, вы также можете использовать

x = x[numpy.logical_not(numpy.isnan(x))]

эквивалентно

x = x[~numpy.isnan(x)]

[Спасибо chbrown за добавленную стенографию]

объяснение

Внутренняя функция numpy.isnanвозвращает логический / логический массив, значение которого Trueвезде xне является числом. Поскольку мы хотим обратного, мы используем оператор логического not, ~чтобы получить массив с Trues везде, который x является допустимым числом.

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


31
Илиx = x[numpy.isfinite(x)]
lazy1

14
Или x = x[~numpy.isnan(x)], что эквивалентно первоначальному ответу mutzmatron, но короче. Если вы хотите сохранить свою бесконечность, знайте numpy.isfinite(numpy.inf) == False, конечно, но ~numpy.isnan(numpy.inf) == True.
chbrown

8
Для тех, кто хочет решить эту проблему с помощью ndarray и сохранить размеры, используйте numpy где :np.where(np.isfinite(x), x, 0)
BoltzmannBrain

1
Ошибка типа: в скалярный индекс можно преобразовать только целочисленные скалярные массивы
towry

1
@towry: это происходит потому, что ваши входные данные xне являются массивом. Если вы хотите использовать логический индексирование, он должен быть массив - напримерx = np.array(x)
jmetz

50
filter(lambda v: v==v, x)

работает как для списков, так и для массива numpy, поскольку v! = v только для NaN


5
Хак, но особенно полезен в случае, когда вы фильтруете nans из массива объектов со смешанными типами, таких как строки и nans.
Остин Ричардсон

Очень чистое решение.
Мундра

2
Это может показаться умным, но если затеняет логику и теоретически другие объекты (такие как пользовательские классы) также могут иметь это свойство
Chris_Rands

Также полезно, потому что это должно xбыть указано только один раз, в отличие от решений типа x[~numpy.isnan(x)]. Это удобно, когда xопределяется длинным выражением, и вы не хотите загромождать код, создавая временную переменную для хранения результата этого длинного выражения.
Кристиан О'Рейли

34

Попробуй это:

import math
print [value for value in x if not math.isnan(value)]

Для получения дополнительной информации читайте в Списке понятий .


5
Если вы используете numy, то и мой ответ, и ответ @ lazy1 почти на порядок быстрее, чем понимание списка - решение lazy1 немного быстрее (хотя технически также не будет возвращать значения бесконечности).
Jmetz

Не забывайте скобки :)print ([value for value in x if not math.isnan(value)])
Hyper

Если вы используете numy, как в верхнем ответе, вы можете использовать этот ответ для понимания списка вместе с npпакетом: Итак, возвращает ваш список без nans:[value for value in x if not np.isnan(value)]
yeliabsalohcin


6

Делаем выше:

x = x[~numpy.isnan(x)]

или

x = x[numpy.logical_not(numpy.isnan(x))]

Я обнаружил, что сброс к той же самой переменной (x) не удаляет фактические значения nan и должен был использовать другую переменную. Установка его в другую переменную удалила nans. например

y = x[~numpy.isnan(x)]

Это странно; в соответствии с документами , индексация логического массива (что это такое) находится под расширенной индексацией, которая, по-видимому, «всегда возвращает копию данных», поэтому вы должны xперезаписывать новое значение (т. е. без NaNs ...) , Можете ли вы предоставить больше информации о том, почему это может происходить?
Jmetz

5

Как показали другие

x[~numpy.isnan(x)]

работает. Но он выдаст ошибку, если numpy dtype не является собственным типом данных, например, если это объект. В этом случае вы можете использовать панд.

x[~pandas.isna(x)] or x[~pandas.isnull(x)]

4

Общепринятый ответ меняет форму для 2d массивов. Я представляю решение здесь, используя функциональность Pandas dropna () . Работает для 1D и 2D массивов. В 2D-случае вы можете выбрать погоду, чтобы удалить строку или столбец, содержащий np.nan.

import pandas as pd
import numpy as np

def dropna(arr, *args, **kwarg):
    assert isinstance(arr, np.ndarray)
    dropped=pd.DataFrame(arr).dropna(*args, **kwarg).values
    if arr.ndim==1:
        dropped=dropped.flatten()
    return dropped

x = np.array([1400, 1500, 1600, np.nan, np.nan, np.nan ,1700])
y = np.array([[1400, 1500, 1600], [np.nan, 0, np.nan] ,[1700,1800,np.nan]] )


print('='*20+' 1D Case: ' +'='*20+'\nInput:\n',x,sep='')
print('\ndropna:\n',dropna(x),sep='')

print('\n\n'+'='*20+' 2D Case: ' +'='*20+'\nInput:\n',y,sep='')
print('\ndropna (rows):\n',dropna(y),sep='')
print('\ndropna (columns):\n',dropna(y,axis=1),sep='')

print('\n\n'+'='*20+' x[np.logical_not(np.isnan(x))] for 2D: ' +'='*20+'\nInput:\n',y,sep='')
print('\ndropna:\n',x[np.logical_not(np.isnan(x))],sep='')

Результат:

==================== 1D Case: ====================
Input:
[1400. 1500. 1600.   nan   nan   nan 1700.]

dropna:
[1400. 1500. 1600. 1700.]


==================== 2D Case: ====================
Input:
[[1400. 1500. 1600.]
 [  nan    0.   nan]
 [1700. 1800.   nan]]

dropna (rows):
[[1400. 1500. 1600.]]

dropna (columns):
[[1500.]
 [   0.]
 [1800.]]


==================== x[np.logical_not(np.isnan(x))] for 2D: ====================
Input:
[[1400. 1500. 1600.]
 [  nan    0.   nan]
 [1700. 1800.   nan]]

dropna:
[1400. 1500. 1600. 1700.]

3

Если вы используете numpy

# first get the indices where the values are finite
ii = np.isfinite(x)

# second get the values
x = x[ii]

1

Самый простой способ это:

numpy.nan_to_num(x)

Документация: https://docs.scipy.org/doc/numpy/reference/generated/numpy.nan_to_num.html.


2
Добро пожаловать на ТАК! Решение, которое вы предлагаете, не отвечает на проблему: ваше решение заменяет NaNs большим числом, в то время как OP попросил полностью удалить элементы.
Пьер Паоло

0

Это мой подход к фильтрации ndarray "X" для NaNs и Infs,

Я создаю карту строк без каких- NaNлибо infследующих действий :

idx = np.where((np.isnan(X)==False) & (np.isinf(X)==False))

idx - это кортеж Его второй столбец ( idx[1]) содержит индексы массива, где ни NaN, ни inf не найдены в строке.

Затем:

filtered_X = X[idx[1]]

filtered_Xсодержит X без NaN ни inf.


0

@ jmetz's answer вероятно, тот, который нужен большинству людей; однако он дает одномерный массив, например, делает невозможным удаление целых строк или столбцов в матрицах.

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

x = x[~numpy.isnan(x).any(axis=1)]

Подробнее смотрите здесь .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.