Skip to content

Commit 103d65a

Browse files
committed
ENH: DataFrame.map uses .map method of ExtensionArrays
1 parent 6c50f70 commit 103d65a

File tree

3 files changed

+29
-5
lines changed

3 files changed

+29
-5
lines changed

doc/source/whatsnew/v2.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Other enhancements
3434
- Improve error message when setting :class:`DataFrame` with wrong number of columns through :meth:`DataFrame.isetitem` (:issue:`51701`)
3535
- Let :meth:`DataFrame.to_feather` accept a non-default :class:`Index` and non-string column names (:issue:`51787`)
3636
- :class:`api.extensions.ExtensionArray` now has a :meth:`~api.extensions.ExtensionArray.map` method (:issue:`51809`)
37+
- :meth:`DataFrame.applymap` now uses the :meth:`~api.extensions.ExtensionArray.map` method for of the underlying arrays for :class:`api.extensions.ExtensionArray` instances (:issue:`xxxxx`)
3738
- Improve error message when having incompatible columns using :meth:`DataFrame.merge` (:issue:`51861`)
3839
- Improved error message when creating a DataFrame with empty data (0 rows), no index and an incorrect number of columns. (:issue:`52084`)
3940
- :meth:`arrays.SparseArray.map` now supports ``na_action`` (:issue:`52096`).

pandas/core/frame.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -9955,14 +9955,14 @@ def applymap(
99559955
raise ValueError(
99569956
f"na_action must be 'ignore' or None. Got {repr(na_action)}"
99579957
)
9958-
ignore_na = na_action == "ignore"
9958+
9959+
if self.empty:
9960+
return self.copy()
9961+
99599962
func = functools.partial(func, **kwargs)
99609963

9961-
# if we have a dtype == 'M8[ns]', provide boxed values
99629964
def infer(x):
9963-
if x.empty:
9964-
return lib.map_infer(x, func, ignore_na=ignore_na)
9965-
return lib.map_infer(x.astype(object)._values, func, ignore_na=ignore_na)
9965+
return x._map_values(func, na_action=na_action)
99669966

99679967
return self.apply(infer).__finalize__(self, "applymap")
99689968

pandas/tests/apply/test_frame_apply.py

+23
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,29 @@ def test_applymap_float_object_conversion(val):
546546
assert result == object
547547

548548

549+
@pytest.mark.parametrize("na_action", ["ignore", None])
550+
def test_applymap_keeps_dtype(na_action):
551+
# GHxxxxx
552+
arr = pd.Series(["a", np.nan, "b"])
553+
sparse_arr = arr.astype(pd.SparseDtype(object))
554+
df = pd.DataFrame(data={"a": arr, "b": sparse_arr})
555+
556+
def func(x):
557+
return str.upper(x) if not pd.isna(x) else x
558+
559+
result = df.applymap(func, na_action=na_action)
560+
561+
expected_sparse = pd.array(["A", np.nan, "B"], dtype=pd.SparseDtype(object))
562+
expected_arr = expected_sparse.astype(object)
563+
expected = pd.DataFrame({"a": expected_arr, "b": expected_sparse})
564+
565+
tm.assert_frame_equal(result, expected)
566+
567+
result_empty = df.iloc[:0, :].applymap(func, na_action=na_action)
568+
expected_empty = expected.iloc[:0, :]
569+
tm.assert_frame_equal(result_empty, expected_empty)
570+
571+
549572
def test_applymap_str():
550573
# GH 2786
551574
df = DataFrame(np.random.random((3, 4)))

0 commit comments

Comments
 (0)