From 970e25beb585936ef68fac90cb46837bf2ed0b00 Mon Sep 17 00:00:00 2001 From: Jeffrey Gerard Date: Tue, 21 Jun 2016 22:49:42 +0200 Subject: [PATCH 1/5] DataFrame sort columns by rows: sort_values(axis=1) Fixes #10806 --- pandas/core/frame.py | 7 +++---- pandas/tests/frame/test_sorting.py | 24 ++++++++++++++++++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index b4509c999a5da..92440731c77e2 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -3127,9 +3127,8 @@ def sort_values(self, by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last'): axis = self._get_axis_number(axis) + other_axis = 0 if axis == 1 else 1 - if axis != 0: - raise ValueError('When sorting by column, axis must be 0 (rows)') if not isinstance(by, list): by = [by] if com.is_sequence(ascending) and len(by) != len(ascending): @@ -3145,7 +3144,7 @@ def trans(v): keys = [] for x in by: - k = self[x].values + k = self.xs(x, axis=other_axis).values if k.ndim == 2: raise ValueError('Cannot sort by duplicate column %s' % str(x)) @@ -3157,7 +3156,7 @@ def trans(v): from pandas.core.groupby import _nargsort by = by[0] - k = self[by].values + k = self.xs(by, axis=other_axis).values if k.ndim == 2: # try to be helpful diff --git a/pandas/tests/frame/test_sorting.py b/pandas/tests/frame/test_sorting.py index 4d57216c8f870..258d8c8645934 100644 --- a/pandas/tests/frame/test_sorting.py +++ b/pandas/tests/frame/test_sorting.py @@ -84,7 +84,7 @@ def test_sort_values(self): frame = DataFrame([[1, 1, 2], [3, 1, 0], [4, 5, 6]], index=[1, 2, 3], columns=list('ABC')) - # by column + # by column (axis=0) sorted_df = frame.sort_values(by='A') indexer = frame['A'].argsort().values expected = frame.ix[frame.index[indexer]] @@ -116,9 +116,25 @@ def test_sort_values(self): self.assertRaises(ValueError, lambda: frame.sort_values( by=['A', 'B'], axis=2, inplace=True)) - msg = 'When sorting by column, axis must be 0' - with assertRaisesRegexp(ValueError, msg): - frame.sort_values(by='A', axis=1) + # by row (axis=1): GH 10806 + sorted_df = frame.sort_values(by=3, axis=1) + expected = frame + assert_frame_equal(sorted_df, expected) + + sorted_df = frame.sort_values(by=3, axis=1, ascending=False) + expected = frame.reindex(columns=['C', 'B', 'A']) + assert_frame_equal(sorted_df, expected) + + sorted_df = frame.sort_values(by=[1, 2], axis=1) + expected = frame.reindex(columns=['B', 'A', 'C']) + assert_frame_equal(sorted_df, expected) + + sorted_df = frame.sort_values(by=[1, 3], axis=1, ascending=[True, False]) + assert_frame_equal(sorted_df, expected) + + sorted_df = frame.sort_values(by=[1, 3], axis=1, ascending=False) + expected = frame.reindex(columns=['C', 'B', 'A']) + assert_frame_equal(sorted_df, expected) msg = r'Length of ascending \(5\) != length of by \(2\)' with assertRaisesRegexp(ValueError, msg): From 0f2361554d0a7c95514957066d01e0d443faaf18 Mon Sep 17 00:00:00 2001 From: Jeffrey Gerard Date: Mon, 11 Jul 2016 21:25:39 +0200 Subject: [PATCH 2/5] Whatsnew entry for DataFrame.sort_values by index (10806) --- doc/source/whatsnew/v0.19.0.txt | 1 + pandas/tests/frame/test_sorting.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.19.0.txt b/doc/source/whatsnew/v0.19.0.txt index 4cc16aac15f8b..c6b51811561c7 100644 --- a/doc/source/whatsnew/v0.19.0.txt +++ b/doc/source/whatsnew/v0.19.0.txt @@ -229,6 +229,7 @@ Other enhancements - ``pd.read_html()`` has gained support for the ``decimal`` option (:issue:`12907`) - A top-level function :func:`union_categorical` has been added for combining categoricals, see :ref:`Unioning Categoricals` (:issue:`13361`) - ``Series`` has gained the properties ``.is_monotonic``, ``.is_monotonic_increasing``, ``.is_monotonic_decreasing``, similar to ``Index`` (:issue:`13336`) +- ``DataFrame.sort_values()`` has gained support for re-ordering columns by index label (:issue:`10806`) .. _whatsnew_0190.api: diff --git a/pandas/tests/frame/test_sorting.py b/pandas/tests/frame/test_sorting.py index 258d8c8645934..efcdae3c6ddea 100644 --- a/pandas/tests/frame/test_sorting.py +++ b/pandas/tests/frame/test_sorting.py @@ -129,7 +129,8 @@ def test_sort_values(self): expected = frame.reindex(columns=['B', 'A', 'C']) assert_frame_equal(sorted_df, expected) - sorted_df = frame.sort_values(by=[1, 3], axis=1, ascending=[True, False]) + sorted_df = frame.sort_values(by=[1, 3], axis=1, + ascending=[True, False]) assert_frame_equal(sorted_df, expected) sorted_df = frame.sort_values(by=[1, 3], axis=1, ascending=False) From 2773cdf1786956119adaecedb69e5a60a4143eed Mon Sep 17 00:00:00 2001 From: Jeffrey Gerard Date: Tue, 12 Jul 2016 19:15:12 +0200 Subject: [PATCH 3/5] Tweak whatsnew entry --- doc/source/whatsnew/v0.19.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.19.0.txt b/doc/source/whatsnew/v0.19.0.txt index c6b51811561c7..3c74414330f78 100644 --- a/doc/source/whatsnew/v0.19.0.txt +++ b/doc/source/whatsnew/v0.19.0.txt @@ -229,7 +229,7 @@ Other enhancements - ``pd.read_html()`` has gained support for the ``decimal`` option (:issue:`12907`) - A top-level function :func:`union_categorical` has been added for combining categoricals, see :ref:`Unioning Categoricals` (:issue:`13361`) - ``Series`` has gained the properties ``.is_monotonic``, ``.is_monotonic_increasing``, ``.is_monotonic_decreasing``, similar to ``Index`` (:issue:`13336`) -- ``DataFrame.sort_values()`` has gained support for re-ordering columns by index label (:issue:`10806`) +- ``DataFrame.sort_values()`` has gained `axis=1` support to re-order columns `by=index_label` (:issue:`10806`) .. _whatsnew_0190.api: From f43ab2e74d1c98754260c6a5b1c3e2e4b02d707c Mon Sep 17 00:00:00 2001 From: Jeffrey Gerard Date: Tue, 12 Jul 2016 20:12:58 +0200 Subject: [PATCH 4/5] Tweak whatsnew entry, once more --- doc/source/whatsnew/v0.19.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.19.0.txt b/doc/source/whatsnew/v0.19.0.txt index 3c74414330f78..86b37bfbf44b1 100644 --- a/doc/source/whatsnew/v0.19.0.txt +++ b/doc/source/whatsnew/v0.19.0.txt @@ -229,7 +229,7 @@ Other enhancements - ``pd.read_html()`` has gained support for the ``decimal`` option (:issue:`12907`) - A top-level function :func:`union_categorical` has been added for combining categoricals, see :ref:`Unioning Categoricals` (:issue:`13361`) - ``Series`` has gained the properties ``.is_monotonic``, ``.is_monotonic_increasing``, ``.is_monotonic_decreasing``, similar to ``Index`` (:issue:`13336`) -- ``DataFrame.sort_values()`` has gained `axis=1` support to re-order columns `by=index_label` (:issue:`10806`) +- ``DataFrame.sort_values()`` has gained `axis=1` support to re-order columns with `by=index_label` (:issue:`10806`) .. _whatsnew_0190.api: From ea2d89eb82a915d522d783c35e1759b826821713 Mon Sep 17 00:00:00 2001 From: Jeffrey Gerard Date: Sun, 17 Jul 2016 16:43:55 +0200 Subject: [PATCH 5/5] More test cases. Clarify whatnew w/ example. --- doc/source/whatsnew/v0.19.0.txt | 8 +++++++- pandas/tests/frame/test_sorting.py | 11 ++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.19.0.txt b/doc/source/whatsnew/v0.19.0.txt index 86b37bfbf44b1..7d3889505e098 100644 --- a/doc/source/whatsnew/v0.19.0.txt +++ b/doc/source/whatsnew/v0.19.0.txt @@ -229,7 +229,13 @@ Other enhancements - ``pd.read_html()`` has gained support for the ``decimal`` option (:issue:`12907`) - A top-level function :func:`union_categorical` has been added for combining categoricals, see :ref:`Unioning Categoricals` (:issue:`13361`) - ``Series`` has gained the properties ``.is_monotonic``, ``.is_monotonic_increasing``, ``.is_monotonic_decreasing``, similar to ``Index`` (:issue:`13336`) -- ``DataFrame.sort_values()`` has gained `axis=1` support to re-order columns with `by=index_label` (:issue:`10806`) +- ``DataFrame`` has gained support to re-order the columns based on the values in a row using ``df.sort_values(by='index_label', axis=1)`` (:issue:`10806`) + + .. ipython:: python + + df = pd.DataFrame({'A': [2, 7], 'B': [3, 5], 'C': [4, 8]}, + index=['row1', 'row2']) + df.sort_values(by='row2', axis=1) .. _whatsnew_0190.api: diff --git a/pandas/tests/frame/test_sorting.py b/pandas/tests/frame/test_sorting.py index efcdae3c6ddea..b7a38e9e13ebd 100644 --- a/pandas/tests/frame/test_sorting.py +++ b/pandas/tests/frame/test_sorting.py @@ -125,7 +125,7 @@ def test_sort_values(self): expected = frame.reindex(columns=['C', 'B', 'A']) assert_frame_equal(sorted_df, expected) - sorted_df = frame.sort_values(by=[1, 2], axis=1) + sorted_df = frame.sort_values(by=[1, 2], axis='columns') expected = frame.reindex(columns=['B', 'A', 'C']) assert_frame_equal(sorted_df, expected) @@ -150,6 +150,11 @@ def test_sort_values_inplace(self): expected = frame.sort_values(by='A') assert_frame_equal(sorted_df, expected) + sorted_df = frame.copy() + sorted_df.sort_values(by=1, axis=1, inplace=True) + expected = frame.sort_values(by=1, axis=1) + assert_frame_equal(sorted_df, expected) + sorted_df = frame.copy() sorted_df.sort_values(by='A', ascending=False, inplace=True) expected = frame.sort_values(by='A', ascending=False) @@ -196,6 +201,10 @@ def test_sort_nan(self): sorted_df = df.sort_values(['A'], na_position='first', ascending=False) assert_frame_equal(sorted_df, expected) + expected = df.reindex(columns=['B', 'A']) + sorted_df = df.sort_values(by=1, axis=1, na_position='first') + assert_frame_equal(sorted_df, expected) + # na_position='last', order expected = DataFrame( {'A': [1, 1, 2, 4, 6, 8, nan],