Skip to content

Commit 9b2a8cf

Browse files
committed
Merge branch 'main' into depr-53910
2 parents 38c2d18 + bdc9a7b commit 9b2a8cf

File tree

5 files changed

+34
-20
lines changed

5 files changed

+34
-20
lines changed

doc/source/whatsnew/v3.0.0.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,7 @@ Other Deprecations
738738
- Deprecated backward-compatibility behavior for :meth:`DataFrame.select_dtypes` matching "str" dtype when ``np.object_`` is specified (:issue:`61916`)
739739
- Deprecated option "future.no_silent_downcasting", as it is no longer used. In a future version accessing this option will raise (:issue:`59502`)
740740
- Deprecated reindexing with a ``fill_value`` that cannot be held by the original object's dtype; explicitly cast before reindexing instead (:issue:`53910`)
741+
- Deprecated silent casting of non-datetime 'other' to datetime in :meth:`Series.combine_first` (:issue:`62931`)
741742
- Deprecated slicing on a :class:`Series` or :class:`DataFrame` with a :class:`DatetimeIndex` using a ``datetime.date`` object, explicitly cast to :class:`Timestamp` instead (:issue:`35830`)
742743
- Deprecated the 'inplace' keyword from :meth:`Resampler.interpolate`, as passing ``True`` raises ``AttributeError`` (:issue:`58690`)
743744

@@ -1188,6 +1189,7 @@ Reshaping
11881189
- Bug in :meth:`DataFrame.join` inconsistently setting result index name (:issue:`55815`)
11891190
- Bug in :meth:`DataFrame.join` when a :class:`DataFrame` with a :class:`MultiIndex` would raise an ``AssertionError`` when :attr:`MultiIndex.names` contained ``None``. (:issue:`58721`)
11901191
- Bug in :meth:`DataFrame.merge` where merging on a column containing only ``NaN`` values resulted in an out-of-bounds array access (:issue:`59421`)
1192+
- Bug in :meth:`Series.combine_first` incorrectly replacing ``None`` entries with ``NaN`` (:issue:`58977`)
11911193
- Bug in :meth:`DataFrame.unstack` producing incorrect results when ``sort=False`` (:issue:`54987`, :issue:`55516`)
11921194
- Bug in :meth:`DataFrame.unstack` raising an error with indexes containing ``NaN`` with ``sort=False`` (:issue:`61221`)
11931195
- Bug in :meth:`DataFrame.merge` when merging two :class:`DataFrame` on ``intc`` or ``uintc`` types on Windows (:issue:`60091`, :issue:`58713`)

pandas/core/frame.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9038,16 +9038,6 @@ def combine(
90389038
0 0 -5.0
90399039
1 0 4.0
90409040
9041-
However, if the same element in both dataframes is None, that None
9042-
is preserved
9043-
9044-
>>> df1 = pd.DataFrame({"A": [0, 0], "B": [None, 4]})
9045-
>>> df2 = pd.DataFrame({"A": [1, 1], "B": [None, 3]})
9046-
>>> df1.combine(df2, take_smaller, fill_value=-5)
9047-
A B
9048-
0 0 -5.0
9049-
1 0 3.0
9050-
90519041
Example that demonstrates the use of `overwrite` and behavior when
90529042
the axis differ between the dataframes.
90539043
@@ -13820,8 +13810,8 @@ def quantile(
1382013810
0.1 1 1
1382113811
0.5 3 100
1382213812
13823-
Specifying `numeric_only=False` will also compute the quantile of
13824-
datetime and timedelta data.
13813+
Specifying `numeric_only=False` will compute the quantiles for all
13814+
columns.
1382513815
1382613816
>>> df = pd.DataFrame(
1382713817
... {

pandas/core/indexes/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4169,7 +4169,7 @@ def reindex(
41694169
limit : int, optional
41704170
Maximum number of consecutive labels in ``target`` to match for
41714171
inexact matches.
4172-
tolerance : int or float, optional
4172+
tolerance : int, float, or list-like, optional
41734173
Maximum distance between original and new labels for inexact
41744174
matches. The values of the index at the matching locations must
41754175
satisfy the equation ``abs(index[indexer] - target) <= tolerance``.

pandas/core/series.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@
8787
)
8888
from pandas.core.dtypes.dtypes import (
8989
ExtensionDtype,
90-
SparseDtype,
9190
)
9291
from pandas.core.dtypes.generic import (
9392
ABCDataFrame,
@@ -3112,8 +3111,8 @@ def combine(
31123111
31133112
Combine the Series and `other` using `func` to perform elementwise
31143113
selection for combined Series.
3115-
`fill_value` is assumed when value is missing at some index
3116-
from one of the two objects being combined.
3114+
`fill_value` is assumed when value is not present at some index
3115+
from one of the two Series being combined.
31173116
31183117
Parameters
31193118
----------
@@ -3254,9 +3253,6 @@ def combine_first(self, other) -> Series:
32543253
if self.dtype == other.dtype:
32553254
if self.index.equals(other.index):
32563255
return self.mask(self.isna(), other)
3257-
elif self._can_hold_na and not isinstance(self.dtype, SparseDtype):
3258-
this, other = self.align(other, join="outer")
3259-
return this.mask(this.isna(), other)
32603256

32613257
new_index = self.index.union(other.index)
32623258

@@ -3271,6 +3267,16 @@ def combine_first(self, other) -> Series:
32713267
if this.dtype.kind == "M" and other.dtype.kind != "M":
32723268
# TODO: try to match resos?
32733269
other = to_datetime(other)
3270+
warnings.warn(
3271+
# GH#62931
3272+
"Silently casting non-datetime 'other' to datetime in "
3273+
"Series.combine_first is deprecated and will be removed "
3274+
"in a future version. Explicitly cast before calling "
3275+
"combine_first instead.",
3276+
Pandas4Warning,
3277+
stacklevel=find_stack_level(),
3278+
)
3279+
32743280
combined = concat([this, other])
32753281
combined = combined.reindex(new_index)
32763282
return combined.__finalize__(self, method="combine_first")

pandas/tests/series/methods/test_combine_first.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import numpy as np
44

5+
from pandas.errors import Pandas4Warning
6+
57
import pandas as pd
68
from pandas import (
79
Period,
@@ -75,9 +77,14 @@ def test_combine_first_dt64(self, unit):
7577
xp = to_datetime(Series(["2010", "2011"])).dt.as_unit(unit)
7678
tm.assert_series_equal(rs, xp)
7779

80+
def test_combine_first_dt64_casting_deprecation(self, unit):
81+
# GH#62931
7882
s0 = to_datetime(Series(["2010", np.nan])).dt.as_unit(unit)
7983
s1 = Series([np.nan, "2011"])
80-
rs = s0.combine_first(s1)
84+
85+
msg = "Silently casting non-datetime 'other' to datetime"
86+
with tm.assert_produces_warning(Pandas4Warning, match=msg):
87+
rs = s0.combine_first(s1)
8188

8289
xp = Series([datetime(2010, 1, 1), "2011"], dtype=f"datetime64[{unit}]")
8390

@@ -144,3 +151,12 @@ def test_combine_mixed_timezone(self):
144151
),
145152
)
146153
tm.assert_series_equal(result, expected)
154+
155+
def test_combine_first_none_not_nan(self):
156+
# GH#58977
157+
s1 = Series([None, None, None], index=["a", "b", "c"])
158+
s2 = Series([None, None, None], index=["b", "c", "d"])
159+
160+
result = s1.combine_first(s2)
161+
expected = Series([None] * 4, index=["a", "b", "c", "d"])
162+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)