From 1ef894f5c0066e735f25840418d04040170c78d6 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sun, 2 Apr 2023 00:02:18 +0100 Subject: [PATCH 01/16] API: rename DataFrame.applymap -> DataFrame.map --- ci/polars | 12 ++++++ doc/source/development/roadmap.rst | 2 +- doc/source/reference/frame.rst | 1 + doc/source/user_guide/basics.rst | 6 +-- doc/source/user_guide/cookbook.rst | 4 +- doc/source/user_guide/visualization.rst | 2 +- doc/source/whatsnew/v2.1.0.rst | 7 +++- pandas/core/frame.py | 49 +++++++++++++++++++++-- pandas/core/generic.py | 2 +- pandas/core/series.py | 2 +- pandas/core/shared_docs.py | 2 +- pandas/io/formats/style.py | 4 +- pandas/io/json/_json.py | 2 +- pandas/tests/frame/methods/test_to_csv.py | 10 ++--- pandas/tests/io/sas/test_sas7bdat.py | 8 ++-- pandas/tests/io/test_html.py | 2 +- pandas/tests/io/test_sql.py | 6 +-- 17 files changed, 87 insertions(+), 34 deletions(-) create mode 100644 ci/polars diff --git a/ci/polars b/ci/polars new file mode 100644 index 0000000000000..f39a9a2616c03 --- /dev/null +++ b/ci/polars @@ -0,0 +1,12 @@ +#!/bin/bash +set -euo pipefail +wget https://s3.amazonaws.com/hubway-data/20{16,17,18,19,20,21,22}{01,02,03,04,05,06,07,08,09,10,11,12}-hubway-tripdata.zip +wget https://s3.amazonaws.com/hubway-data/2018{01,02,03,04}-hubway-tripdata.zip +wget https://s3.amazonaws.com/hubway-data/2018{05,06,07,08,09,10,11,12}-bluebikes-tripdata.zip +wget https://s3.amazonaws.com/hubway-data/20{19,20,21,22}{01,02,03,04,05,06,07,08,09,10,11,12}-bluebikes-tripdata.zip +wget https://s3.amazonaws.com/hubway-data/2023{01,02}-bluebikes-tripdata.zip +find . -iname "*-hubway-*.zip" -exec unzip {} \; +find . -iname "*-bluebikes-*.zip" -exec unzip {} \; +rm -f *-hubway-*.zip +rm -f *-bluebikes-*.zip +wget https://s3.amazonaws.com/hubway-data/current_bluebikes_stations.csv diff --git a/doc/source/development/roadmap.rst b/doc/source/development/roadmap.rst index f2198d1ce521d..2d142453fb735 100644 --- a/doc/source/development/roadmap.rst +++ b/doc/source/development/roadmap.rst @@ -179,7 +179,7 @@ Numba-accelerated operations `Numba `__ 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. diff --git a/doc/source/reference/frame.rst b/doc/source/reference/frame.rst index ec29f1dc0d67d..fefb02dd916cd 100644 --- a/doc/source/reference/frame.rst +++ b/doc/source/reference/frame.rst @@ -116,6 +116,7 @@ Function application, GroupBy & window :toctree: api/ DataFrame.apply + DataFrame.map DataFrame.applymap DataFrame.pipe DataFrame.agg diff --git a/doc/source/user_guide/basics.rst b/doc/source/user_guide/basics.rst index 16a85ccc74b43..48fcaf85f0f59 100644 --- a/doc/source/user_guide/basics.rst +++ b/doc/source/user_guide/basics.rst @@ -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: @@ -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: @@ -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 diff --git a/doc/source/user_guide/cookbook.rst b/doc/source/user_guide/cookbook.rst index 3a0aad41933bc..326d2a2df0e5d 100644 --- a/doc/source/user_guide/cookbook.rst +++ b/doc/source/user_guide/cookbook.rst @@ -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) `__ .. ipython:: python @@ -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 diff --git a/doc/source/user_guide/visualization.rst b/doc/source/user_guide/visualization.rst index 844be80abd1ff..7ab16f8127b94 100644 --- a/doc/source/user_guide/visualization.rst +++ b/doc/source/user_guide/visualization.rst @@ -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(); diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index a037e50593737..9e4ce137f77ea 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -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` (:meth:`DataFrame.applymap`) 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 @@ -59,7 +59,7 @@ 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") @@ -67,6 +67,8 @@ Also, note that :meth:`Categorical.map` implicitly has had its ``na_action`` set 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. +Notice also that :meth:`DataFrame.applymap` has been renamed to :meth:`DataFrame.map` (:issue:`52353`). + .. _whatsnew_210.enhancements.other: Other enhancements @@ -175,6 +177,7 @@ Deprecations - Deprecated making :meth:`Series.apply` return a :class:`DataFrame` when the passed-in callable returns a :class:`Series` object. In the future this will return a :class:`Series` whose values are themselves :class:`Series`. This pattern was very slow and it's recommended to use alternative methods to archive the same goal (:issue:`52116`) - Deprecated parameter ``convert_type`` in :meth:`Series.apply` (:issue:`52140`) - Deprecated ``freq`` parameter in :class:`PeriodArray` constructor, pass ``dtype`` instead (:issue:`52462`) +- Deprecated :meth:`DataFrame.applymap`. Use the new :meth:`DataFrame.map` method instead (:issue:`52353`) - .. --------------------------------------------------------------------------- diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 7ae7653c04bd4..398e59ca137ad 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -9684,7 +9684,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. @@ -9776,7 +9776,7 @@ def apply( ) return op.apply().__finalize__(self, method="apply") - def applymap( + def map( self, func: PythonFuncType, na_action: str | None = None, **kwargs ) -> DataFrame: """ @@ -9818,7 +9818,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 @@ -9835,7 +9835,7 @@ def applymap( 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 @@ -9862,6 +9862,47 @@ def infer(x): return self.apply(infer).__finalize__(self, "applymap") + def applymap( + self, func: PythonFuncType, na_action: str | None = None, **kwargs + ) -> DataFrame: + """ + Apply a function to a {klass} 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`. + """ + 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 diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 2f9e2e55cea4a..3207601815480 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -5954,7 +5954,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`. diff --git a/pandas/core/series.py b/pandas/core/series.py index 04927d64a602d..81173efd93521 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -4256,7 +4256,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 ----- diff --git a/pandas/core/shared_docs.py b/pandas/core/shared_docs.py index 30ec5baf227eb..23806dfb9fc36 100644 --- a/pandas/core/shared_docs.py +++ b/pandas/core/shared_docs.py @@ -608,7 +608,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. diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 26ec4844d2a75..e2c5ed2ea92b6 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -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 @@ -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 diff --git a/pandas/io/json/_json.py b/pandas/io/json/_json.py index ef8c7550476e3..f73d372a920a8 100644 --- a/pandas/io/json/_json.py +++ b/pandas/io/json/_json.py @@ -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() diff --git a/pandas/tests/frame/methods/test_to_csv.py b/pandas/tests/frame/methods/test_to_csv.py index 8a68876d7e11a..639c6f9d73511 100644 --- a/pandas/tests/frame/methods/test_to_csv.py +++ b/pandas/tests/frame/methods/test_to_csv.py @@ -997,9 +997,7 @@ def test_to_csv_date_format(self, datetime_frame): # Check that the data was put in the specified format test = read_csv(path, index_col=0) - datetime_frame_int = datetime_frame.applymap( - lambda x: int(x.strftime("%Y%m%d")) - ) + datetime_frame_int = datetime_frame.map(lambda x: int(x.strftime("%Y%m%d"))) datetime_frame_int.index = datetime_frame_int.index.map( lambda x: int(x.strftime("%Y%m%d")) ) @@ -1010,9 +1008,7 @@ def test_to_csv_date_format(self, datetime_frame): # Check that the data was put in the specified format test = read_csv(path, index_col=0) - datetime_frame_str = datetime_frame.applymap( - lambda x: x.strftime("%Y-%m-%d") - ) + datetime_frame_str = datetime_frame.map(lambda x: x.strftime("%Y-%m-%d")) datetime_frame_str.index = datetime_frame_str.index.map( lambda x: x.strftime("%Y-%m-%d") ) @@ -1025,7 +1021,7 @@ def test_to_csv_date_format(self, datetime_frame): test = read_csv(path, index_col=0) - datetime_frame_columns = datetime_frame_columns.applymap( + datetime_frame_columns = datetime_frame_columns.map( lambda x: int(x.strftime("%Y%m%d")) ) # Columns don't get converted to ints by read_csv diff --git a/pandas/tests/io/sas/test_sas7bdat.py b/pandas/tests/io/sas/test_sas7bdat.py index 348d2382976c3..d56139d32b1da 100644 --- a/pandas/tests/io/sas/test_sas7bdat.py +++ b/pandas/tests/io/sas/test_sas7bdat.py @@ -266,12 +266,12 @@ def test_max_sas_date(datapath): df = pd.read_sas(fname, encoding="iso-8859-1") # SAS likes to left pad strings with spaces - lstrip before comparing - df = df.applymap(lambda x: x.lstrip() if isinstance(x, str) else x) + df = df.map(lambda x: x.lstrip() if isinstance(x, str) else x) # GH 19732: Timestamps imported from sas will incur floating point errors try: df["dt_as_dt"] = df["dt_as_dt"].dt.round("us") except pd._libs.tslibs.np_datetime.OutOfBoundsDatetime: - df = df.applymap(round_datetime_to_ms) + df = df.map(round_datetime_to_ms) except AttributeError: df["dt_as_dt"] = df["dt_as_dt"].apply(round_datetime_to_ms) # if there are any date/times > pandas.Timestamp.max then ALL in that chunk @@ -302,12 +302,12 @@ def test_max_sas_date_iterator(datapath): results = [] for df in pd.read_sas(fname, encoding="iso-8859-1", chunksize=1): # SAS likes to left pad strings with spaces - lstrip before comparing - df = df.applymap(lambda x: x.lstrip() if isinstance(x, str) else x) + df = df.map(lambda x: x.lstrip() if isinstance(x, str) else x) # GH 19732: Timestamps imported from sas will incur floating point errors try: df["dt_as_dt"] = df["dt_as_dt"].dt.round("us") except pd._libs.tslibs.np_datetime.OutOfBoundsDatetime: - df = df.applymap(round_datetime_to_ms) + df = df.map(round_datetime_to_ms) except AttributeError: df["dt_as_dt"] = df["dt_as_dt"].apply(round_datetime_to_ms) df.reset_index(inplace=True, drop=True) diff --git a/pandas/tests/io/test_html.py b/pandas/tests/io/test_html.py index 047918d4694e0..4398637237b42 100644 --- a/pandas/tests/io/test_html.py +++ b/pandas/tests/io/test_html.py @@ -131,7 +131,7 @@ def test_to_html_compat(self): r_idx_names=False, ) # pylint: disable-next=consider-using-f-string - .applymap("{:.3f}".format).astype(float) + .map("{:.3f}".format).astype(float) ) out = df.to_html() res = self.read_html(out, attrs={"class": "dataframe"}, index_col=0)[0] diff --git a/pandas/tests/io/test_sql.py b/pandas/tests/io/test_sql.py index cd1f0ce6fcfd8..e53daf2f63d10 100644 --- a/pandas/tests/io/test_sql.py +++ b/pandas/tests/io/test_sql.py @@ -2137,13 +2137,13 @@ def test_datetime_time(self, sqlite_buildin): sqlite_conn = sqlite_buildin assert sql.to_sql(df, "test_time2", sqlite_conn, index=False) == 2 res = sql.read_sql_query("SELECT * FROM test_time2", sqlite_conn) - ref = df.applymap(lambda _: _.strftime("%H:%M:%S.%f")) + ref = df.map(lambda _: _.strftime("%H:%M:%S.%f")) tm.assert_frame_equal(ref, res) # check if adapter is in place # then test if sqlalchemy is unaffected by the sqlite adapter assert sql.to_sql(df, "test_time3", self.conn, index=False) == 2 if self.flavor == "sqlite": res = sql.read_sql_query("SELECT * FROM test_time3", self.conn) - ref = df.applymap(lambda _: _.strftime("%H:%M:%S.%f")) + ref = df.map(lambda _: _.strftime("%H:%M:%S.%f")) tm.assert_frame_equal(ref, res) res = sql.read_sql_table("test_time3", self.conn) tm.assert_frame_equal(df, res) @@ -2951,7 +2951,7 @@ def test_datetime_time(self, tz_aware): res = read_sql_query("SELECT * FROM test_time", self.conn) if self.flavor == "sqlite": # comes back as strings - expected = df.applymap(lambda _: _.strftime("%H:%M:%S.%f")) + expected = df.map(lambda _: _.strftime("%H:%M:%S.%f")) tm.assert_frame_equal(res, expected) def _get_index_columns(self, tbl_name): From 6427c91c24ee98b5c5ade74639852fb5c3fb0190 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sun, 2 Apr 2023 17:19:33 +0100 Subject: [PATCH 02/16] fix test failure --- pandas/tests/generic/test_finalize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index cdab112e7ad86..ec8907c3e0efe 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -159,7 +159,7 @@ operator.methodcaller("melt", id_vars=["A"], value_vars=["B"]), ), pytest.param( - (pd.DataFrame, frame_data, operator.methodcaller("applymap", lambda x: x)) + (pd.DataFrame, frame_data, operator.methodcaller("map", lambda x: x)) ), pytest.param( ( From 63d7663357ab4b77d6da2ced062cf62c0870588d Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sun, 2 Apr 2023 17:31:16 +0100 Subject: [PATCH 03/16] fix precommit --- pandas/tests/generic/test_finalize.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index ec8907c3e0efe..3c4ea5bd1fb2c 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -158,9 +158,7 @@ ({"A": ["a", "b", "c"], "B": [1, 3, 5], "C": [2, 4, 6]},), operator.methodcaller("melt", id_vars=["A"], value_vars=["B"]), ), - pytest.param( - (pd.DataFrame, frame_data, operator.methodcaller("map", lambda x: x)) - ), + pytest.param((pd.DataFrame, frame_data, operator.methodcaller("map", lambda x: x))), pytest.param( ( pd.DataFrame, From 08d4425a7ee98abf83d7f5f2e163bdda783c51f6 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sun, 2 Apr 2023 18:19:44 +0100 Subject: [PATCH 04/16] fix code_checks.sh --- pandas/core/frame.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 398e59ca137ad..53c5fef61d19a 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -9827,7 +9827,7 @@ def map( >>> 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 @@ -9840,7 +9840,7 @@ def map( 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 @@ -9860,7 +9860,7 @@ def map( 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 @@ -9895,6 +9895,19 @@ def applymap( 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.", From 0cdbfc3666d497a555af73d3334779d08a072d74 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sun, 2 Apr 2023 19:58:16 +0100 Subject: [PATCH 05/16] fix slow tests --- doc/source/whatsnew/v2.1.0.rst | 4 ++-- pandas/tests/io/test_html.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 9e4ce137f77ea..23538c373d0f1 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -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.map` (:meth:`DataFrame.applymap`) applies the callable to all elements of the :class:`DataFrame`, +Similarly, :meth:`DataFrame.map` (previously named :meth:`DataFrame.applymap`) 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 @@ -67,7 +67,7 @@ Also, note that :meth:`Categorical.map` implicitly has had its ``na_action`` set 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. -Notice also that :meth:`DataFrame.applymap` has been renamed to :meth:`DataFrame.map` (:issue:`52353`). +Notice also that in this version, :meth:`DataFrame.applymap` has been renamed to :meth:`DataFrame.map` (:issue:`52353`). .. _whatsnew_210.enhancements.other: diff --git a/pandas/tests/io/test_html.py b/pandas/tests/io/test_html.py index 4398637237b42..4bd4e0cd7146f 100644 --- a/pandas/tests/io/test_html.py +++ b/pandas/tests/io/test_html.py @@ -682,8 +682,8 @@ def try_remove_ws(x): "Hamilton Bank, NA", "The Citizens Savings Bank", ] - dfnew = df.applymap(try_remove_ws).replace(old, new) - gtnew = ground_truth.applymap(try_remove_ws) + dfnew = df.map(try_remove_ws).replace(old, new) + gtnew = ground_truth.map(try_remove_ws) converted = dfnew date_cols = ["Closing Date", "Updated Date"] converted[date_cols] = converted[date_cols].apply(to_datetime) From 1e5b5c5230622a57075188185ad0ed361d3bc4ce Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Tue, 4 Apr 2023 07:53:30 +0100 Subject: [PATCH 06/16] minor doc update --- pandas/core/frame.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 53c5fef61d19a..1ab9904705f4b 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -9782,6 +9782,10 @@ def map( """ 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. @@ -9809,6 +9813,8 @@ def map( -------- DataFrame.apply : Apply a function along input axis of DataFrame. DataFrame.replace: Replace values given in `to_replace` with `value`. + DataFrame.applymap : Apply a function elementwise on a DataFrame (deprecated). + Series.map : Apply a function elementwise on a Series. Examples -------- From 69f7c08245f6952b07fd8ddeada0b18316051728 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Wed, 5 Apr 2023 23:43:13 +0100 Subject: [PATCH 07/16] sall cleanup --- pandas/core/frame.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 1ab9904705f4b..223a95d416626 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -9813,7 +9813,6 @@ def map( -------- DataFrame.apply : Apply a function along input axis of DataFrame. DataFrame.replace: Replace values given in `to_replace` with `value`. - DataFrame.applymap : Apply a function elementwise on a DataFrame (deprecated). Series.map : Apply a function elementwise on a Series. Examples From e1c30b872366342a0c973dc235b67cc6e1cdd353 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Thu, 6 Apr 2023 08:23:55 +0100 Subject: [PATCH 08/16] update df.applymap -> df.map in style.ipynb --- doc/source/user_guide/style.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/user_guide/style.ipynb b/doc/source/user_guide/style.ipynb index 79596c946c068..7ae19dfe8021e 100644 --- a/doc/source/user_guide/style.ipynb +++ b/doc/source/user_guide/style.ipynb @@ -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", "\n", "[table]: ../reference/api/pandas.io.formats.style.Styler.set_table_styles.rst\n", "[styler]: ../reference/api/pandas.io.formats.style.Styler.rst\n", @@ -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" ] }, { From 8bad43bbca021d934802b97f1dd3145da7b1c8fb Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Fri, 7 Apr 2023 21:05:57 +0100 Subject: [PATCH 09/16] fix tests/frame/methods/test_map.py --- ci/polars | 12 ------ doc/source/whatsnew/v2.1.0.rst | 2 +- pandas/tests/frame/methods/test_map.py | 52 +++++++++++++++----------- 3 files changed, 31 insertions(+), 35 deletions(-) delete mode 100644 ci/polars diff --git a/ci/polars b/ci/polars deleted file mode 100644 index f39a9a2616c03..0000000000000 --- a/ci/polars +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -set -euo pipefail -wget https://s3.amazonaws.com/hubway-data/20{16,17,18,19,20,21,22}{01,02,03,04,05,06,07,08,09,10,11,12}-hubway-tripdata.zip -wget https://s3.amazonaws.com/hubway-data/2018{01,02,03,04}-hubway-tripdata.zip -wget https://s3.amazonaws.com/hubway-data/2018{05,06,07,08,09,10,11,12}-bluebikes-tripdata.zip -wget https://s3.amazonaws.com/hubway-data/20{19,20,21,22}{01,02,03,04,05,06,07,08,09,10,11,12}-bluebikes-tripdata.zip -wget https://s3.amazonaws.com/hubway-data/2023{01,02}-bluebikes-tripdata.zip -find . -iname "*-hubway-*.zip" -exec unzip {} \; -find . -iname "*-bluebikes-*.zip" -exec unzip {} \; -rm -f *-hubway-*.zip -rm -f *-bluebikes-*.zip -wget https://s3.amazonaws.com/hubway-data/current_bluebikes_stations.csv diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 23538c373d0f1..c4d6633316a92 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -176,8 +176,8 @@ Deprecations - Deprecated :meth:`DataFrame.swapaxes` and :meth:`Series.swapaxes`, use :meth:`DataFrame.transpose` or :meth:`Series.transpose` instead (:issue:`51946`) - Deprecated making :meth:`Series.apply` return a :class:`DataFrame` when the passed-in callable returns a :class:`Series` object. In the future this will return a :class:`Series` whose values are themselves :class:`Series`. This pattern was very slow and it's recommended to use alternative methods to archive the same goal (:issue:`52116`) - Deprecated parameter ``convert_type`` in :meth:`Series.apply` (:issue:`52140`) -- Deprecated ``freq`` parameter in :class:`PeriodArray` constructor, pass ``dtype`` instead (:issue:`52462`) - Deprecated :meth:`DataFrame.applymap`. Use the new :meth:`DataFrame.map` method instead (:issue:`52353`) +- Deprecated ``freq`` parameter in :class:`PeriodArray` constructor, pass ``dtype`` instead (:issue:`52462`) - .. --------------------------------------------------------------------------- diff --git a/pandas/tests/frame/methods/test_map.py b/pandas/tests/frame/methods/test_map.py index 0dac96cda9b54..10424c3acd932 100644 --- a/pandas/tests/frame/methods/test_map.py +++ b/pandas/tests/frame/methods/test_map.py @@ -13,13 +13,13 @@ import pandas._testing as tm -def test_applymap(float_frame): - result = float_frame.applymap(lambda x: x * 2) +def test_map(float_frame): + result = float_frame.map(lambda x: x * 2) tm.assert_frame_equal(result, float_frame * 2) - float_frame.applymap(type) + float_frame.map(type) # GH 465: function returning tuples - result = float_frame.applymap(lambda x: (x, x))["A"][0] + result = float_frame.map(lambda x: (x, x))["A"][0] assert isinstance(result, tuple) @@ -27,7 +27,7 @@ def test_applymap(float_frame): def test_applymap_float_object_conversion(val): # GH 2909: object conversion to float in constructor? df = DataFrame(data=[val, "a"]) - result = df.applymap(lambda x: x).dtypes[0] + result = df.map(lambda x: x).dtypes[0] assert result == object @@ -41,7 +41,7 @@ def test_applymap_keeps_dtype(na_action): def func(x): return str.upper(x) if not pd.isna(x) else x - result = df.applymap(func, na_action=na_action) + result = df.map(func, na_action=na_action) expected_sparse = pd.array(["A", np.nan, "B"], dtype=pd.SparseDtype(object)) expected_arr = expected_sparse.astype(object) @@ -49,7 +49,7 @@ def func(x): tm.assert_frame_equal(result, expected) - result_empty = df.iloc[:0, :].applymap(func, na_action=na_action) + result_empty = df.iloc[:0, :].map(func, na_action=na_action) expected_empty = expected.iloc[:0, :] tm.assert_frame_equal(result_empty, expected_empty) @@ -61,9 +61,9 @@ def test_applymap_str(): cols = ["a", "a", "a", "a"] df.columns = cols - expected = df2.applymap(str) + expected = df2.map(str) expected.columns = cols - result = df.applymap(str) + result = df.map(str) tm.assert_frame_equal(result, expected) @@ -75,7 +75,7 @@ def test_applymap_datetimelike(col, val): # datetime/timedelta df = DataFrame(np.random.random((3, 4))) df[col] = val - result = df.applymap(str) + result = df.map(str) assert result.loc[0, col] == str(df.loc[0, col]) @@ -91,24 +91,24 @@ def test_applymap_datetimelike(col, val): @pytest.mark.parametrize("func", [round, lambda x: x]) def test_applymap_empty(expected, func): # GH 8222 - result = expected.applymap(func) + result = expected.map(func) tm.assert_frame_equal(result, expected) def test_applymap_kwargs(): # GH 40652 - result = DataFrame([[1, 2], [3, 4]]).applymap(lambda x, y: x + y, y=2) + result = DataFrame([[1, 2], [3, 4]]).map(lambda x, y: x + y, y=2) expected = DataFrame([[3, 4], [5, 6]]) tm.assert_frame_equal(result, expected) def test_applymap_na_ignore(float_frame): # GH 23803 - strlen_frame = float_frame.applymap(lambda x: len(str(x))) + strlen_frame = float_frame.map(lambda x: len(str(x))) float_frame_with_na = float_frame.copy() mask = np.random.randint(0, 2, size=float_frame.shape, dtype=bool) float_frame_with_na[mask] = pd.NA - strlen_frame_na_ignore = float_frame_with_na.applymap( + strlen_frame_na_ignore = float_frame_with_na.map( lambda x: len(str(x)), na_action="ignore" ) strlen_frame_with_na = strlen_frame.copy() @@ -124,7 +124,7 @@ def func(x): return (x.hour, x.day, x.month) # it works! - DataFrame(ser).applymap(func) + DataFrame(ser).map(func) def test_applymap_box(): @@ -144,7 +144,7 @@ def test_applymap_box(): } ) - result = df.applymap(lambda x: type(x).__name__) + result = df.map(lambda x: type(x).__name__) expected = DataFrame( { "a": ["Timestamp", "Timestamp"], @@ -161,8 +161,8 @@ def test_frame_applymap_dont_convert_datetime64(): df = DataFrame({"x1": [datetime(1996, 1, 1)]}) - df = df.applymap(lambda x: x + BDay()) - df = df.applymap(lambda x: x + BDay()) + df = df.map(lambda x: x + BDay()) + df = df.map(lambda x: x + BDay()) result = df.x1.dtype assert result == "M8[ns]" @@ -182,7 +182,7 @@ def non_reducing_function(val): for func in [reducing_function, non_reducing_function]: del values[:] - df.applymap(func) + df.map(func) assert values == df.a.to_list() @@ -193,7 +193,7 @@ def test_applymap_type(): index=["a", "b", "c"], ) - result = df.applymap(type) + result = df.map(type) expected = DataFrame( {"col1": [int, str, type], "col2": [float, datetime, float]}, index=["a", "b", "c"], @@ -201,7 +201,15 @@ def test_applymap_type(): tm.assert_frame_equal(result, expected) -def test_applymap_invalid_na_action(float_frame): +def test_map_invalid_na_action(float_frame): # GH 23803 with pytest.raises(ValueError, match="na_action must be .*Got 'abc'"): - float_frame.applymap(lambda x: len(str(x)), na_action="abc") + float_frame.map(lambda x: len(str(x)), na_action="abc") + + +def test_applymap_deprecated(): + # GH52353 + df = DataFrame({"a": [1, 2, 3]}) + msg = "DataFrame.applymap has been deprecated. Use DataFrame.map instead." + with tm.assert_produces_warning(FutureWarning, match=msg): + df.applymap(lambda x: x) From 763555084d207f6d81b17a1a223c90e53d7b09c4 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Fri, 7 Apr 2023 23:01:11 +0100 Subject: [PATCH 10/16] fix names --- pandas/tests/frame/methods/test_map.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pandas/tests/frame/methods/test_map.py b/pandas/tests/frame/methods/test_map.py index 10424c3acd932..596ef453b2e02 100644 --- a/pandas/tests/frame/methods/test_map.py +++ b/pandas/tests/frame/methods/test_map.py @@ -24,7 +24,7 @@ def test_map(float_frame): @pytest.mark.parametrize("val", [1, 1.0]) -def test_applymap_float_object_conversion(val): +def test_map_float_object_conversion(val): # GH 2909: object conversion to float in constructor? df = DataFrame(data=[val, "a"]) result = df.map(lambda x: x).dtypes[0] @@ -32,7 +32,7 @@ def test_applymap_float_object_conversion(val): @pytest.mark.parametrize("na_action", [None, "ignore"]) -def test_applymap_keeps_dtype(na_action): +def test_map_keeps_dtype(na_action): # GH52219 arr = Series(["a", np.nan, "b"]) sparse_arr = arr.astype(pd.SparseDtype(object)) @@ -54,7 +54,7 @@ def func(x): tm.assert_frame_equal(result_empty, expected_empty) -def test_applymap_str(): +def test_map_str(): # GH 2786 df = DataFrame(np.random.random((3, 4))) df2 = df.copy() @@ -71,7 +71,7 @@ def test_applymap_str(): "col, val", [["datetime", Timestamp("20130101")], ["timedelta", pd.Timedelta("1 min")]], ) -def test_applymap_datetimelike(col, val): +def test_map_datetimelike(col, val): # datetime/timedelta df = DataFrame(np.random.random((3, 4))) df[col] = val @@ -89,20 +89,20 @@ def test_applymap_datetimelike(col, val): ], ) @pytest.mark.parametrize("func", [round, lambda x: x]) -def test_applymap_empty(expected, func): +def test_map_empty(expected, func): # GH 8222 result = expected.map(func) tm.assert_frame_equal(result, expected) -def test_applymap_kwargs(): +def test_map_kwargs(): # GH 40652 result = DataFrame([[1, 2], [3, 4]]).map(lambda x, y: x + y, y=2) expected = DataFrame([[3, 4], [5, 6]]) tm.assert_frame_equal(result, expected) -def test_applymap_na_ignore(float_frame): +def test_map_na_ignore(float_frame): # GH 23803 strlen_frame = float_frame.map(lambda x: len(str(x))) float_frame_with_na = float_frame.copy() @@ -116,7 +116,7 @@ def test_applymap_na_ignore(float_frame): tm.assert_frame_equal(strlen_frame_na_ignore, strlen_frame_with_na) -def test_applymap_box_timestamps(): +def test_map_box_timestamps(): # GH 2689, GH 2627 ser = Series(date_range("1/1/2000", periods=10)) @@ -127,7 +127,7 @@ def func(x): DataFrame(ser).map(func) -def test_applymap_box(): +def test_map_box(): # ufunc will not be boxed. Same test cases as the test_map_box df = DataFrame( { @@ -156,7 +156,7 @@ def test_applymap_box(): tm.assert_frame_equal(result, expected) -def test_frame_applymap_dont_convert_datetime64(): +def test_frame_map_dont_convert_datetime64(): from pandas.tseries.offsets import BDay df = DataFrame({"x1": [datetime(1996, 1, 1)]}) @@ -168,7 +168,7 @@ def test_frame_applymap_dont_convert_datetime64(): assert result == "M8[ns]" -def test_applymap_function_runs_once(): +def test_map_function_runs_once(): df = DataFrame({"a": [1, 2, 3]}) values = [] # Save values function is applied to @@ -186,7 +186,7 @@ def non_reducing_function(val): assert values == df.a.to_list() -def test_applymap_type(): +def test_map_type(): # GH 46719 df = DataFrame( {"col1": [3, "string", float], "col2": [0.25, datetime(2020, 1, 1), np.nan]}, From 6ef09ae83ed73b045a126c67c63aaa3a7e5bccbe Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Tue, 11 Apr 2023 18:37:44 +0100 Subject: [PATCH 11/16] fix doc string --- pandas/core/frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 284290ce53b97..7a19c337d9ba5 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -9872,7 +9872,7 @@ def applymap( self, func: PythonFuncType, na_action: str | None = None, **kwargs ) -> DataFrame: """ - Apply a function to a {klass} elementwise. + Apply a function to a Dataframe elementwise. .. deprecated:: 2.1.0 From 0294062a2aa0482052644d41cab8c5943e4fc990 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Fri, 14 Apr 2023 23:28:08 +0100 Subject: [PATCH 12/16] fix --- doc/source/whatsnew/v2.1.0.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 82c75f3caf9ec..9c4c5ed33758b 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -231,7 +231,9 @@ Deprecations - Deprecated logical operations (``|``, ``&``, ``^``) between pandas objects and dtype-less sequences (e.g. ``list``, ``tuple``), wrap a sequence in a :class:`Series` or numpy array before operating instead (:issue:`51521`) - Deprecated making :meth:`Series.apply` return a :class:`DataFrame` when the passed-in callable returns a :class:`Series` object. In the future this will return a :class:`Series` whose values are themselves :class:`Series`. This pattern was very slow and it's recommended to use alternative methods to archive the same goal (:issue:`52116`) - Deprecated parameter ``convert_type`` in :meth:`Series.apply` (:issue:`52140`) -- Deprecated :meth:`DataFrame.applymap`. Use the new :meth:`DataFrame.map` method instead (:issue:`52353- Deprecated the "fastpath" keyword in :class:`Categorical` constructor, use :meth:`Categorical.from_codes` instead (:issue:`20110`) +- Deprecated passing a dictionary to :meth:`.SeriesGroupBy.agg`; pass a list of aggregations instead (:issue:`50684`) +- Deprecated :meth:`DataFrame.applymap`. Use the new :meth:`DataFrame.map` method instead (:issue:`52353) +- Deprecated the "fastpath" keyword in :class:`Categorical` constructor, use :meth:`Categorical.from_codes` instead (:issue:`20110`) - Deprecated the methods :meth:`Series.bool` and :meth:`DataFrame.bool` (:issue:`51749`) - Deprecated unused "closed" and "normalize" keywords in the :class:`DatetimeIndex` constructor (:issue:`52628`) - Deprecated unused "closed" keyword in the :class:`TimedeltaIndex` constructor (:issue:`52628`) From ce0f2f051fd871b880524d74da42e6bc17684146 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sat, 15 Apr 2023 11:01:00 +0100 Subject: [PATCH 13/16] fix whatsnew reference endstring --- doc/source/whatsnew/v2.1.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 9c4c5ed33758b..ee7b91dbbf383 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -232,7 +232,7 @@ Deprecations - Deprecated making :meth:`Series.apply` return a :class:`DataFrame` when the passed-in callable returns a :class:`Series` object. In the future this will return a :class:`Series` whose values are themselves :class:`Series`. This pattern was very slow and it's recommended to use alternative methods to archive the same goal (:issue:`52116`) - Deprecated parameter ``convert_type`` in :meth:`Series.apply` (:issue:`52140`) - Deprecated passing a dictionary to :meth:`.SeriesGroupBy.agg`; pass a list of aggregations instead (:issue:`50684`) -- Deprecated :meth:`DataFrame.applymap`. Use the new :meth:`DataFrame.map` method instead (:issue:`52353) +- Deprecated :meth:`DataFrame.applymap`. Use the new :meth:`DataFrame.map` method instead (:issue:`52353`) - Deprecated the "fastpath" keyword in :class:`Categorical` constructor, use :meth:`Categorical.from_codes` instead (:issue:`20110`) - Deprecated the methods :meth:`Series.bool` and :meth:`DataFrame.bool` (:issue:`51749`) - Deprecated unused "closed" and "normalize" keywords in the :class:`DatetimeIndex` constructor (:issue:`52628`) From 399437622e6e34943bc0f23c4373d8d67bed9088 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sat, 15 Apr 2023 12:24:37 +0100 Subject: [PATCH 14/16] fix whatsnew alphabetic sorting --- doc/source/whatsnew/v2.1.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index ee7b91dbbf383..e2489a52c8e57 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -225,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`) @@ -232,7 +233,6 @@ Deprecations - Deprecated making :meth:`Series.apply` return a :class:`DataFrame` when the passed-in callable returns a :class:`Series` object. In the future this will return a :class:`Series` whose values are themselves :class:`Series`. This pattern was very slow and it's recommended to use alternative methods to archive the same goal (:issue:`52116`) - Deprecated parameter ``convert_type`` in :meth:`Series.apply` (:issue:`52140`) - Deprecated passing a dictionary to :meth:`.SeriesGroupBy.agg`; pass a list of aggregations instead (:issue:`50684`) -- Deprecated :meth:`DataFrame.applymap`. Use the new :meth:`DataFrame.map` method instead (:issue:`52353`) - Deprecated the "fastpath" keyword in :class:`Categorical` constructor, use :meth:`Categorical.from_codes` instead (:issue:`20110`) - Deprecated the methods :meth:`Series.bool` and :meth:`DataFrame.bool` (:issue:`51749`) - Deprecated unused "closed" and "normalize" keywords in the :class:`DatetimeIndex` constructor (:issue:`52628`) From 390ac797eab541ecaae54d1a54d1b361074b0289 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sun, 16 Apr 2023 14:29:53 +0100 Subject: [PATCH 15/16] update whatsnew --- doc/source/whatsnew/v2.1.0.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index e2489a52c8e57..cd525ba42d421 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -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.map` (previously named :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 @@ -63,12 +63,12 @@ and ``na_action="ignore"`` did not work correctly for any ``ExtensionArray`` sub 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. -Notice also that in this version, :meth:`DataFrame.applymap` has been renamed to :meth:`DataFrame.map` (:issue:`52353`). - .. _whatsnew_210.enhancements.other: Other enhancements From c1d0b5056d1ddbc4baf2c95c7ea875dc47b70eef Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sun, 16 Apr 2023 14:40:40 +0100 Subject: [PATCH 16/16] update whatsnew II --- doc/source/whatsnew/v2.1.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index cd525ba42d421..c039613ddf8f8 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -63,7 +63,7 @@ and ``na_action="ignore"`` did not work correctly for any ``ExtensionArray`` sub 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`). +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 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