Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API/DEPR: Rename DataFrame.applymap to DataFrame.map #52364

Merged
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/development/roadmap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ Numba-accelerated operations

`Numba <https://numba.pydata.org>`__ is a JIT compiler for Python code. We'd like to provide
ways for users to apply their own Numba-jitted functions where pandas accepts user-defined functions
(for example, :meth:`Series.apply`, :meth:`DataFrame.apply`, :meth:`DataFrame.applymap`,
(for example, :meth:`Series.apply`, :meth:`DataFrame.apply`, :meth:`DataFrame.map`,
and in groupby and window contexts). This will improve the performance of
user-defined-functions in these operations by staying within compiled code.

Expand Down
1 change: 1 addition & 0 deletions doc/source/reference/frame.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ Function application, GroupBy & window
:toctree: api/

DataFrame.apply
DataFrame.map
DataFrame.applymap
DataFrame.pipe
DataFrame.agg
Expand Down
6 changes: 3 additions & 3 deletions doc/source/user_guide/basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ on an entire ``DataFrame`` or ``Series``, row- or column-wise, or elementwise.
1. `Tablewise Function Application`_: :meth:`~DataFrame.pipe`
2. `Row or Column-wise Function Application`_: :meth:`~DataFrame.apply`
3. `Aggregation API`_: :meth:`~DataFrame.agg` and :meth:`~DataFrame.transform`
4. `Applying Elementwise Functions`_: :meth:`~DataFrame.applymap`
4. `Applying Elementwise Functions`_: :meth:`~DataFrame.map`

.. _basics.pipe:

Expand Down Expand Up @@ -1170,7 +1170,7 @@ Applying elementwise functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since not all functions can be vectorized (accept NumPy arrays and return
another array or value), the methods :meth:`~DataFrame.applymap` on DataFrame
another array or value), the methods :meth:`~DataFrame.map` on DataFrame
and analogously :meth:`~Series.map` on Series accept any Python function taking
a single value and returning a single value. For example:

Expand All @@ -1187,7 +1187,7 @@ a single value and returning a single value. For example:
return len(str(x))

df4["one"].map(f)
df4.applymap(f)
df4.map(f)

:meth:`Series.map` has an additional feature; it can be used to easily
"link" or "map" values defined by a secondary series. This is closely related
Expand Down
4 changes: 2 additions & 2 deletions doc/source/user_guide/cookbook.rst
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ Ambiguity arises when an index consists of integers with a non-zero start or non
New columns
***********

`Efficiently and dynamically creating new columns using applymap
`Efficiently and dynamically creating new columns using DataFrame.map (previously named applymap)
<https://stackoverflow.com/questions/16575868/efficiently-creating-additional-columns-in-a-pandas-dataframe-using-map>`__

.. ipython:: python
Expand All @@ -254,7 +254,7 @@ New columns
new_cols = [str(x) + "_cat" for x in source_cols]
categories = {1: "Alpha", 2: "Beta", 3: "Charlie"}

df[new_cols] = df[source_cols].applymap(categories.get)
df[new_cols] = df[source_cols].map(categories.get)
df

