diff --git a/doc/source/release.rst b/doc/source/release.rst index 77d86b8a7a9f1..0a901d1ff044c 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -756,6 +756,7 @@ Bug Fixes - Test suite no longer leaves around temporary files when testing graphics. (:issue:`5347`) (thanks for catching this @yarikoptic!) - Fixed html tests on win32. (:issue:`4580`) + - Make sure that ``head/tail`` are ``iloc`` based, (:issue:`5370`) pandas 0.12.0 diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 2361c6920985b..0a5306de9bbb5 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -3085,16 +3085,6 @@ def last_valid_index(self): """ return self.index[self.count(1) > 0][-1] - def head(self, n=5): - """Returns first n rows of DataFrame - """ - return self[:n] - - def tail(self, n=5): - """Returns last n rows of DataFrame - """ - return self[-n:] - #---------------------------------------------------------------------- # Data reshaping diff --git a/pandas/core/generic.py b/pandas/core/generic.py index b230df7483760..b5e526e42a547 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1461,6 +1461,24 @@ def filter(self, items=None, like=None, regex=None, axis=None): else: raise TypeError('Must pass either `items`, `like`, or `regex`') + def head(self, n=5): + """ + Returns first n rows + """ + l = len(self) + if abs(n) > l: + n = l if n > 0 else -l + return self.iloc[:n] + + def tail(self, n=5): + """ + Returns last n rows + """ + l = len(self) + if abs(n) > l: + n = l if n > 0 else -l + return self.iloc[-n:] + #---------------------------------------------------------------------- # Attribute access diff --git a/pandas/core/panel.py b/pandas/core/panel.py index d4ba7dd4e708a..6b50bfb76a3ea 100644 --- a/pandas/core/panel.py +++ b/pandas/core/panel.py @@ -581,6 +581,12 @@ def conform(self, frame, axis='items'): axes = self._get_plane_axes(axis) return frame.reindex(**self._extract_axes_for_slice(self, axes)) + def head(self, n=5): + raise NotImplementedError + + def tail(self, n=5): + raise NotImplementedError + def _needs_reindex_multi(self, axes, method, level): # only allowing multi-index on Panel (and not > dims) return method is None and not self._is_mixed_type and self._AXIS_LEN <= 3 and com._count_not_none(*axes.values()) == 3 diff --git a/pandas/core/series.py b/pandas/core/series.py index 699dc9b31464e..d3cc53d0bc9fc 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1058,16 +1058,6 @@ def to_sparse(self, kind='block', fill_value=None): return SparseSeries(self, kind=kind, fill_value=fill_value).__finalize__(self) - def head(self, n=5): - """Returns first n rows of Series - """ - return self[:n] - - def tail(self, n=5): - """Returns last n rows of Series - """ - return self[-n:] - #---------------------------------------------------------------------- # Statistics, overridden ndarray methods diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 12b960ad376ff..b73c7cdbb8f87 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -4261,6 +4261,12 @@ def test_head_tail(self): assert_frame_equal(self.frame.head(), self.frame[:5]) assert_frame_equal(self.frame.tail(), self.frame[-5:]) + # with a float index + df = self.frame.copy() + df.index = np.arange(len(self.frame)) + 0.1 + assert_frame_equal(df.head(), df.iloc[:5]) + assert_frame_equal(df.tail(), df.iloc[-5:]) + def test_insert(self): df = DataFrame(np.random.randn(5, 3), index=np.arange(5), columns=['c', 'b', 'a']) diff --git a/pandas/tests/test_generic.py b/pandas/tests/test_generic.py index fdeb61f09cadb..cf9b2d174faea 100644 --- a/pandas/tests/test_generic.py +++ b/pandas/tests/test_generic.py @@ -317,6 +317,39 @@ def test_metadata_propagation(self): except (ValueError): pass + def test_head_tail(self): + # GH5370 + + o = self._construct(shape=10) + + # check all index types + for index in [ tm.makeFloatIndex, tm.makeIntIndex, + tm.makeStringIndex, tm.makeUnicodeIndex, + tm.makeDateIndex, tm.makePeriodIndex ]: + axis = o._get_axis_name(0) + setattr(o,axis,index(len(getattr(o,axis)))) + + # Panel + dims + try: + o.head() + except (NotImplementedError): + raise nose.SkipTest('not implemented on {0}'.format(o.__class__.__name__)) + + self._compare(o.head(), o.iloc[:5]) + self._compare(o.tail(), o.iloc[-5:]) + + # 0-len + self._compare(o.head(0), o.iloc[:0]) + self._compare(o.tail(0), o.iloc[0:]) + + # bounded + self._compare(o.head(len(o)+1), o) + self._compare(o.tail(len(o)+1), o) + + # neg index + self._compare(o.head(-3), o.head(7)) + self._compare(o.tail(-3), o.tail(7)) + class TestSeries(unittest.TestCase, Generic): _typ = Series _comparator = lambda self, x, y: assert_series_equal(x,y)