From 078615847c6e402db67aab31c95ef1742341066e Mon Sep 17 00:00:00 2001 From: Skipper Seabold Date: Thu, 30 Jul 2015 11:05:14 -0500 Subject: [PATCH] ENH: Make index optional in pivot. Closes #3962 TST: Test for index is None in pivot DOC: Add release note DOC: Formatting DOC: Document index=None --- doc/source/whatsnew/v0.17.0.txt | 2 ++ pandas/core/frame.py | 5 ++-- pandas/core/reshape.py | 10 ++++++-- pandas/tests/test_frame.py | 41 +++++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v0.17.0.txt b/doc/source/whatsnew/v0.17.0.txt index c97f143cb63c2..4cf4c51f75fbb 100644 --- a/doc/source/whatsnew/v0.17.0.txt +++ b/doc/source/whatsnew/v0.17.0.txt @@ -110,6 +110,8 @@ Other enhancements - ``pd.merge`` will now allow duplicate column names if they are not merged upon (:issue:`10639`). +- ``pd.pivot`` will now allow passing index as ``None`` (:issue:`3962`). + .. _whatsnew_0170.api: .. _whatsnew_0170.api_breaking: diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 872e8efb0d4e9..3770fc01462e8 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -3460,8 +3460,9 @@ def pivot(self, index=None, columns=None, values=None): Parameters ---------- - index : string or object - Column name to use to make new frame's index + index : string or object, optional + Column name to use to make new frame's index. If None, uses + existing index. columns : string or object Column name to use to make new frame's columns values : string or object, optional diff --git a/pandas/core/reshape.py b/pandas/core/reshape.py index 99767ab199843..f782aa38bc965 100644 --- a/pandas/core/reshape.py +++ b/pandas/core/reshape.py @@ -319,11 +319,17 @@ def pivot(self, index=None, columns=None, values=None): See DataFrame.pivot """ if values is None: - indexed = self.set_index([index, columns]) + cols = [columns] if index is None else [index, columns] + append = index is None + indexed = self.set_index(cols, append=append) return indexed.unstack(columns) else: + if index is None: + index = self.index + else: + index = self[index] indexed = Series(self[values].values, - index=MultiIndex.from_arrays([self[index], + index=MultiIndex.from_arrays([index, self[columns]])) return indexed.unstack(columns) diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 9ab004eb31a99..b7175cb45687c 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -9478,6 +9478,47 @@ def test_pivot_integer_bug(self): repr(result) self.assert_numpy_array_equal(result.columns, ['A', 'B']) + def test_pivot_index_none(self): + # gh-3962 + data = { + 'index': ['A', 'B', 'C', 'C', 'B', 'A'], + 'columns': ['One', 'One', 'One', 'Two', 'Two', 'Two'], + 'values': [1., 2., 3., 3., 2., 1.] + } + + frame = DataFrame(data).set_index('index') + result = frame.pivot(columns='columns', values='values') + expected = DataFrame({ + 'One': {'A': 1., 'B': 2., 'C': 3.}, + 'Two': {'A': 1., 'B': 2., 'C': 3.} + }) + + expected.index.name, expected.columns.name = 'index', 'columns' + assert_frame_equal(result, expected) + + # omit values + result = frame.pivot(columns='columns') + + expected.columns = pd.MultiIndex.from_tuples([('values', 'One'), + ('values', 'Two')], + names=[None, 'columns']) + expected.index.name = 'index' + assert_frame_equal(result, expected, check_names=False) + self.assertEqual(result.index.name, 'index',) + self.assertEqual(result.columns.names, (None, 'columns')) + expected.columns = expected.columns.droplevel(0) + + data = { + 'index': range(7), + 'columns': ['One', 'One', 'One', 'Two', 'Two', 'Two'], + 'values': [1., 2., 3., 3., 2., 1.] + } + + result = frame.pivot(columns='columns', values='values') + + expected.columns.name = 'columns' + assert_frame_equal(result, expected) + def test_reindex(self): newFrame = self.frame.reindex(self.ts1.index)