update1 2020-01-25: Tippfehlerbehebung IEEE745
-> IEEE 754
In [1]: from datetime import datetime
In [2]: (datetime(2020, 1, 11) - datetime(2018, 12, 13)).days
Out[2]: 394
Ich werde den Umgang mit Nan in Python erklären. Im Folgenden wird die Notation von nan als Konzept als NaN bezeichnet.
Disclaimer: Dieser Beitrag ist für justInCase Adventskalender 2018 und wurde nach einem Zeitraum von ca. 400 Tagen veröffentlicht, jedoch aufgrund der Laufzeit, des Inhalts Erfüllt nicht.
Verifizierungsumgebung wird am Ende beschrieben
Weitere Informationen finden Sie im vorherigen Artikel Was ist NaN? NaN Zoya (R).
Beachten Sie, dass sich leises NaN in allgemeinen numerischen Operationen ausbreitet. Was sollten Ihrer Meinung nach die folgenden beiden Werte zurückgeben? Tatsächlich ändert sich die Behandlung von NaN bei min und max zwischen IEEE 754-2008 und IEEE 754-2019. Die Erklärung von ist in einem anderen Artikel.
min(1.0, float('nan'))
max(1.0, float('nan'))
Es gibt kein Sprachliteral. Wenn Sie "float (" nan ")" oder "numpy" aufrufen, für das kein Modulaufruf erforderlich ist, wird "np.nan" häufig verwendet.
import math
import decimal
import numpy as np
import pandas as pd
float('nan')
math.nan
0.0 * math.inf
math.inf / math.inf
# 0.0/0.0 ZeroDivisionError in Python. C, R,Viele Sprachen wie Julia geben NaN zurück
np.nan
np.core.numeric.NaN
pd.np.nan
Alle Float-Objekte. Die Objekte, auf die numpy`` pandas
verweist, sind dieselben, obwohl sie keine Singleton-Objekte sind.
nans = [float('nan'), math.nan, 0 * math.inf, math.inf / math.inf, np.nan, np.core.numeric.NaN, pd.np.nan]
import pprint
pprint.pprint([(type(n), id(n)) for n in nans])
# [(<class 'float'>, 4544450768),
# (<class 'float'>, 4321186672),
# (<class 'float'>, 4544450704),
# (<class 'float'>, 4544450832),
# (<class 'float'>, 4320345936),
# (<class 'float'>, 4320345936),
# (<class 'float'>, 4320345936)]
float ('nan')
selbst ist ein unveränderliches Objekt der float-Klasse, also hashbar. Es kann also ein Wörterbuchschlüssel sein, aber seltsamerweise können Sie mehrere Nans hinzufügen. Und wenn Sie den Schlüssel nicht im Voraus an eine Variable binden, können Sie ihn nicht erneut abrufen. Es wird angenommen, dass dies auf die Tatsache zurückzuführen ist, dass alle Ergebnisse des Vergleichsoperators von "NaN" "Falsch" sind, dh "float (" nan ") == float (" nan ")" -> "falsch".
>>> d = {float('nan'): 1, float('nan'): 2, float('nan'): 3}
>>> d
{nan: 1, nan: 2, nan: 3}
>>> d[float('nan')]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: nan
Beachten Sie die Existenz von Objekten mit NaN-ähnlichen Eigenschaften, die keine Float-Klassen sind. Insbesondere sind "pd.NaT" und "np.datetime64 (" NaT ")" verschiedene Klassen.
decimal.Decimal('nan')
pd.NaT
np.datetime64("NaT")
# >>> type(decimal.Decimal('nan'))
# <class 'decimal.Decimal'>
# >>> type(pd.NaT)
# <class 'pandas._libs.tslibs.nattype.NaTType'>
# >>> type(np.datetime64("NaT"))
# <class 'numpy.datetime64'>
Daher sind die folgenden Vorsichtsmaßnahmen erforderlich, wenn Sie "np.isnat" verwenden.
>>> np.isnat(pd.NaT)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ufunc 'isnat' is only defined for datetime and timedelta.
>>> np.isnat(np.datetime64("NaT"))
True
math.isnan
np.isnan
pd.isna
Die aktuelle Situation von math.isnan
ist hier.
https://github.com/python/cpython/blob/e42b705188271da108de42b55d9344642170aa2b/Include/pymath.h#L88-L103
https://github.com/python/cpython/blob/34fd4c20198dea6ab2fe8dc6d32d744d9bde868d/Lib/_pydecimal.py#L713-L726
/* Py_IS_NAN(X)
* Return 1 if float or double arg is a NaN, else 0.
* Caution:
* X is evaluated more than once.
* This may not work on all platforms. Each platform has *some*
* way to spell this, though -- override in pyconfig.h if you have
* a platform where it doesn't work.
* Note: PC/pyconfig.h defines Py_IS_NAN as _isnan
*/
#ifndef Py_IS_NAN
#if defined HAVE_DECL_ISNAN && HAVE_DECL_ISNAN == 1
#define Py_IS_NAN(X) isnan(X)
#else
#define Py_IS_NAN(X) ((X) != (X))
#endif
#endif
def _isnan(self):
"""Returns whether the number is not actually one.
0 if a number
1 if NaN
2 if sNaN
"""
if self._is_special:
exp = self._exp
if exp == 'n':
return 1
elif exp == 'N':
return 2
return 0
Beachten Sie, dass die Pandas-Methode "isna" (und "isnull") "True" als fehlenden Wert nicht nur für "float nan", sondern auch für "None" und "pd.NaT" zurückgibt.
Wenn pandas.options.mode.use_inf_as_na = True
, gibt es einen Tipp, dass np.inf
auch als fehlender Wert beurteilt wird.
>>> pd.isna(math.nan)
True
>>> pd.isna(None)
True
>>> pd.isna(math.inf)
False
>>> pandas.options.mode.use_inf_as_na = True
>>> pd.isna(math.inf)
True
Die direkte Methode des Pandas-Objekts verwendet ein skalares oder Array-ähnliches Argument, und der Rückgabewert ist ein Bool mit der gleichen Größe wie das Argument. Andererseits ist die direkte Methode von pd.DataFrame ein DataFrame sowohl für das Argument als auch für den Rückgabewert.
pd.isna # for scalar or array-like
pd.DataFrame.isna # for DataFrame
Das Array-ähnliche Objekt bezieht sich speziell auf das folgende Objekt. (https://github.com/pandas-dev/pandas/blob/v0.25.3/pandas/core/dtypes/missing.py#L136-L147)
ABCSeries,
np.ndarray,
ABCIndexClass,
ABCExtensionArray,
ABCDatetimeArray,
ABCTimedeltaArray,
Es sollte beachtet werden, dass entweder für "pd.isna" oder "pd.isnull" genau das gleiche ist (eine unter dem Gesichtspunkt der Lesbarkeit einheitliche Verwendung ist wünschenswert).
# https://github.com/pandas-dev/pandas/blob/v0.25.3/pandas/core/dtypes/missing.py#L125
>>> id(pd.isnull)
4770964688
>>> id(pd.isna)
4770964688
Wenn Sie nicht auf einen unerwarteten Fehler stoßen möchten, ist "pd.isna" sicher, aber seien Sie vorsichtig, da es nach dem Urteil "Decimal (" nan ")" ausläuft.
math.nan | decimal.Decimal('nan') | np.datetime64("NaT") | pd.NaT | math.inf | None | |
---|---|---|---|---|---|---|
math.isnan | True | True | error | error | False | error |
decimal.Decimal.is_nan | error | True | error | error | error | error |
np.isnan | True | error | True | error | False | error |
pd.isna | True | False | True | True | False | True |
np.isnat | error | error | True | error | error | error |
Überprüfen Sie den binären Ausdruck. Sie können sehen, dass es ruhig NaN ist.
>>> import struct
>>> xs = struct.pack('>d', math.nan)
>>> xs
b'\x7f\xf8\x00\x00\x00\x00\x00\x00'
>>> xn = struct.unpack('>Q', xs)[0]
>>> xn
9221120237041090560
>>> bin(xn)
'0b111111111111000000000000000000000000000000000000000000000000000'
--NaN in Python folgt NaN in IEEE754, aber hier und da gibt es einige süchtig machende Punkte. --Beachten Sie die Existenz von "Decimal (" nan ")", "pd.NaT", "numpy.datetime64 (" NaT ")", die nicht float nan sind.
pd.NA
von pandas 1.0.0 eingeführt. Es wird in Zukunft verwendet, um "pd.NA" anstelle von nan als fehlenden Wert zu verwenden. Ich werde darüber in einem anderen Artikel schreiben.Schließlich Wenn Sie diese Art von verrückter Geschichte lieben, besuchen Sie uns bitte bei justInCase. https://www.wantedly.com/companies/justincase
das ist alles
$ uname -a
Darwin MacBook-Pro-3.local 18.7.0 Darwin Kernel Version 18.7.0: Sat Oct 12 00:02:19 PDT 2019; root:xnu-4903.278.12~1/RELEASE_X86_64 x86_64
$ python
Python 3.7.4 (default, Nov 17 2019, 08:06:12)
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
$ pip list | grep -e numpy -e pandas
numpy 1.18.0
pandas 0.25.3
Recommended Posts