Jak mogę usunąć Nan z listy Python / NumPy

89

Mam listę zawierającą wartości, jedna z wartości, które otrzymałem, to „nan”

countries= [nan, 'USA', 'UK', 'France']

Próbowałem go usunąć, ale za każdym razem pojawia się błąd

cleanedList = [x for x in countries if (math.isnan(x) == True)]
TypeError: a float is required

Kiedy próbowałem tego:

cleanedList = cities[np.logical_not(np.isnan(countries))]
cleanedList = cities[~np.isnan(countries)]

TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
user3001937
źródło
4
To wygląda jak łańcuch "nan", a nie rzeczywista wartość NaN.
BrenBarn,
1
tak, to jest ciąg. [x dla x w krajach, jeśli x! = 'nan']
MarshalSHI,
4
if condition == Truejest niepotrzebne, zawsze możesz to zrobić if condition.
przypomnij sobie
Żadne z dotychczasowych rozwiązań nie jest satysfakcjonujące. Mam ten sam problem. Zasadniczo nie działa w przypadku ciągów. Dlatego w twoim przypadku np.isnan('USA')wyśle ​​ten sam komunikat o błędzie. Jeśli znajdę jakieś rozwiązanie, wrzucę je.
Yohan Obadia

Odpowiedzi:

127

Pytanie się zmieniło, więc odpowiedź:

Ciągów nie można testować przy użyciu, math.isnanponieważ wymaga to argumentu zmiennoprzecinkowego. Na swojej countriesliście masz liczby zmiennoprzecinkowe i łańcuchy.

W Twoim przypadku powinny wystarczyć:

cleanedList = [x for x in countries if str(x) != 'nan']

Stara odpowiedź

Na twojej countriesliście literał 'nan'to łańcuch, a nie liczba zmiennoprzecinkowa w Pythonie, nanktóra jest równoważna z:

float('NaN')

W Twoim przypadku powinny wystarczyć:

cleanedList = [x for x in countries if x != 'nan']
Społeczność
źródło
1
Logicznie rzecz biorąc, to, co mówisz, jest prawdą. Ale ze mną nie wyszło.
user3001937
Wtedy problem tkwi w innym obszarze, tablica, którą podałeś, to ciągi znaków, które math.isnannaturalnie przejdą przez błędy.
Tak ! kiedy
drukuję
1
@ user3001937 Zaktualizowałem odpowiedź na podstawie nowych informacji
2
zhangxaochen: to nie jest sznur, to pływak. Przyjrzyj się uważnie zaktualizowanej odpowiedzi; Lego Stormtroopr jest konwertowane xna ciąg, więc możesz to porównać. nanzawsze zwraca wartość false dla ==, nawet w porównaniu z nan, więc jest to najłatwiejszy sposób porównania.
Bezpłatna Monica Cellio
17

Problem wynika z tego, że np.isnan()nie obsługuje poprawnie wartości łańcuchowych. Na przykład, jeśli:

np.isnan("A")
TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''

Jednak wersja pandy pd.isnull()działa dla wartości liczbowych i ciągów:

pd.isnull("A")
> False

pd.isnull(3)
> False

pd.isnull(np.nan)
> True

pd.isnull(None)
> True
Yohan Obadia
źródło
14

Na przykładzie, w którym ...

countries= [nan, 'USA', 'UK', 'France']

Ponieważ nan nie jest równe nan (nan! = Nan), a kraje [0] = nan, należy przestrzegać następujących zasad:

countries[0] == countries[0]
False

Jednak,

countries[1] == countries[1]
True
countries[2] == countries[2]
True
countries[3] == countries[3]
True

Dlatego powinno działać:

cleanedList = [x for x in countries if x == x]
vlmercado
źródło
1
To jedyna odpowiedź, która działa, gdy na liście ciągów znajduje się liczba zmiennoprzecinkowa („nan”)
kmundnic
13
import numpy as np

mylist = [3, 4, 5, np.nan]
l = [x for x in mylist if ~np.isnan(x)]

Powinno to usunąć wszystkie NaN. Oczywiście zakładam, że nie jest to tutaj ciąg znaków, ale rzeczywisty NaN ( np.nan).

Ajay Shah
źródło
1
To daje mi błąd: TypeError: ufunc 'isnan' nie jest obsługiwany dla typów danych wejściowych, a wejścia nie mogły być bezpiecznie przekształcone do żadnego obsługiwanego typu zgodnie z regułą rzutowania
``
1
Dlaczego nie po prostu x[~ np.isnan(x)]:? W numpy nie jest potrzebne rozumienie listy. Oczywiście zakładam, że x jest tablicą numpy.
bue
Założyłem, że x nie będzie tablicą numpy, jak sugerowało pytanie.
Ajay Shah
Oczekuje unoszenia się. Nie będzie działać na listach z ciągami znaków @ZakKeirn
Shirish Bajpai
5

użyj numpy fantazyjnego indeksowania :

In [29]: countries=np.asarray(countries)

In [30]: countries[countries!='nan']
Out[30]: 
array(['USA', 'UK', 'France'], 
      dtype='|S6')
zhangxaochen
źródło
5

jeśli sprawdzisz typ elementu

type(countries[1])

wynik będzie <class float> taki, że możesz użyć następującego kodu:

[i for i in countries if type(i) is not float]
Beyran11
źródło
4

Lubię usuwać brakujące wartości z takiej listy:

list_no_nan = [x for x in list_with_nan if pd.notnull(x)]
Aaron England
źródło
1

W twoim przykładzie 'nan'jest to ciąg, więc zamiast używać isnan()po prostu sprawdź ciąg

lubię to:

cleanedList = [x for x in countries if x != 'nan']
Seryjny
źródło
0

Innym sposobem na zrobienie tego byłoby użycie takiego filtra :

countries = list(filter(lambda x: str(x) != 'nan', countries))
Sorin Dragan
źródło
-1

Zauważyłem, że na przykład Pandy zwracają „nan” dla pustych wartości. Ponieważ nie jest to ciąg, musisz go przekonwertować na jeden, aby go dopasować. Na przykład:

ulist = df.column1.unique() #create a list from a column with Pandas which 
for loc in ulist:
    loc = str(loc)   #here 'nan' is converted to a string to compare with if
    if loc != 'nan':
        print(loc)
wróbel
źródło