diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 2aac2596c18cb..f6262e2759ff6 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -104,7 +104,7 @@ Other enhancements - Added :meth:`~DataFrame.set_flags` for setting table-wide flags on a ``Series`` or ``DataFrame`` (:issue:`28394`) - :class:`Index` with object dtype supports division and multiplication (:issue:`34160`) - :meth:`DataFrame.explode` and :meth:`Series.explode` now support exploding of sets (:issue:`35614`) -- +- Added :meth:`~DataFrame.peek` and :meth:`~Series.peek` to simultaneously check head and tail rows (:issue:`18691`) .. _whatsnew_120.api_breaking.python: diff --git a/pandas/core/generic.py b/pandas/core/generic.py index fffd2e068ebcf..329badf59c339 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -4994,6 +4994,95 @@ def tail(self: FrameOrSeries, n: int = 5) -> FrameOrSeries: return self.iloc[0:0] return self.iloc[-n:] + def peek(self: FrameOrSeries, n: int = 5) -> FrameOrSeries: + """ + Return the first `n` rows and the last `n` rows. + + This function returns the first `n` rows and the last `n` rows from the + object based on position. It is useful for quickly verifying data, for + example, after sorting or appending rows. + + For negative values of `n`, this function returns all rows except + the first `n` rows and last `n` rows, equivalent to ``df[n:-n]``. + + Parameters + ---------- + n : int, default 5 + Number of rows to select from head and tail. + + Returns + ------- + type of caller + The first `n` rows and last `n` rows of the caller object. + + See Also + -------- + DataFrame.head : The first `n` rows of the caller object. + DataFrame.tail : The last `n` rows of the caller object. + + Examples + -------- + >>> df = pd.DataFrame({'animal': ['alligator', 'bee', 'falcon', 'lion', + ... 'monkey', 'parrot', 'shark', 'whale', 'zebra']}) + >>> df + animal + 0 alligator + 1 bee + 2 falcon + 3 lion + 4 monkey + 5 parrot + 6 shark + 7 whale + 8 zebra + + Peeking at the first 5 and last 5 rows + + >>> df.peek() + animal + 0 alligator + 1 bee + 2 falcon + 3 lion + 4 monkey + 5 parrot + 6 shark + 7 whale + 8 zebra + + Viewing the first and last `n` lines (three in this case) + + >>> df.peek(3) + animal + 0 alligator + 1 bee + 2 falcon + 6 shark + 7 whale + 8 zebra + + For negative values of `n` + + >>> df.peek(-3) + animal + 3 lion + 4 monkey + 5 parrot + """ + if n == 0: + return self.iloc[0:0] + + # To avoid duplication of rows, we check if the head and tail combined + # would be greater than the size of the dataframe + elif n > self.shape[0] / 2: + return self + + # When abs(n) > self.shape[0]/2, this returns nothing + elif n < 0: + return self.iloc[abs(n):n] + + return pd.concat([self.iloc[:n], self.iloc[-n:]], axis=0) + def sample( self: FrameOrSeries, n=None, diff --git a/pandas/tests/generic/test_generic.py b/pandas/tests/generic/test_generic.py index 2c2584e8dee01..ebbaf75e6ceda 100644 --- a/pandas/tests/generic/test_generic.py +++ b/pandas/tests/generic/test_generic.py @@ -251,7 +251,7 @@ def test_metadata_propagation(self): self.check_metadata(v1 & v2) self.check_metadata(v1 | v2) - def test_head_tail(self, index): + def test_head_tail_peek(self, index): # GH5370 o = self._construct(shape=len(index)) @@ -263,18 +263,25 @@ def test_head_tail(self, index): self._compare(o.head(), o.iloc[:5]) self._compare(o.tail(), o.iloc[-5:]) + if o.shape[0] >= 10: + self._compare(o.peek(), pd.concat([o.iloc[:5], o.iloc[-5:]], axis=0)) + else: + self._compare(o.peek(), o) # 0-len self._compare(o.head(0), o.iloc[0:0]) self._compare(o.tail(0), o.iloc[0:0]) + self._compare(o.peek(0), o.iloc[0:0]) # bounded self._compare(o.head(len(o) + 1), o) self._compare(o.tail(len(o) + 1), o) + self._compare(o.peek(len(o) // 2 + 1), o) # neg index self._compare(o.head(-3), o.head(len(index) - 3)) self._compare(o.tail(-3), o.tail(len(index) - 3)) + self._compare(o.peek(-3), o.iloc[3:-3]) def test_sample(self): # Fixes issue: 2419