Przypisywanie zmiennej NaN w Pythonie bez numpy

103

Większość języków ma stałą NaN, której można użyć do przypisania zmiennej wartości NaN. Czy Python może to zrobić bez używania numpy?

zelinka
źródło
1
C, C ++, java, C #, ocaml, jest częścią wielu języków.
zelinka
2
NaN w C jest NAN; jest to stała zdefiniowana w math.hC99. (Uważam, że najnowszą znormalizowaną wersję języka można nazwać tym językiem. Zatem „C” to C11.) (Patrz stackoverflow.com/questions/1923837/how-to-use-nan-and-inf-in -c ); w C ++ jest NANteż, jest też nan(), nanf()i nanl()chociaż jestem nieco mniej pewny tego, co robią. double.NaNw Javie, Double.NaNw C #…
Thanatos

Odpowiedzi:

169

Tak - użyj math.nan.

>>> from math import nan
>>> print(nan)
nan
>>> print(nan + 2)
nan
>>> nan == nan
False
>>> import math
>>> math.isnan(nan)
True

Przed Pythonem 3.5 można było używać float("nan") (bez rozróżniania wielkości liter).

Zauważ, że sprawdzenie, czy dwie rzeczy, które są NaN są sobie równe, zawsze zwróci fałsz. Dzieje się tak po części dlatego, że o dwóch rzeczach, które „nie są liczbą”, nie można (ściśle rzecz biorąc) powiedzieć, że są sobie równe - zobacz: Jakie jest uzasadnienie dla wszystkich porównań zwracających fałsz dla wartości NaN IEEE754?aby uzyskać więcej szczegółów i informacji.

Zamiast tego użyj math.isnan(...) jeśli chcesz określić, czy wartość to NaN, czy nie.

Ponadto dokładna semantyka ==operacji na wartości NaN może powodować subtelne problemy podczas próby przechowywania NaN wewnątrz typów kontenerów, takich jaklist lub dict(lub podczas korzystania z niestandardowych typów kontenerów). Aby uzyskać więcej informacji, zobacz Sprawdzanie obecności NaN w kontenerze .


Możesz również konstruować liczby NaN, używając dziesiętnych znaków Pythona modułu :

>>> from decimal import Decimal
>>> b = Decimal('nan')
>>> print(b)
NaN
>>> print(repr(b))
Decimal('NaN')
>>>
>>> Decimal(float('nan'))
Decimal('NaN')
>>> 
>>> import math
>>> math.isnan(b)
True

math.isnan(...) będzie również działać z obiektami Decimal.


Jednak nie można konstruować liczb NaN w module ułamków Pythona :

>>> from fractions import Fraction
>>> Fraction('nan')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python35\lib\fractions.py", line 146, in __new__
    numerator)
ValueError: Invalid literal for Fraction: 'nan'
>>>
>>> Fraction(float('nan'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python35\lib\fractions.py", line 130, in __new__
    value = Fraction.from_float(numerator)
  File "C:\Python35\lib\fractions.py", line 214, in from_float
    raise ValueError("Cannot convert %r to %s." % (f, cls.__name__))
ValueError: Cannot convert nan to Fraction.

Nawiasem mówiąc, możesz także zrobić float('Inf'), Decimal('Inf')lub math.inf(3,5+), aby przypisać nieskończone liczby. (A także zobaczmath.isinf(...) )

Jednak robi Fraction('Inf')lubFraction(float('inf')) nie jest dozwolone i spowoduje zgłoszenie wyjątku, podobnie jak NaN.

Jeśli chcesz szybko i łatwo sprawdzić, czy liczba nie jest ani NaN, ani nieskończona, możesz użyć math.isfinite(...)od wersji Python 3.2+.


Jeśli chcesz wykonać podobne sprawdzenia na liczbach zespolonych, cmathmoduł zawiera podobny zestaw funkcji i stałych jak mathmoduł:

Michael0x2a
źródło
2
Zauważ, że użycie float ('nan) jest 3 razy wolniejsze niż użycie np.nan i około 6,5 razy wolniej niż przypisanie nan = float (' nan ') raz, a następnie użycie zmiennej' nan 'dla wszystkich kolejnych przypisań (zgodnie z sugestią abarnerta odpowiedź).
Daniel Goldfarb,
18
nan = float('nan')

A teraz masz stałą, nan .

Możesz w podobny sposób utworzyć wartości NaN dla dziesiętnych.Decimal .:

dnan = Decimal('nan')
abarnert
źródło
Jest to najbardziej wydajna odpowiedź w przypadku wielu przypisań nan: oznacza to, że użyj zmiennej float („nan”) tylko raz, a następnie użyj przypisanej stałej dla wszystkich pozostałych przypisań. Jeśli jednak wykonujesz tylko jedno lub dwa przypisania z sumy nan, to użycie numpy.nan jest najszybsze.
Daniel Goldfarb,
7

Zastosowanie float("nan"):

>>> float("nan")
nan
orlp
źródło
6

Możesz zrobić, float('nan')aby uzyskać NaN.

BrenBarn
źródło
6

Możesz uzyskać NaN z „inf - inf”, a „inf” z liczby większej niż 2e308, więc generalnie użyłem:

>>> inf = 9e999
>>> inf
inf
>>> inf - inf
nan
Junior Polegato
źródło
3
Ta odpowiedź została bezzasadnie odrzucona. Piszę wiele małych testów parsowania w plikach .txt i używam ast.literal_eval, aby uzyskać oczekiwaną część wyjściową. Nie można tam nazwać float („nan”) i ta odpowiedź była dla mnie pomocna.
Vitalik Verhovodov
0

Bardziej spójnym (i mniej nieprzejrzystym) sposobem generowania inf i -inf jest ponowne użycie float ():

>> positive_inf = float('inf')
>> positive_inf
inf
>> negative_inf = float('-inf')
>> negative_inf
-inf

Zauważ, że rozmiar pływaka różni się w zależności od architektury, więc prawdopodobnie najlepiej jest unikać używania magicznych liczb, takich jak 9e999, nawet jeśli to prawdopodobnie zadziała.

import sys
sys.float_info
sys.float_info(max=1.7976931348623157e+308,
               max_exp=1024, max_10_exp=308,
               min=2.2250738585072014e-308, min_exp=-1021,
               min_10_exp=-307, dig=15, mant_dig=53,
               epsilon=2.220446049250313e-16, radix=2, rounds=1)
user3685621
źródło