You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Previously, when dealing with a nullable dtype (e.g. ``Float64Dtype`` or ``int64[pyarrow]``), ``NaN`` was treated as interchangeable with :class:`NA` in some circumstances but not others. This was done to make adoption easier, but caused some confusion (:issue:`32265`). In 3.0, an option ``"mode.nan_is_na"`` (default ``True``) controls whether to treat ``NaN`` as equivalent to :class:`NA`.
550
+
Previously, when dealing with a nullable dtype (e.g. ``Float64Dtype`` or ``int64[pyarrow]``),
551
+
``NaN`` was treated as interchangeable with :class:`NA` in some circumstances but not others.
552
+
This was done to make adoption easier, but caused some confusion (:issue:`32265`).
553
+
In 3.0, this behaviour is made consistent to by default treat ``NaN`` as equivalent
554
+
to :class:`NA` in all cases.
551
555
552
-
With ``pd.set_option("mode.nan_is_na", True)`` (again, this is the default), ``NaN`` can be passed to constructors, ``__setitem__``, ``__contains__`` and be treated the same as :class:`NA`. The only change users will see is that arithmetic and ``np.ufunc`` operations that previously introduced ``NaN`` entries produce :class:`NA` entries instead:
556
+
By default, ``NaN`` can be passed to constructors, ``__setitem__``, ``__contains__``
557
+
and will be treated the same as :class:`NA`. The only change users will see is
558
+
that arithmetic and ``np.ufunc`` operations that previously introduced ``NaN``
559
+
entries produce :class:`NA` entries instead.
553
560
554
561
*Old behavior:*
555
562
556
563
.. code-block:: ipython
557
564
558
-
In [2]: ser = pd.Series([0, None], dtype=pd.Float64Dtype())
565
+
# NaN in input gets converted to NA
566
+
In [1]: ser = pd.Series([0, np.nan], dtype=pd.Float64Dtype())
567
+
In [2]: ser
568
+
Out[2]:
569
+
0 0.0
570
+
1 <NA>
571
+
dtype: Float64
572
+
# NaN produced by arithmetic (0/0) remained NaN
559
573
In [3]: ser / 0
560
574
Out[3]:
561
575
0 NaN
562
576
1 <NA>
563
577
dtype: Float64
578
+
# the NaN value is not considered as missing
579
+
In [4]: (ser / 0).isna()
580
+
Out[4]:
581
+
0 False
582
+
1 True
583
+
dtype: bool
564
584
565
585
*New behavior:*
566
586
567
587
.. ipython:: python
568
588
569
-
ser = pd.Series([0, None], dtype=pd.Float64Dtype())
589
+
ser = pd.Series([0, np.nan], dtype=pd.Float64Dtype())
590
+
ser
570
591
ser /0
592
+
(ser /0).isna()
571
593
572
-
By contrast, with ``pd.set_option("mode.nan_is_na", False)``, ``NaN`` is always considered distinct and specifically as a floating-point value, so cannot be used with integer dtypes:
594
+
In the future, the intention is to consider ``NaN`` and :class:`NA` as distinct
595
+
values, and an option to control this behaviour is added in 3.0 through
596
+
``pd.options.future.distinguish_nan_and_na``. When enabled, ``NaN`` is always
597
+
considered distinct and specifically as a floating-point value. As a consequence,
598
+
it cannot be used with integer dtypes.
573
599
574
600
*Old behavior:*
575
601
@@ -583,13 +609,21 @@ By contrast, with ``pd.set_option("mode.nan_is_na", False)``, ``NaN`` is always
583
609
584
610
.. ipython:: python
585
611
586
-
pd.set_option("mode.nan_is_na", False)
587
-
ser = pd.Series([1, np.nan], dtype=pd.Float64Dtype())
588
-
ser[1]
612
+
with pd.option_context("future.distinguish_nan_and_na", True):
613
+
ser = pd.Series([1, np.nan], dtype=pd.Float64Dtype())
614
+
print(ser[1])
615
+
616
+
If we had passed ``pd.Int64Dtype()`` or ``"int64[pyarrow]"`` for the dtype in
617
+
the latter example, this would raise, as a float ``NaN`` cannot be held by an
618
+
integer dtype.
589
619
590
-
If we had passed ``pd.Int64Dtype()`` or ``"int64[pyarrow]"`` for the dtype in the latter example, this would raise, as a float ``NaN`` cannot be held by an integer dtype.
620
+
With ``"future.distinguish_nan_and_na"`` enabled, ``ser.to_numpy()`` (and
621
+
``frame.values`` and ``np.asarray(obj)``) will convert to ``object`` dtype if
622
+
:class:`NA` entries are present, where before they would coerce to
623
+
``NaN``. To retain a float numpy dtype, explicitly pass ``na_value=np.nan``
624
+
to :meth:`Series.to_numpy`.
591
625
592
-
With ``"mode.nan_is_na"`` set to ``False``, ``ser.to_numpy()`` (and ``frame.values`` and ``np.asarray(obj)``) will convert to ``object`` dtype if :class:`NA` entries are present, where before they would coerce to ``NaN``. To retain a float numpy dtype, explicitly pass ``na_value=np.nan`` to :meth:`Series.to_numpy`.
626
+
Note that the option is experimental and subject to change in future releases.
593
627
594
628
The ``__module__`` attribute now points to public modules
0 commit comments