From e5ea65d2274ac25af21524d7d74ebaa7a00bfa01 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Tue, 14 Oct 2025 22:28:39 +0530 Subject: [PATCH 1/6] BUG: Fix boolean value of NA is ambiguous in iloc assignment for nullable integer Series --- pandas/core/arrays/numeric.py | 22 ++++++++++++---------- pandas/tests/indexing/test_iloc.py | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/pandas/core/arrays/numeric.py b/pandas/core/arrays/numeric.py index 80fbbf99a5494..3d157495c0c1f 100644 --- a/pandas/core/arrays/numeric.py +++ b/pandas/core/arrays/numeric.py @@ -24,6 +24,7 @@ pandas_dtype, ) +import pandas as pd from pandas.core.arrays.masked import ( BaseMaskedArray, BaseMaskedDtype, @@ -231,16 +232,17 @@ def _coerce_to_data_and_mask( values = np.ones(values.shape, dtype=dtype) else: idx = np.nanargmax(values) - if int(values[idx]) != original[idx]: - # We have ints that lost precision during the cast. - inferred_type = lib.infer_dtype(original, skipna=True) - if ( - inferred_type not in ["floating", "mixed-integer-float"] - and not mask.any() - ): - values = np.asarray(original, dtype=dtype) - else: - values = np.asarray(original, dtype="object") + if not (pd.isna(values[idx]) or pd.isna(original[idx])): + if int(values[idx]) != original[idx]: + # We have ints that lost precision during the cast. + inferred_type = lib.infer_dtype(original, skipna=True) + if ( + inferred_type not in ["floating", "mixed-integer-float"] + and not mask.any() + ): + values = np.asarray(original, dtype=dtype) + else: + values = np.asarray(original, dtype="object") # we copy as need to coerce here if mask.any(): diff --git a/pandas/tests/indexing/test_iloc.py b/pandas/tests/indexing/test_iloc.py index ddb58ecbfa6f3..153848ec1f5b6 100644 --- a/pandas/tests/indexing/test_iloc.py +++ b/pandas/tests/indexing/test_iloc.py @@ -1090,6 +1090,25 @@ def test_iloc_setitem_pure_position_based(self, indexer, has_ref): expected = DataFrame({"a": [1, 2, 3], "b": [11, 12, 13], "c": [7, 8, 9]}) tm.assert_frame_equal(df2, expected) + def test_iloc_assignment_nullable_int_with_na(self): + # GH#62473 + ser = Series( + [4, 6, 9, None, 10, 13, 15], index=[6, 1, 5, 0, 3, 2, 4], dtype="Int64" + ) + indices = Series( + [6, 1, 5, 0, 3, 2, 4], index=[6, 1, 5, 0, 3, 2, 4], dtype="int64" + ) + values = Series( + [4, 6, 9, None, 10, 13, 15], index=[4, 1, 2, 6, 0, 5, 3], dtype="Int64" + ) + + ser.iloc[indices] = values + + expected = Series( + [None, 6, 13, 15, 4, 9, 10], index=[6, 1, 5, 0, 3, 2, 4], dtype="Int64" + ) + tm.assert_series_equal(ser.sort_index(), expected.sort_index()) + @pytest.mark.parametrize("has_ref", [True, False]) def test_iloc_setitem_dictionary_value(self, has_ref): # GH#37728 From 47e1a01f0a29cc65b6e69c0e91a4d5b933740ee1 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Tue, 14 Oct 2025 22:59:24 +0530 Subject: [PATCH 2/6] BUG: Fix boolean value of NA is ambiguous in iloc assignment for nullable integer Series --- pandas/tests/indexing/test_iloc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexing/test_iloc.py b/pandas/tests/indexing/test_iloc.py index 153848ec1f5b6..dedab686389ff 100644 --- a/pandas/tests/indexing/test_iloc.py +++ b/pandas/tests/indexing/test_iloc.py @@ -1107,7 +1107,7 @@ def test_iloc_assignment_nullable_int_with_na(self): expected = Series( [None, 6, 13, 15, 4, 9, 10], index=[6, 1, 5, 0, 3, 2, 4], dtype="Int64" ) - tm.assert_series_equal(ser.sort_index(), expected.sort_index()) + tm.assert_series_equal(ser.sort_index(), expected) @pytest.mark.parametrize("has_ref", [True, False]) def test_iloc_setitem_dictionary_value(self, has_ref): From 3327426ef88a6fad0ea13322daed12fb6a86a327 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Wed, 15 Oct 2025 09:32:38 +0530 Subject: [PATCH 3/6] BUG: Fix boolean value of NA is ambiguous in iloc assignment for nullable integer Series --- pandas/tests/indexing/test_iloc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexing/test_iloc.py b/pandas/tests/indexing/test_iloc.py index dedab686389ff..195565ac69a27 100644 --- a/pandas/tests/indexing/test_iloc.py +++ b/pandas/tests/indexing/test_iloc.py @@ -1107,7 +1107,7 @@ def test_iloc_assignment_nullable_int_with_na(self): expected = Series( [None, 6, 13, 15, 4, 9, 10], index=[6, 1, 5, 0, 3, 2, 4], dtype="Int64" ) - tm.assert_series_equal(ser.sort_index(), expected) + tm.assert_series_equal(ser, expected) @pytest.mark.parametrize("has_ref", [True, False]) def test_iloc_setitem_dictionary_value(self, has_ref): From 3a691369b11a4c801fe91ba00a7e58a3ee95409c Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Wed, 15 Oct 2025 10:27:12 +0530 Subject: [PATCH 4/6] BUG: Fix boolean value of NA is ambiguous in iloc assignment for nullable integer Series --- pandas/tests/indexing/test_iloc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexing/test_iloc.py b/pandas/tests/indexing/test_iloc.py index 195565ac69a27..10bb773f26454 100644 --- a/pandas/tests/indexing/test_iloc.py +++ b/pandas/tests/indexing/test_iloc.py @@ -1105,7 +1105,7 @@ def test_iloc_assignment_nullable_int_with_na(self): ser.iloc[indices] = values expected = Series( - [None, 6, 13, 15, 4, 9, 10], index=[6, 1, 5, 0, 3, 2, 4], dtype="Int64" + [NA, 6, 13, 15, 4, 9, 10], index=[6, 1, 5, 0, 3, 2, 4], dtype="Int64" ) tm.assert_series_equal(ser, expected) From caa0fd3d884619daaa4eaec4cda589a943468473 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Wed, 15 Oct 2025 11:46:27 +0530 Subject: [PATCH 5/6] BUG: Fix boolean value of NA is ambiguous in iloc assignment for nullable integer Series --- pandas/tests/indexing/test_iloc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexing/test_iloc.py b/pandas/tests/indexing/test_iloc.py index 10bb773f26454..88856418cb531 100644 --- a/pandas/tests/indexing/test_iloc.py +++ b/pandas/tests/indexing/test_iloc.py @@ -1105,7 +1105,7 @@ def test_iloc_assignment_nullable_int_with_na(self): ser.iloc[indices] = values expected = Series( - [NA, 6, 13, 15, 4, 9, 10], index=[6, 1, 5, 0, 3, 2, 4], dtype="Int64" + [NA, 6, 13, 10, 15, 9, 4], index=[6, 1, 5, 0, 3, 2, 4], dtype="Int64" ) tm.assert_series_equal(ser, expected) From bec4591065d5bdac1ebbce88fc6ab908f0b3d3db Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Sun, 9 Nov 2025 11:59:40 +0530 Subject: [PATCH 6/6] BUG: Fix boolean value of NA is ambiguous in iloc assignment --- pandas/core/arrays/numeric.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pandas/core/arrays/numeric.py b/pandas/core/arrays/numeric.py index 3d157495c0c1f..295f930767fb7 100644 --- a/pandas/core/arrays/numeric.py +++ b/pandas/core/arrays/numeric.py @@ -24,11 +24,11 @@ pandas_dtype, ) -import pandas as pd from pandas.core.arrays.masked import ( BaseMaskedArray, BaseMaskedDtype, ) +from pandas.core.construction import extract_array if TYPE_CHECKING: from collections.abc import ( @@ -143,6 +143,7 @@ def _safe_cast(cls, values: np.ndarray, dtype: np.dtype, copy: bool) -> np.ndarr def _coerce_to_data_and_mask( values, dtype, copy: bool, dtype_cls: type[NumericDtype], default_dtype: np.dtype ): + values = extract_array(values, extract_numpy=True) checker = dtype_cls._checker mask = None @@ -232,17 +233,16 @@ def _coerce_to_data_and_mask( values = np.ones(values.shape, dtype=dtype) else: idx = np.nanargmax(values) - if not (pd.isna(values[idx]) or pd.isna(original[idx])): - if int(values[idx]) != original[idx]: - # We have ints that lost precision during the cast. - inferred_type = lib.infer_dtype(original, skipna=True) - if ( - inferred_type not in ["floating", "mixed-integer-float"] - and not mask.any() - ): - values = np.asarray(original, dtype=dtype) - else: - values = np.asarray(original, dtype="object") + if int(values[idx]) != original[idx]: + # We have ints that lost precision during the cast. + inferred_type = lib.infer_dtype(original, skipna=True) + if ( + inferred_type not in ["floating", "mixed-integer-float"] + and not mask.any() + ): + values = np.asarray(original, dtype=dtype) + else: + values = np.asarray(original, dtype="object") # we copy as need to coerce here if mask.any():