From e9cb7dd7d3d9b810c4575cbdbead8148d85e990f Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Mon, 8 Jul 2024 08:36:34 -1000 Subject: [PATCH] Support at/iat indexers in cudf.pandas (#16177) closes #16112 Authors: - Matthew Roeschke (https://github.com/mroeschke) Approvers: - Bradley Dice (https://github.com/bdice) URL: https://github.com/rapidsai/cudf/pull/16177 --- python/cudf/cudf/core/dataframe.py | 12 ++++++++++-- python/cudf/cudf/pandas/_wrappers/pandas.py | 12 ++++++++++++ .../cudf_pandas_tests/test_cudf_pandas.py | 19 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/python/cudf/cudf/core/dataframe.py b/python/cudf/cudf/core/dataframe.py index b249410c2e4..3e5ff9c18b5 100644 --- a/python/cudf/cudf/core/dataframe.py +++ b/python/cudf/cudf/core/dataframe.py @@ -462,6 +462,10 @@ def _setitem_tuple_arg(self, key, value): self._frame[col].loc[key[0]] = value[i] +class _DataFrameAtIndexer(_DataFrameLocIndexer): + pass + + class _DataFrameIlocIndexer(_DataFrameIndexer): """ For selection by index. @@ -584,6 +588,10 @@ def _setitem_tuple_arg(self, key, value): self._frame[col].iloc[key[0]] = value[i] +class _DataFrameiAtIndexer(_DataFrameIlocIndexer): + pass + + class DataFrame(IndexedFrame, Serializable, GetAttrGetItemMixin): """ A GPU Dataframe object. @@ -2581,14 +2589,14 @@ def iat(self): """ Alias for ``DataFrame.iloc``; provided for compatibility with Pandas. """ - return self.iloc + return _DataFrameiAtIndexer(self) @property def at(self): """ Alias for ``DataFrame.loc``; provided for compatibility with Pandas. """ - return self.loc + return _DataFrameAtIndexer(self) @property # type: ignore @_external_only_api( diff --git a/python/cudf/cudf/pandas/_wrappers/pandas.py b/python/cudf/cudf/pandas/_wrappers/pandas.py index a64bf7772fe..dd6f6fe76ba 100644 --- a/python/cudf/cudf/pandas/_wrappers/pandas.py +++ b/python/cudf/cudf/pandas/_wrappers/pandas.py @@ -775,6 +775,18 @@ def Index__new__(cls, *args, **kwargs): pd.core.indexing._LocIndexer, ) +_AtIndexer = make_intermediate_proxy_type( + "_AtIndexer", + cudf.core.dataframe._DataFrameAtIndexer, + pd.core.indexing._AtIndexer, +) + +_iAtIndexer = make_intermediate_proxy_type( + "_iAtIndexer", + cudf.core.dataframe._DataFrameiAtIndexer, + pd.core.indexing._iAtIndexer, +) + FixedForwardWindowIndexer = make_final_proxy_type( "FixedForwardWindowIndexer", _Unusable, diff --git a/python/cudf/cudf_pandas_tests/test_cudf_pandas.py b/python/cudf/cudf_pandas_tests/test_cudf_pandas.py index f51ce103677..b0aeaba3916 100644 --- a/python/cudf/cudf_pandas_tests/test_cudf_pandas.py +++ b/python/cudf/cudf_pandas_tests/test_cudf_pandas.py @@ -1566,3 +1566,22 @@ def test_arrow_string_arrays(): ) tm.assert_equal(cu_arr, pd_arr) + + +@pytest.mark.parametrize("indexer", ["at", "iat"]) +def test_at_iat(indexer): + df = xpd.DataFrame(range(3)) + result = getattr(df, indexer)[0, 0] + assert result == 0 + + getattr(df, indexer)[0, 0] = 1 + expected = pd.DataFrame([1, 1, 2]) + tm.assert_frame_equal(df, expected) + + +def test_at_setitem_empty(): + df = xpd.DataFrame({"name": []}, dtype="float64") + df.at[0, "name"] = 1.0 + df.at[0, "new"] = 2.0 + expected = pd.DataFrame({"name": [1.0], "new": [2.0]}) + tm.assert_frame_equal(df, expected)