diff --git a/ci/code_checks.sh b/ci/code_checks.sh index 62a5d81fc8f73..2fd772b3015b8 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -590,6 +590,7 @@ if [[ -z "$CHECK" || "$CHECK" == "docstrings" ]]; then pandas.Series.sparse.sp_values \ pandas.Timestamp.fromtimestamp \ pandas.api.types.infer_dtype \ + pandas.api.types.is_any_real_numeric_dtype \ pandas.api.types.is_bool_dtype \ pandas.api.types.is_categorical_dtype \ pandas.api.types.is_complex_dtype \ diff --git a/doc/source/reference/arrays.rst b/doc/source/reference/arrays.rst index aeaca7caea25d..457edb46a7ec0 100644 --- a/doc/source/reference/arrays.rst +++ b/doc/source/reference/arrays.rst @@ -653,6 +653,7 @@ Data type introspection .. autosummary:: :toctree: api/ + api.types.is_any_real_numeric_dtype api.types.is_bool_dtype api.types.is_categorical_dtype api.types.is_complex_dtype diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index addebad8b45af..b02861ac14dcf 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -760,6 +760,7 @@ Other API changes - The levels of the index of the :class:`Series` returned from ``Series.sparse.from_coo`` now always have dtype ``int32``. Previously they had dtype ``int64`` (:issue:`50926`) - :func:`to_datetime` with ``unit`` of either "Y" or "M" will now raise if a sequence contains a non-round ``float`` value, matching the ``Timestamp`` behavior (:issue:`50301`) - The methods :meth:`Series.round`, :meth:`DataFrame.__invert__`, :meth:`Series.__invert__`, :meth:`DataFrame.swapaxes`, :meth:`DataFrame.first`, :meth:`DataFrame.last`, :meth:`Series.first`, :meth:`Series.last` and :meth:`DataFrame.align` will now always return new objects (:issue:`51032`) +- Added :func:`pandas.api.types.is_any_real_numeric_dtype` to check for real numeric dtypes (:issue:`51152`) .. --------------------------------------------------------------------------- .. _whatsnew_200.deprecations: @@ -774,7 +775,7 @@ Deprecations - :meth:`Index.is_integer` has been deprecated. Use :func:`pandas.api.types.is_integer_dtype` instead (:issue:`50042`) - :meth:`Index.is_floating` has been deprecated. Use :func:`pandas.api.types.is_float_dtype` instead (:issue:`50042`) - :meth:`Index.holds_integer` has been deprecated. Use :func:`pandas.api.types.infer_dtype` instead (:issue:`50243`) -- :meth:`Index.is_numeric` has been deprecated. Use :func:`pandas.api.types.is_numeric_dtype` instead (:issue:`50042`) +- :meth:`Index.is_numeric` has been deprecated. Use :func:`pandas.api.types.is_any_real_numeric_dtype` instead (:issue:`50042`,:issue:`51152`) - :meth:`Index.is_categorical` has been deprecated. Use :func:`pandas.api.types.is_categorical_dtype` instead (:issue:`50042`) - :meth:`Index.is_object` has been deprecated. Use :func:`pandas.api.types.is_object_dtype` instead (:issue:`50042`) - :meth:`Index.is_interval` has been deprecated. Use :func:`pandas.api.types.is_intterval_dtype` instead (:issue:`50042`) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index f816b30b825b7..fb953e601735e 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -47,7 +47,7 @@ from pandas.core.dtypes.common import ( ensure_int64, ensure_platform_int, - is_any_numeric_dtype, + is_any_real_numeric_dtype, is_bool_dtype, is_categorical_dtype, is_datetime64_dtype, @@ -596,7 +596,7 @@ def _from_inferred_categories( if known_categories: # Convert to a specialized type with `dtype` if specified. - if is_any_numeric_dtype(dtype.categories): + if is_any_real_numeric_dtype(dtype.categories): cats = to_numeric(inferred_categories, errors="coerce") elif is_datetime64_dtype(dtype.categories): cats = to_datetime(inferred_categories, errors="coerce") @@ -1752,7 +1752,7 @@ def _values_for_rank(self): if mask.any(): values = values.astype("float64") values[mask] = np.nan - elif is_any_numeric_dtype(self.categories): + elif is_any_real_numeric_dtype(self.categories): values = np.array(self) else: # reorder the categories (so rank can use the float codes) diff --git a/pandas/core/dtypes/api.py b/pandas/core/dtypes/api.py index 00300c5c74e51..254abe330b8e7 100644 --- a/pandas/core/dtypes/api.py +++ b/pandas/core/dtypes/api.py @@ -1,4 +1,5 @@ from pandas.core.dtypes.common import ( + is_any_real_numeric_dtype, is_array_like, is_bool, is_bool_dtype, @@ -41,6 +42,7 @@ ) __all__ = [ + "is_any_real_numeric_dtype", "is_array_like", "is_bool", "is_bool_dtype", diff --git a/pandas/core/dtypes/common.py b/pandas/core/dtypes/common.py index 3281c7fe859e5..eaa033e3d469a 100644 --- a/pandas/core/dtypes/common.py +++ b/pandas/core/dtypes/common.py @@ -1161,9 +1161,9 @@ def is_numeric_dtype(arr_or_dtype) -> bool: ) -def is_any_numeric_dtype(arr_or_dtype) -> bool: +def is_any_real_numeric_dtype(arr_or_dtype) -> bool: """ - Check whether the provided array or dtype is of a real number dtype + Check whether the provided array or dtype is of a real number dtype. Parameters ---------- @@ -1173,19 +1173,21 @@ def is_any_numeric_dtype(arr_or_dtype) -> bool: Returns ------- boolean - Whether or not the array or dtype is of a real number dtype + Whether or not the array or dtype is of a real number dtype. Examples - ------- - >>> is_any_numeric_dtype(str) - False - >>> is_any_numeric_dtype(int) + -------- + >>> is_any_real_numeric_dtype(int) True - >>> is_any_numeric_dtype(float) + >>> is_any_real_numeric_dtype(float) True - >>> is_any_numeric_dtype(complex(1,2)) + >>> is_any_real_numeric_dtype(object) + False + >>> is_any_real_numeric_dtype(str) + False + >>> is_any_real_numeric_dtype(complex(1, 2)) False - >>> is_any_numeric_dtype(bool) + >>> is_any_real_numeric_dtype(bool) False """ return ( @@ -1721,6 +1723,7 @@ def is_all_strings(value: ArrayLike) -> bool: "is_1d_only_ea_obj", "is_all_strings", "is_any_int_dtype", + "is_any_real_numeric_dtype", "is_array_like", "is_bool", "is_bool_dtype", @@ -1749,7 +1752,6 @@ def is_all_strings(value: ArrayLike) -> bool: "is_nested_list_like", "is_number", "is_numeric_dtype", - "is_any_numeric_dtype", "is_object_dtype", "is_period_dtype", "is_re", diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 0caa8005f1ebc..ed2e3a7499728 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -88,7 +88,7 @@ ensure_int64, ensure_object, ensure_platform_int, - is_any_numeric_dtype, + is_any_real_numeric_dtype, is_bool_dtype, is_categorical_dtype, is_dtype_equal, @@ -2429,7 +2429,7 @@ def is_numeric(self) -> bool: """ warnings.warn( f"{type(self).__name__}.is_numeric is deprecated. " - "Use pandas.api.types.is_numeric_dtype instead", + "Use pandas.api.types.is_any_real_numeric_dtype instead", FutureWarning, stacklevel=find_stack_level(), ) @@ -6029,8 +6029,8 @@ def _should_compare(self, other: Index) -> bool: Check if `self == other` can ever have non-False entries. """ - if (is_bool_dtype(other) and is_any_numeric_dtype(self)) or ( - is_bool_dtype(self) and is_any_numeric_dtype(other) + if (is_bool_dtype(other) and is_any_real_numeric_dtype(self)) or ( + is_bool_dtype(self) and is_any_real_numeric_dtype(other) ): # GH#16877 Treat boolean labels passed to a numeric index as not # found. Without this fix False and True would be treated as 0 and 1 diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 49b92e0984713..fd737cdcb967f 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -27,7 +27,7 @@ from pandas.util._exceptions import find_stack_level from pandas.core.dtypes.common import ( - is_any_numeric_dtype, + is_any_real_numeric_dtype, is_categorical_dtype, is_extension_array_dtype, is_float, @@ -841,7 +841,7 @@ def _get_xticks(self, convert_period: bool = False): if convert_period and isinstance(index, ABCPeriodIndex): self.data = self.data.reindex(index=index.sort_values()) x = self.data.index.to_timestamp()._mpl_repr() - elif is_any_numeric_dtype(index): + elif is_any_real_numeric_dtype(index): # Matplotlib supports numeric values or datetime objects as # xaxis values. Taking LBYL approach here, by the time # matplotlib raises exception when using non numeric/datetime diff --git a/pandas/tests/api/test_types.py b/pandas/tests/api/test_types.py index 8c729fd19cbc7..0f89549f2ab03 100644 --- a/pandas/tests/api/test_types.py +++ b/pandas/tests/api/test_types.py @@ -8,6 +8,7 @@ class TestTypes(Base): allowed = [ + "is_any_real_numeric_dtype", "is_bool", "is_bool_dtype", "is_categorical_dtype", diff --git a/pandas/tests/dtypes/test_common.py b/pandas/tests/dtypes/test_common.py index 73abea30029b1..695ba359f60d1 100644 --- a/pandas/tests/dtypes/test_common.py +++ b/pandas/tests/dtypes/test_common.py @@ -558,6 +558,20 @@ def _is_numeric(self) -> bool: assert com.is_numeric_dtype(MyNumericDType()) +def test_is_any_real_numeric_dtype(): + assert not com.is_any_real_numeric_dtype(str) + assert not com.is_any_real_numeric_dtype(bool) + assert not com.is_any_real_numeric_dtype(complex) + assert not com.is_any_real_numeric_dtype(object) + assert not com.is_any_real_numeric_dtype(np.datetime64) + assert not com.is_any_real_numeric_dtype(np.array(["a", "b", complex(1, 2)])) + assert not com.is_any_real_numeric_dtype(pd.DataFrame([complex(1, 2), True])) + + assert com.is_any_real_numeric_dtype(int) + assert com.is_any_real_numeric_dtype(float) + assert com.is_any_real_numeric_dtype(np.array([1, 2.5])) + + def test_is_float_dtype(): assert not com.is_float_dtype(str) assert not com.is_float_dtype(int) diff --git a/pandas/tests/indexes/multi/test_equivalence.py b/pandas/tests/indexes/multi/test_equivalence.py index 3861d74cee092..9babbd5b8d56d 100644 --- a/pandas/tests/indexes/multi/test_equivalence.py +++ b/pandas/tests/indexes/multi/test_equivalence.py @@ -1,7 +1,7 @@ import numpy as np import pytest -from pandas.core.dtypes.common import is_any_numeric_dtype +from pandas.core.dtypes.common import is_any_real_numeric_dtype import pandas as pd from pandas import ( @@ -255,7 +255,7 @@ def test_is_all_dates(idx): def test_is_numeric(idx): # MultiIndex is never numeric - assert not is_any_numeric_dtype(idx) + assert not is_any_real_numeric_dtype(idx) def test_multiindex_compare(): diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 27f501e1d7a19..783cf76403059 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -19,7 +19,7 @@ from pandas.util._test_decorators import async_mark from pandas.core.dtypes.common import ( - is_any_numeric_dtype, + is_any_real_numeric_dtype, is_numeric_dtype, is_object_dtype, ) @@ -659,7 +659,7 @@ def test_append_empty_preserve_name(self, name, expected): indirect=["index"], ) def test_is_numeric(self, index, expected): - assert is_any_numeric_dtype(index) is expected + assert is_any_real_numeric_dtype(index) is expected @pytest.mark.parametrize( "index, expected",