Repository: modin-project/modin

Issue:
slice_shift function implementation



Discussion:

Resolving patch:
diff --git a/modin/pandas/base.py b/modin/pandas/base.py
--- a/modin/pandas/base.py
+++ b/modin/pandas/base.py
@@ -2675,9 +2675,6 @@ def skew(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs):
             )
         )
 
-    def slice_shift(self, periods=1, axis=0):
-        return self._default_to_pandas("slice_shift", periods=periods, axis=axis)
-
     def sort_index(
         self,
         axis=0,
diff --git a/modin/pandas/dataframe.py b/modin/pandas/dataframe.py
--- a/modin/pandas/dataframe.py
+++ b/modin/pandas/dataframe.py
@@ -1526,6 +1526,51 @@ def nsmallest(self, n, columns, keep="first"):
             )
         )
 
+    def slice_shift(self, periods=1, axis=0):
+        """
+        Equivalent to `shift` without copying data.
+        The shifted data will not include the dropped periods and the
+        shifted axis will be smaller than the original.
+        Parameters
+        ----------
+        periods : int
+            Number of periods to move, can be positive or negative.
+        axis : int or str
+            Shift direction.
+        Returns
+        -------
+        shifted : same type as caller
+        """
+        if periods == 0:
+            return self.copy()
+
+        if axis == "index" or axis == 0:
+            if abs(periods) >= len(self.index):
+                return DataFrame(columns=self.columns)
+            else:
+                if periods > 0:
+                    new_index = self.index.drop(labels=self.index[:periods])
+                    new_df = self.drop(self.index[-periods:])
+                else:
+                    new_index = self.index.drop(labels=self.index[periods:])
+                    new_df = self.drop(self.index[:-periods])
+
+                new_df.index = new_index
+                return new_df
+        else:
+            if abs(periods) >= len(self.columns):
+                return DataFrame(index=self.index)
+            else:
+                if periods > 0:
+                    new_columns = self.columns.drop(labels=self.columns[:periods])
+                    new_df = self.drop(self.columns[-periods:], axis="columns")
+                else:
+                    new_columns = self.columns.drop(labels=self.columns[periods:])
+                    new_df = self.drop(self.columns[:-periods], axis="columns")
+
+                new_df.columns = new_columns
+                return new_df
+
     def pivot(self, index=None, columns=None, values=None):
         return self._default_to_pandas(
             pandas.DataFrame.pivot, index=index, columns=columns, values=values
diff --git a/modin/pandas/series.py b/modin/pandas/series.py
--- a/modin/pandas/series.py
+++ b/modin/pandas/series.py
@@ -932,6 +932,44 @@ def nsmallest(self, n=5, keep="first"):
         """
         return Series(query_compiler=self._query_compiler.nsmallest(n=n, keep=keep))
 
+    def slice_shift(self, periods=1, axis=0):
+        """
+        Equivalent to `shift` without copying data.
+        The shifted data will not include the dropped periods and the
+        shifted axis will be smaller than the original.
+        Parameters
+        ----------
+        periods : int
+            Number of periods to move, can be positive or negative.
+        axis : int or str
+            Shift direction.
+        Returns
+        -------
+        shifted : same type as caller
+        """
+        if periods == 0:
+            return self.copy()
+
+        if axis == "index" or axis == 0:
+            if abs(periods) >= len(self.index):
+                return Series(dtype=self.dtype)
+            else:
+                if periods > 0:
+                    new_index = self.index.drop(labels=self.index[:periods])
+                    new_df = self.drop(self.index[-periods:])
+                else:
+                    new_index = self.index.drop(labels=self.index[periods:])
+                    new_df = self.drop(self.index[:-periods])
+
+                new_df.index = new_index
+                return new_df
+        else:
+            raise ValueError(
+                "No axis named {axis} for object type {type}".format(
+                    axis=axis, type=type(self)
+                )
+            )
+
     @property
     def plot(
         self,


Test patch:
diff --git a/modin/pandas/test/test_dataframe.py b/modin/pandas/test/test_dataframe.py
--- a/modin/pandas/test/test_dataframe.py
+++ b/modin/pandas/test/test_dataframe.py
@@ -2455,10 +2455,24 @@ def test_shift(self, data, index, axis, periods):
             pandas_df.shift(periods=periods, axis=axis, fill_value=777),
         )
 
-    def test_slice_shift(self):
-        data = test_data_values[0]
-        with pytest.warns(UserWarning):
-            pd.DataFrame(data).slice_shift()
+    @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
+    @pytest.mark.parametrize("index", ["default", "ndarray"])
+    @pytest.mark.parametrize("axis", [0, 1])
+    @pytest.mark.parametrize("periods", [0, 1, -1, 10, -10, 1000000000, -1000000000])
+    def test_slice_shift(self, data, index, axis, periods):
+        if index == "default":
+            modin_df = pd.DataFrame(data)
+            pandas_df = pandas.DataFrame(data)
+        elif index == "ndarray":
+            data_column_length = len(data[next(iter(data))])
+            index_data = np.arange(2, data_column_length + 2)
+            modin_df = pd.DataFrame(data, index=index_data)
+            pandas_df = pandas.DataFrame(data, index=index_data)
+
+        df_equals(
+            modin_df.slice_shift(periods=periods, axis=axis),
+            pandas_df.slice_shift(periods=periods, axis=axis),
+        )
 
     def test_stack(self):
         data = test_data_values[0]
diff --git a/modin/pandas/test/test_series.py b/modin/pandas/test/test_series.py
--- a/modin/pandas/test/test_series.py
+++ b/modin/pandas/test/test_series.py
@@ -2470,10 +2470,22 @@ def test_skew(data, skipna):
 
 
 @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
-def test_slice_shift(data):
-    modin_series, _ = create_test_series(data)  # noqa: F841
-    with pytest.warns(UserWarning):
-        modin_series.slice_shift()
+@pytest.mark.parametrize("index", ["default", "ndarray"])
+@pytest.mark.parametrize("periods", [0, 1, -1, 10, -10, 1000000000, -1000000000])
+def test_slice_shift(data, index, periods):
+    if index == "default":
+        modin_series, pandas_series = create_test_series(data)
+    elif index == "ndarray":
+        modin_series, pandas_series = create_test_series(data)
+        data_column_length = len(data[next(iter(data))])
+        index_data = np.arange(2, data_column_length + 2)
+        modin_series.index = index_data
+        pandas_series.index = index_data
+
+    df_equals(
+        modin_series.slice_shift(periods=periods),
+        pandas_series.slice_shift(periods=periods),
+    )
 
 
 @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)