`Keep other columns when using min() with groupby
Expand Down
4 changes: 2 additions & 2 deletions doc/source/user_guide/style.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@
"\n",
"- Using [.set_table_styles()][table] to control broader areas of the table with specified internal CSS. Although table styles allow the flexibility to add CSS selectors and properties controlling all individual parts of the table, they are unwieldy for individual cell specifications. Also, note that table styles cannot be exported to Excel. \n",
"- Using [.set_td_classes()][td_class] to directly link either external CSS classes to your data cells or link the internal CSS classes created by [.set_table_styles()][table]. See [here](#Setting-Classes-and-Linking-to-External-CSS). These cannot be used on column header rows or indexes, and also won't export to Excel. \n",
"- Using the [.apply()][apply] and [.applymap()][applymap] functions to add direct internal CSS to specific data cells. See [here](#Styler-Functions). As of v1.4.0 there are also methods that work directly on column header rows or indexes; [.apply_index()][applyindex] and [.applymap_index()][applymapindex]. Note that only these methods add styles that will export to Excel. These methods work in a similar way to [DataFrame.apply()][dfapply] and [DataFrame.applymap()][dfapplymap].\n",
"- Using the [.apply()][apply] and [.applymap()][applymap] functions to add direct internal CSS to specific data cells. See [here](#Styler-Functions). As of v1.4.0 there are also methods that work directly on column header rows or indexes; [.apply_index()][applyindex] and [.applymap_index()][applymapindex]. Note that only these methods add styles that will export to Excel. These methods work in a similar way to [DataFrame.apply()][dfapply] and [DataFrame.map()][dfmap].\n",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are changing DataFrame.applymap() to DataFrame.map(), shouldn't we then change Styler.applymap() to Styler.map() to make things consistent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a logical next step and @attack68 has proposed in #52353 (comment) to takie on styler.applymap after this has been merged.A good idea IMO.

"\n",
"[table]: ../reference/api/pandas.io.formats.style.Styler.set_table_styles.rst\n",
"[styler]: ../reference/api/pandas.io.formats.style.Styler.rst\n",
Expand All @@ -362,7 +362,7 @@
"[applyindex]: ../reference/api/pandas.io.formats.style.Styler.apply_index.rst\n",
"[applymapindex]: ../reference/api/pandas.io.formats.style.Styler.applymap_index.rst\n",
"[dfapply]: ../reference/api/pandas.DataFrame.apply.rst\n",
"[dfapplymap]: ../reference/api/pandas.DataFrame.applymap.rst"
"[dfmap]: ../reference/api/pandas.DataFrame.map.rst"
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion doc/source/user_guide/visualization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1709,7 +1709,7 @@ Colormaps can also be used other plot types, like bar charts:

.. ipython:: python

dd = pd.DataFrame(np.random.randn(10, 10)).applymap(abs)
dd = pd.DataFrame(np.random.randn(10, 10)).map(abs)
dd = dd.cumsum()

plt.figure();
Expand Down
7 changes: 5 additions & 2 deletions doc/source/whatsnew/v2.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ enhancement1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

When given a callable, :meth:`Series.map` applies the callable to all elements of the :class:`Series`.
Similarly, :meth:`DataFrame.applymap` applies the callable to all elements of the :class:`DataFrame`,
Similarly, :meth:`DataFrame.map` applies the callable to all elements of the :class:`DataFrame`,
while :meth:`Index.map` applies the callable to all elements of the :class:`Index`.

Frequently, it is not desirable to apply the callable to nan-like values of the array and to avoid doing
Expand Down Expand Up @@ -59,10 +59,12 @@ and ``na_action="ignore"`` did not work correctly for any ``ExtensionArray`` sub
ser = pd.Series(["a", "b", np.nan], dtype="category")
ser.map(str.upper, na_action="ignore")
df = pd.DataFrame(ser)
df.applymap(str.upper, na_action="ignore")
df.map(str.upper, na_action="ignore")
idx = pd.Index(ser)
idx.map(str.upper, na_action="ignore")

Notice also that in this version, :meth:`DataFrame.map` been added and :meth:`DataFrame.applymap` has been deprecated. :meth:`DataFrame.map` has the same functionality as :meth:`DataFrame.applymap`, but does the new name better communicate that this is the :class:`DataFrame` version of :meth:`Series.map` (:issue:`52353`).

Also, note that :meth:`Categorical.map` implicitly has had its ``na_action`` set to ``"ignore"`` by default.
This has been deprecated and will :meth:`Categorical.map` in the future change the default
to ``na_action=None``, like for all the other array types.
Expand Down Expand Up @@ -223,6 +225,7 @@ Deprecations
- Deprecated :func:`is_datetime64tz_dtype`, check ``isinstance(dtype, pd.DatetimeTZDtype)`` instead (:issue:`52607`)
- Deprecated :func:`is_int64_dtype`, check ``dtype == np.dtype(np.int64)`` instead (:issue:`52564`)
- Deprecated :func:`is_interval_dtype`, check ``isinstance(dtype, pd.IntervalDtype)`` instead (:issue:`52607`)
- Deprecated :meth:`DataFrame.applymap`. Use the new :meth:`DataFrame.map` method instead (:issue:`52353`)
- Deprecated :meth:`DataFrame.swapaxes` and :meth:`Series.swapaxes`, use :meth:`DataFrame.transpose` or :meth:`Series.transpose` instead (:issue:`51946`)
- Deprecated ``freq`` parameter in :class:`PeriodArray` constructor, pass ``dtype`` instead (:issue:`52462`)
- Deprecated behavior of :meth:`Series.dt.to_pydatetime`, in a future version this will return a :class:`Series` containing python ``datetime`` objects instead of an ``ndarray`` of datetimes; this matches the behavior of other :meth:`Series.dt` properties (:issue:`20306`)
Expand Down
73 changes: 66 additions & 7 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -9673,7 +9673,7 @@ def apply(

See Also
--------
DataFrame.applymap: For elementwise operations.
DataFrame.map: For elementwise operations.
DataFrame.aggregate: Only perform aggregating type operations.
DataFrame.transform: Only perform transforming type operations.

Expand Down Expand Up @@ -9765,12 +9765,16 @@ def apply(
)
return op.apply().__finalize__(self, method="apply")

def applymap(
def map(
self, func: PythonFuncType, na_action: str | None = None, **kwargs
) -> DataFrame:
"""
Apply a function to a Dataframe elementwise.

.. versionadded:: 2.1.0

DataFrame.applymap was deprecated and renamed to DataFrame.map.

This method applies a function that accepts and returns a scalar
to every element of a DataFrame.

Expand Down Expand Up @@ -9798,6 +9802,7 @@ def applymap(
--------
DataFrame.apply : Apply a function along input axis of DataFrame.
DataFrame.replace: Replace values given in `to_replace` with `value`.
Series.map : Apply a function elementwise on a Series.

Examples
--------
Expand All @@ -9807,7 +9812,7 @@ def applymap(
0 1.000 2.120
1 3.356 4.567

>>> df.applymap(lambda x: len(str(x)))
>>> df.map(lambda x: len(str(x)))
0 1
0 3 4
1 5 5
Expand All @@ -9816,20 +9821,20 @@ def applymap(

>>> df_copy = df.copy()
>>> df_copy.iloc[0, 0] = pd.NA
>>> df_copy.applymap(lambda x: len(str(x)), na_action='ignore')
>>> df_copy.map(lambda x: len(str(x)), na_action='ignore')
0 1
0 NaN 4
1 5.0 5

Note that a vectorized version of `func` often exists, which will
be much faster. You could square each number elementwise.

>>> df.applymap(lambda x: x**2)
>>> df.map(lambda x: x**2)
0 1
0 1.000000 4.494400
1 11.262736 20.857489

But it's better to avoid applymap in that case.
But it's better to avoid map in that case.

>>> df ** 2
0 1
Expand All @@ -9849,7 +9854,61 @@ def applymap(
def infer(x):
return x._map_values(func, na_action=na_action)

return self.apply(infer).__finalize__(self, "applymap")
return self.apply(infer).__finalize__(self, "map")

def applymap(
self, func: PythonFuncType, na_action: str | None = None, **kwargs
) -> DataFrame:
"""
Apply a function to a Dataframe elementwise.

.. deprecated:: 2.1.0

DataFrame.applymap has been deprecated. Use DataFrame.map instead.

This method applies a function that accepts and returns a scalar
to every element of a DataFrame.

Parameters
----------
func : callable
Python function, returns a single value from a single value.
na_action : {None, 'ignore'}, default None
If ‘ignore’, propagate NaN values, without passing them to func.
**kwargs
Additional keyword arguments to pass as keywords arguments to
`func`.

Returns
-------
DataFrame
Transformed DataFrame.

See Also
--------
DataFrame.apply : Apply a function along input axis of DataFrame.
DataFrame.map : Apply a function along input axis of DataFrame.
DataFrame.replace: Replace values given in `to_replace` with `value`.

Examples
--------
>>> df = pd.DataFrame([[1, 2.12], [3.356, 4.567]])
>>> df
0 1
0 1.000 2.120
1 3.356 4.567

>>> df.map(lambda x: len(str(x)))
0 1
0 3 4
1 5 5
"""
warnings.warn(
"DataFrame.applymap has been deprecated. Use DataFrame.map instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return self.map(func, na_action=na_action, **kwargs)

# ----------------------------------------------------------------------
# Merging / joining methods
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -5942,7 +5942,7 @@ def pipe(
See Also
--------
DataFrame.apply : Apply a function along input axis of DataFrame.
DataFrame.applymap : Apply a function elementwise on a whole DataFrame.
DataFrame.map : Apply a function elementwise on a whole DataFrame.
Series.map : Apply a mapping correspondence on a
:class:`~pandas.Series`.

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -4250,7 +4250,7 @@ def map(
Series.apply : For applying more complex functions on a Series.
Series.replace: Replace values given in `to_replace` with `value`.
DataFrame.apply : Apply a function row-/column-wise.
DataFrame.applymap : Apply a function elementwise on a whole DataFrame.
DataFrame.map : Apply a function elementwise on a whole DataFrame.

Notes
-----
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/shared_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@
DataFrame.fillna : Fill NA values.
Series.where : Replace values based on boolean condition.
DataFrame.where : Replace values based on boolean condition.
DataFrame.applymap: Apply a function to a Dataframe elementwise.
DataFrame.map: Apply a function to a Dataframe elementwise.
Series.map: Map values of Series according to an input mapping or function.
Series.str.replace : Simple string replacement.

Expand Down
4 changes: 2 additions & 2 deletions pandas/io/formats/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -1813,7 +1813,7 @@ def _apply_index(
if method == "apply":
result = data.apply(func, axis=0, **kwargs)
elif method == "applymap":
result = data.applymap(func, **kwargs)
result = data.map(func, **kwargs)

self._update_ctx_header(result, axis)
return self
Expand Down Expand Up @@ -1938,7 +1938,7 @@ def _applymap(
if subset is None:
subset = IndexSlice[:]
subset = non_reducing_slice(subset)
result = self.data.loc[subset].applymap(func)
result = self.data.loc[subset].map(func)
self._update_ctx(result)
return self

Expand Down
2 changes: 1 addition & 1 deletion pandas/io/json/_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ def __init__(
obj = obj.copy()
timedeltas = obj.select_dtypes(include=["timedelta"]).columns
if len(timedeltas):
obj[timedeltas] = obj[timedeltas].applymap(lambda x: x.isoformat())
obj[timedeltas] = obj[timedeltas].map(lambda x: x.isoformat())
# Convert PeriodIndex to datetimes before serializing
if isinstance(obj.index.dtype, PeriodDtype):
obj.index = obj.index.to_timestamp()
Expand Down
Loading