Repository: pandas-dev/pandas

Issue:
Generalize shift infrastructure.
Currently `Panel.shift` has its own code-path that is 4 years old. Change it to use the generic `shift` code found in `generic.py`/`internals.py`.



Discussion:
https://github.com/dalejung/pandas/compare/panel-tshift-4853...general-shift-4867

@wesm was there a specific reason that `Panel.shift` dropped periods, as opposed to `DataFrame.shift` that kept a `NaN` row?

Maybe too late to change that behavior? 

Was to avoid the huge allocate-copy step IIRC


Resolving patch:
diff --git a/pandas/core/panel.py b/pandas/core/panel.py
--- a/pandas/core/panel.py
+++ b/pandas/core/panel.py
@@ -1116,8 +1116,7 @@ def count(self, axis='major'):
 
     def shift(self, lags, freq=None, axis='major'):
         """
-        Shift major or minor axis by specified number of leads/lags. Drops
-        periods right now compared with DataFrame.shift
+        Shift major or minor axis by specified number of leads/lags. 
 
         Parameters
         ----------
@@ -1128,35 +1127,13 @@ def shift(self, lags, freq=None, axis='major'):
         -------
         shifted : Panel
         """
-        values = self.values
-        items = self.items
-        major_axis = self.major_axis
-        minor_axis = self.minor_axis
-
         if freq:
             return self.tshift(lags, freq, axis=axis)
 
-        if lags > 0:
-            vslicer = slice(None, -lags)
-            islicer = slice(lags, None)
-        elif lags == 0:
-            vslicer = islicer = slice(None)
-        else:
-            vslicer = slice(-lags, None)
-            islicer = slice(None, lags)
-
-        axis = self._get_axis_name(axis)
-        if axis == 'major_axis':
-            values = values[:, vslicer, :]
-            major_axis = major_axis[islicer]
-        elif axis == 'minor_axis':
-            values = values[:, :, vslicer]
-            minor_axis = minor_axis[islicer]
-        else:
+        if axis == 'items':
             raise ValueError('Invalid axis')
 
-        return self._constructor(values, items=items, major_axis=major_axis,
-                                 minor_axis=minor_axis)
+        return super(Panel, self).shift(lags, freq=freq, axis=axis)
 
     def tshift(self, periods=1, freq=None, axis='major', **kwds):
         return super(Panel, self).tshift(periods, freq, axis, **kwds)
diff --git a/vb_suite/panel_methods.py b/vb_suite/panel_methods.py
new file mode 100644
--- /dev/null
+++ b/vb_suite/panel_methods.py
@@ -0,0 +1,19 @@
+from vbench.api import Benchmark
+from datetime import datetime
+
+common_setup = """from pandas_vb_common import *
+"""
+
+#----------------------------------------------------------------------
+# shift
+
+setup = common_setup + """
+index = date_range(start="2000", freq="D", periods=1000)
+panel = Panel(np.random.randn(100, len(index), 1000))
+"""
+
+panel_shift = Benchmark('panel.shift(1)', setup,
+                               start_date=datetime(2012, 1, 12))
+
+panel_shift_minor = Benchmark('panel.shift(1, axis=minor)', setup,
+                               start_date=datetime(2012, 1, 12))
diff --git a/vb_suite/suite.py b/vb_suite/suite.py
--- a/vb_suite/suite.py
+++ b/vb_suite/suite.py
@@ -18,6 +18,7 @@
            'panel_ctor',
            'packers',
            'parser_vb',
+           'panel_methods',
            'plotting',
            'reindex',
            'replace',


Test patch:
diff --git a/pandas/tests/test_panel.py b/pandas/tests/test_panel.py
--- a/pandas/tests/test_panel.py
+++ b/pandas/tests/test_panel.py
@@ -1642,7 +1642,7 @@ def test_shift(self):
 
         # negative numbers, #2164
         result = self.panel.shift(-1)
-        expected = Panel(dict((i, f.shift(-1)[:-1])
+        expected = Panel(dict((i, f.shift(-1))
                               for i, f in compat.iteritems(self.panel)))
         assert_panel_equal(result, expected)