From 1e6ac769a3d65a6e66ca8986125eb1d2bf31297e Mon Sep 17 00:00:00 2001 From: pedrocariellof Date: Sun, 30 Jun 2024 23:30:52 -0300 Subject: [PATCH 1/3] Series.isconstant() method added --- doc/source/whatsnew/v3.0.0.rst | 2 + pandas/core/series.py | 41 ++++++++++++ .../tests/series/methods/test_isconstant.py | 67 +++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 pandas/tests/series/methods/test_isconstant.py diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index f4ce36db32813..a4e961a71ab75 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -43,6 +43,7 @@ Other enhancements - :meth:`DataFrame.cummin`, :meth:`DataFrame.cummax`, :meth:`DataFrame.cumprod` and :meth:`DataFrame.cumsum` methods now have a ``numeric_only`` parameter (:issue:`53072`) - :meth:`DataFrame.fillna` and :meth:`Series.fillna` can now accept ``value=None``; for non-object dtype the corresponding NA value will be used (:issue:`57723`) - :meth:`Series.cummin` and :meth:`Series.cummax` now supports :class:`CategoricalDtype` (:issue:`52335`) +- :meth:`Series.isconstant` checks if a :class:`Series` has constant values, with an optional parameter to drop NaN values (:issue:`58806`) - :meth:`Series.plot` now correctly handle the ``ylabel`` parameter for pie charts, allowing for explicit control over the y-axis label (:issue:`58239`) - Support reading Stata 110-format (Stata 7) dta files (:issue:`47176`) - @@ -200,6 +201,7 @@ starting with 3.0, so it can be safely removed from your code. Other Deprecations ^^^^^^^^^^^^^^^^^^ +- Deprecated :meth:`series.values`, now don't drops the ``tz`` from ``dt64tz``, converts ``interval`` to ``object``, converts ``period`` to ``object``. - Deprecated :meth:`Timestamp.utcfromtimestamp`, use ``Timestamp.fromtimestamp(ts, "UTC")`` instead (:issue:`56680`) - Deprecated :meth:`Timestamp.utcnow`, use ``Timestamp.now("UTC")`` instead (:issue:`56680`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.all`, :meth:`DataFrame.min`, :meth:`DataFrame.max`, :meth:`DataFrame.sum`, :meth:`DataFrame.prod`, :meth:`DataFrame.mean`, :meth:`DataFrame.median`, :meth:`DataFrame.sem`, :meth:`DataFrame.var`, :meth:`DataFrame.std`, :meth:`DataFrame.skew`, :meth:`DataFrame.kurt`, :meth:`Series.all`, :meth:`Series.min`, :meth:`Series.max`, :meth:`Series.sum`, :meth:`Series.prod`, :meth:`Series.mean`, :meth:`Series.median`, :meth:`Series.sem`, :meth:`Series.var`, :meth:`Series.std`, :meth:`Series.skew`, and :meth:`Series.kurt`. (:issue:`57087`) diff --git a/pandas/core/series.py b/pandas/core/series.py index 97a53650ec5ff..d49f00510c419 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -25,6 +25,7 @@ import warnings import numpy as np +import numba from pandas._libs import ( lib, @@ -5423,6 +5424,46 @@ def isnull(self) -> Series: """ return super().isnull() + def isconstant(self, dropna = False): + """ + Return if the series has constant values. + + Parameters + ---------- + dropna : bool, default False + If True, NaN values will be ignored. If False, NaN values will be considered + in the determination of whether the series has constant values. + + Returns + ------- + bool + True if the series has constant values, False otherwise. + + Examples + -------- + >>> s = pd.Series([2, 2, 2, 2]) + >>> s.isconstant() + True + + >>> s = pd.Series([2, 2, 3]) + >>> s.isconstant() + False + + >>> s = pd.Series([2, 2, 2, np.nan]) + >>> s.isconstant(dropna=True) + True + + >>> s = pd.Series([2, 2, 2, np.nan]) + >>> s.isconstant(dropna=False) + False + """ + v = self.to_numpy() + if dropna: + v = remove_na_arraylike(v) + if v.shape[0] == 0 or not notna(v).any(): + return True + return (v[0] == v).all() + # error: Cannot determine type of 'notna' @doc(NDFrame.notna, klass=_shared_doc_kwargs["klass"]) # type: ignore[has-type] def notna(self) -> Series: diff --git a/pandas/tests/series/methods/test_isconstant.py b/pandas/tests/series/methods/test_isconstant.py new file mode 100644 index 0000000000000..116f9d6986b40 --- /dev/null +++ b/pandas/tests/series/methods/test_isconstant.py @@ -0,0 +1,67 @@ +import numpy as np +import pytest + +from pandas import ( + Series, +) + +class TestSeriesIsConstant: + def test_isconstant(self): + s = Series([2, 2, 2, 2]) + result = s.isconstant() + assert result + + s = Series([2, 2, 2, 3]) + result = s.isconstant() + assert not result + + s = Series([]) + result = s.isconstant() + assert result + + s = Series([5]) + result = s.isconstant() + assert result + + def test_isconstant_with_nan(self): + s = Series([np.nan]) + result = s.isconstant() + assert result + + s = Series([np.nan,np.nan]) + result = s.isconstant() + assert result + + s = Series([np.nan,1]) + result = s.isconstant() + assert not result + + s = Series([np.nan, np.nan, 1]) + result = s.isconstant() + assert not result + + def test_isconstant_with_nan_dropna(self): + s = Series([np.nan]) + result = s.isconstant(True) + assert result + + s = Series([np.nan,np.nan]) + result = s.isconstant(True) + assert result + + s = Series([np.nan,1]) + result = s.isconstant(True) + assert result + + s = Series([np.nan, np.nan, 1]) + result = s.isconstant(True) + assert result + + def test_isconstant_mixed_types(self): + s = Series([2, '2', 2]) + result = s.isconstant() + assert not result + + s = Series([2, 2.0, 2]) + result = s.isconstant() + assert result \ No newline at end of file From 096cfaa0abf493ad12aafea0fdd6a2720b619e25 Mon Sep 17 00:00:00 2001 From: pedrocariellof Date: Sun, 30 Jun 2024 23:37:34 -0300 Subject: [PATCH 2/3] Adjusting the v3.0.0 file --- doc/source/whatsnew/v3.0.0.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index a4e961a71ab75..9bf4c1cd2b4a9 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -201,7 +201,6 @@ starting with 3.0, so it can be safely removed from your code. Other Deprecations ^^^^^^^^^^^^^^^^^^ -- Deprecated :meth:`series.values`, now don't drops the ``tz`` from ``dt64tz``, converts ``interval`` to ``object``, converts ``period`` to ``object``. - Deprecated :meth:`Timestamp.utcfromtimestamp`, use ``Timestamp.fromtimestamp(ts, "UTC")`` instead (:issue:`56680`) - Deprecated :meth:`Timestamp.utcnow`, use ``Timestamp.now("UTC")`` instead (:issue:`56680`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.all`, :meth:`DataFrame.min`, :meth:`DataFrame.max`, :meth:`DataFrame.sum`, :meth:`DataFrame.prod`, :meth:`DataFrame.mean`, :meth:`DataFrame.median`, :meth:`DataFrame.sem`, :meth:`DataFrame.var`, :meth:`DataFrame.std`, :meth:`DataFrame.skew`, :meth:`DataFrame.kurt`, :meth:`Series.all`, :meth:`Series.min`, :meth:`Series.max`, :meth:`Series.sum`, :meth:`Series.prod`, :meth:`Series.mean`, :meth:`Series.median`, :meth:`Series.sem`, :meth:`Series.var`, :meth:`Series.std`, :meth:`Series.skew`, and :meth:`Series.kurt`. (:issue:`57087`) From 972d87ec27e18670398521355ebdb4858ffb0e56 Mon Sep 17 00:00:00 2001 From: pedrocariellof Date: Sun, 30 Jun 2024 23:43:35 -0300 Subject: [PATCH 3/3] Precommit done --- pandas/core/series.py | 7 +++---- pandas/tests/series/methods/test_isconstant.py | 18 ++++++++---------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index d49f00510c419..3d555a56e63b2 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -25,7 +25,6 @@ import warnings import numpy as np -import numba from pandas._libs import ( lib, @@ -5424,14 +5423,14 @@ def isnull(self) -> Series: """ return super().isnull() - def isconstant(self, dropna = False): + def isconstant(self, dropna=False): """ Return if the series has constant values. Parameters ---------- dropna : bool, default False - If True, NaN values will be ignored. If False, NaN values will be considered + If True, NaN values will be ignored. If False, NaN values will be considered in the determination of whether the series has constant values. Returns @@ -5462,7 +5461,7 @@ def isconstant(self, dropna = False): v = remove_na_arraylike(v) if v.shape[0] == 0 or not notna(v).any(): return True - return (v[0] == v).all() + return (v[0] == v).all() # error: Cannot determine type of 'notna' @doc(NDFrame.notna, klass=_shared_doc_kwargs["klass"]) # type: ignore[has-type] diff --git a/pandas/tests/series/methods/test_isconstant.py b/pandas/tests/series/methods/test_isconstant.py index 116f9d6986b40..e3fd92604802a 100644 --- a/pandas/tests/series/methods/test_isconstant.py +++ b/pandas/tests/series/methods/test_isconstant.py @@ -1,9 +1,7 @@ import numpy as np -import pytest -from pandas import ( - Series, -) +from pandas import Series + class TestSeriesIsConstant: def test_isconstant(self): @@ -28,11 +26,11 @@ def test_isconstant_with_nan(self): result = s.isconstant() assert result - s = Series([np.nan,np.nan]) + s = Series([np.nan, np.nan]) result = s.isconstant() assert result - s = Series([np.nan,1]) + s = Series([np.nan, 1]) result = s.isconstant() assert not result @@ -45,11 +43,11 @@ def test_isconstant_with_nan_dropna(self): result = s.isconstant(True) assert result - s = Series([np.nan,np.nan]) + s = Series([np.nan, np.nan]) result = s.isconstant(True) assert result - s = Series([np.nan,1]) + s = Series([np.nan, 1]) result = s.isconstant(True) assert result @@ -58,10 +56,10 @@ def test_isconstant_with_nan_dropna(self): assert result def test_isconstant_mixed_types(self): - s = Series([2, '2', 2]) + s = Series([2, "2", 2]) result = s.isconstant() assert not result s = Series([2, 2.0, 2]) result = s.isconstant() - assert result \ No newline at end of file + assert result