Skip to content

Commit 5269aef

Browse files
authored
ENH: make DataFrame.applymap uses the .map method of ExtensionArrays (#52219)
* ENH: DataFrame.map uses .map method of ExtensionArrays * add gh number * fix failures * fix failures * fix whatsnew
1 parent cc65991 commit 5269aef

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
@@ -36,6 +36,7 @@ Other enhancements
3636
- :class:`api.extensions.ExtensionArray` now has a :meth:`~api.extensions.ExtensionArray.map` method (:issue:`51809`)
3737
- Improve error message when having incompatible columns using :meth:`DataFrame.merge` (:issue:`51861`)
3838
- Improved error message when creating a DataFrame with empty data (0 rows), no index and an incorrect number of columns. (:issue:`52084`)
39+
- :meth:`DataFrame.applymap` now uses the :meth:`~api.extensions.ExtensionArray.map` method of underlying :class:`api.extensions.ExtensionArray` instances (:issue:`52219`)
3940
- :meth:`arrays.SparseArray.map` now supports ``na_action`` (:issue:`52096`).
4041

4142
.. ---------------------------------------------------------------------------

pandas/core/frame.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -9949,14 +9949,14 @@ def applymap(
99499949
raise ValueError(
99509950
f"na_action must be 'ignore' or None. Got {repr(na_action)}"
99519951
)
9952-
ignore_na = na_action == "ignore"
9952+
9953+
if self.empty:
9954+
return self.copy()
9955+
99539956
func = functools.partial(func, **kwargs)
99549957

9955-
# if we have a dtype == 'M8[ns]', provide boxed values
99569958
def infer(x):
9957-
if x.empty:
9958-
return lib.map_infer(x, func, ignore_na=ignore_na)
9959-
return lib.map_infer(x.astype(object)._values, func, ignore_na=ignore_na)
9959+
return x._map_values(func, na_action=na_action)
99609960

99619961
return self.apply(infer).__finalize__(self, "applymap")
99629962

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", [None, "ignore"])
550+
def test_applymap_keeps_dtype(na_action):
551+
# GH52219
552+
arr = Series(["a", np.nan, "b"])
553+
sparse_arr = arr.astype(pd.SparseDtype(object))
554+
df = 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 = 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)