Видалення нанних значень з масиву


223

Я хочу розібратися, як видалити значення nan зі свого масиву. Мій масив виглядає приблизно так:

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

Як я можу видалити nanзначення з x?


Щоб було зрозуміло, під «видаленням NaNs» ви маєте на увазі відфільтрувати лише підмножину ненульових значень . Не "заповнюйте NaNs деяким значенням (нульовим, постійним, середнім, середнім і т. Д.)"
smci

Відповіді:


362

Якщо ви використовуєте numpy для своїх масивів, ви також можете використовувати

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

Рівнозначно

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

[Завдяки chbrown за додану стенографію]

Пояснення

Внутрішня функція numpy.isnanповертає булевий / логічний масив, який має значення Trueскрізь, яке xне є a-число. Як ми хочемо навпаки, ми використовуємо логічний оператор, ~щоб отримати масив з Trues всюди, що x є дійсним числом.

Нарешті, ми використовуємо цей логічний масив для індексації у вихідний масив x, щоб отримати лише не-NaN-значення.


31
Абоx = x[numpy.isfinite(x)]
lazy1

14
Або x = x[~numpy.isnan(x)], що еквівалентно оригінальній відповіді муцматрона, але коротше. Якщо ви хочете зберегти свої нескінченності навколо, знайте, що numpy.isfinite(numpy.inf) == False, звичайно, але ~numpy.isnan(numpy.inf) == True.
chbrown

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

1
TypeError: лише цілі скалярні масиви можуть бути перетворені в скалярний індекс
буксирування

1
@towry: це відбувається тому, що ваш внесок, а xне масивний масив. Якщо ви хочете використовувати логічну індексацію, це повинен бути масив, наприкладx = np.array(x)
jmetz

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

працює і для списків, і для масиву numpy, оскільки v! = v лише для NaN


5
Хак, але особливо корисний у тому випадку, коли ви фільтруєте нан з масиву об’єктів змішаних типів, таких як струни та нан.
Остін Річардсон

Дуже чистий розчин.
Мондра

2
Це може здатися розумним, але якщо затьмарювати логіку і теоретично інші об'єкти (наприклад, спеціальні класи) також можуть мати це властивість
Chris_Rands

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

34

Спробуйте це:

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

Докладніше читайте у розділі Зрозуміння списку .


5
Якщо ви використовуєте numpy і мою відповідь, і що від @ lazy1 майже на порядок швидше, ніж розуміння списку - рішення lazy1 трохи швидше (хоча технічно також не поверне жодних значень нескінченності).
jmetz

Не забудьте дужки :)print ([value for value in x if not math.isnan(value)])
вперше

Якщо ви використовуєте numpy, як головну відповідь, тоді ви можете використовувати цю відповідь для розуміння списку разом із npпакетом: Тож повертає свій список без нан:[value for value in x if not np.isnan(value)]
yeliabsalohcin

23

Для мене відповідь @jmetz не спрацювала, однак використання pandas isnull () зробив.

x = x[~pd.isnull(x)]

6

Виконайте вище:

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

або

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

Я виявив, що скидання на одну і ту ж змінну (x) не видаляє фактичні значення nan і довелося використовувати іншу змінну. Встановивши його на іншу змінну, вилучили нан. напр

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

Це дивно; згідно з документами , булева індексація масиву (що це таке) перебуває під розширеним індексуванням, яке, мабуть, "завжди повертає копію даних", тому вам слід xперезаписати з новим значенням (тобто без NaNs ...) . Чи можете ви надати більше інформації, чому це може статися?
jmetz

5

Як показали інші

x[~numpy.isnan(x)]

працює. Але це призведе до помилки, якщо numtype dtype не є нативним типом даних, наприклад, якщо він є об'єктом. У такому випадку ви можете використовувати панди.

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

4

Загальноприйнятий відповідь змінює форму для 2d масивів. Я представляю тут рішення, використовуючи функцію Pandas dropna () . Він працює для 1D і 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
Ласкаво просимо до SO! Пропоноване вами рішення не відповідає на проблему: ваше рішення замінює NaNs великою кількістю, тоді як ОП просить повністю видалити елементи.
П’єр Паоло

0

Це мій підхід до фільтрації ndarray "X" для NaNs та infs,

Я створюю карту рядків без будь-якого NaNта будь-якого infнаступного:

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

idx - кортеж. У другому стовпці ( idx[1]) містяться індекси масиву, де в рядку немає NaN, ані інф .

Тоді:

filtered_X = X[idx[1]]

filtered_Xмістить X без NaN nor inf.


0

@ відповідь jmetz - це, мабуть, саме той, хто найбільше потребує; однак він дає одновимірний масив, наприклад робить його непридатним для видалення цілих рядків або стовпців у матрицях.

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

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

Детальніше дивіться тут .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.