update1 25/01/2020: correction de faute de frappe ʻIEEE745-> ʻIEEE 754
In [1]: from datetime import datetime
In [2]: (datetime(2020, 1, 11) - datetime(2018, 12, 13)).days
Out[2]: 394
Je vais vous expliquer la manipulation de nan en Python. Dans ce qui suit, la notation de nan en tant que concept est appelée NaN.
Disclaimer: Ce message est pour justInCase Advent Calendar 2018 et a été publié après une période d'environ 400 jours, mais en raison de la période de maturité, le contenu N'est pas satisfaisant.
--NaN en Python suit NaN dans IEEE 754, mais il y a quelques points addictifs ici et là.
Decimal ('nan')
, pd.NaT
,numpy.datetime64 ('NaT')
, qui ne sont pas float nan.
--L'objet nan et math.nan qui peuvent être appelés à partir des modules numpy et pandas sont identiques. Vous pouvez utiliser n'importe lequel d'entre eux. (Mais il vaut mieux unifier du point de vue de la lisibilité)pd.NA
sera introduit à partir de pandas 1.0.0. Il est souhaitable d'utiliser «pd.NA» au lieu de nan comme valeur manquante à l'avenir. J'écrirai à ce sujet dans un autre article.[L'environnement de vérification est décrit à la fin](# Environnement de vérification)
Veuillez vous référer à l'article précédent Qu'est-ce que NaN? NaN Zoya (R).
Notez que NaN silencieux se propage dans les opérations numériques générales, mais que pensez-vous que les deux valeurs suivantes devraient renvoyer? En fait, le traitement du NaN aux valeurs min et max change entre IEEE 754-2008 et IEEE 754-2019. L'explication de est dans un autre article.
min(1.0, float('nan'))
max(1.0, float('nan'))
Il n'y a pas de langage littéral. Si vous appelez float ('nan')
ou numpy, ce qui ne nécessite pas d'appel de module, np.nan
a tendance à être beaucoup utilisé.
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 en Python. C, R,De nombreuses langues, comme Julia, renvoient NaN
np.nan
np.core.numeric.NaN
pd.np.nan
Tous les objets flottants. Les objets référencés par «numpy» pandas »sont les mêmes, bien qu'ils ne soient pas des objets singleton.
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')
lui-même est un objet immuable de la classe float, donc hachable. Cela peut donc être une clé de dictionnaire, mais étrangement, cela vous permet d'ajouter plusieurs nans. Et si vous ne liez pas la clé à une variable à l'avance, vous ne pouvez pas la récupérer à nouveau. On pense que cela est dû au fait que tous les résultats de l'opérateur de comparaison de NaN
sont False
, c'est-à-direfloat ('nan') == float ('nan')
-> False
.
>>> 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
Notez l'existence d'objets avec des propriétés de type NaN qui ne sont pas des classes flottantes. En particulier, «pd.NaT» et «np.datetime64 (« NaT »)» sont des classes différentes.
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'>
Par conséquent, les précautions suivantes sont nécessaires lors de l'utilisation de np.isnat
.
>>> 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
La situation actuelle de «math.isnan» est ici. 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
Notez que la méthode «isna» de pandas (et aussi «isnull») renvoie «True» comme valeurs manquantes pour «None» et «pd.NaT» ainsi que «float nan».
Si pandas.options.mode.use_inf_as_na = True
, il y a une astuce qui np.inf
est également considérée comme une valeur manquante.
>>> 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
La méthode directe de l'objet pandas prend comme argument un scalaire ou un tableau et la valeur de retour est un booléen de la même taille que l'argument. D'autre part, la méthode directe de pd.DataFrame est un DataFrame pour l'argument et la valeur de retour.
pd.isna # for scalar or array-like
pd.DataFrame.isna # for DataFrame
L'objet de type tableau fait spécifiquement référence à l'objet suivant. (https://github.com/pandas-dev/pandas/blob/v0.25.3/pandas/core/dtypes/missing.py#L136-L147)
ABCSeries,
np.ndarray,
ABCIndexClass,
ABCExtensionArray,
ABCDatetimeArray,
ABCTimedeltaArray,
Il convient de noter, peut être soit pour «pd.isna» et «pd.isnull» est exactement le même (une utilisation unifiée du point de vue de la lisibilité est souhaitable).
# https://github.com/pandas-dev/pandas/blob/v0.25.3/pandas/core/dtypes/missing.py#L125
>>> id(pd.isnull)
4770964688
>>> id(pd.isna)
4770964688
Si vous ne voulez pas rencontrer d'erreur inattendue, pd.isna
est sûr, mais soyez prudent car il se fuira au jugement de Decimal ('nan')
.
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 |
Confirmez l'expression binaire. Vous pouvez voir que c'est NaN calme.
>>> 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 en Python suit NaN dans IEEE754, mais il y a quelques points addictifs ici et là.
Decimal ('nan')
, pd.NaT
,numpy.datetime64 ('NaT')
, qui ne sont pas float nan.
--L'objet nan et math.nan qui peuvent être appelés à partir des modules numpy et pandas sont identiques. Vous pouvez utiliser n'importe lequel d'entre eux. (Mais il vaut mieux unifier du point de vue de la lisibilité)pd.NA
de pandas 1.0.0. Il sera utilisé à l'avenir pour utiliser pd.NA
au lieu de nan comme valeur manquante. J'écrirai à ce sujet dans un autre article.finalement Si vous aimez ce genre d'histoire maniaque, venez nous rendre visite à justInCase. https://www.wantedly.com/companies/justincase
c'est tout
$ 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