Skip to content

Commit bef3300

Browse files
committed
ENH: always sort pivot table columns per #1181
1 parent 9abfb4a commit bef3300

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

pandas/tools/pivot.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# pylint: disable=E1103
22

33
from pandas import Series, DataFrame
4+
from pandas.core.index import MultiIndex
45
from pandas.core.reshape import _unstack_multiple
56
from pandas.tools.merge import concat
67
import pandas.core.common as com
@@ -103,6 +104,12 @@ def pivot_table(data, values=None, rows=None, cols=None, aggfunc='mean',
103104

104105
table = agged.unstack(to_unstack)
105106

107+
if isinstance(table, DataFrame):
108+
if isinstance(table.columns, MultiIndex):
109+
table = table.sortlevel(axis=1)
110+
else:
111+
table = table.sort_index(axis=1)
112+
106113
if fill_value is not None:
107114
table = table.fillna(value=fill_value)
108115

pandas/tools/tests/test_pivot.py

+47
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,53 @@ def test_pivot_no_level_overlap(self):
171171
expected = grouped.unstack('b').unstack('c').dropna(axis=1, how='all')
172172
tm.assert_frame_equal(table, expected)
173173

174+
def test_pivot_columns_lexsorted(self):
175+
import datetime
176+
import numpy as np
177+
import pandas
178+
179+
n = 10000
180+
181+
dtype = np.dtype([
182+
("Index", object),
183+
("Symbol", object),
184+
("Year", int),
185+
("Month", int),
186+
("Day", int),
187+
("Quantity", int),
188+
("Price", float),
189+
])
190+
191+
products = np.array([
192+
('SP500', 'ADBE'),
193+
('SP500', 'NVDA'),
194+
('SP500', 'ORCL'),
195+
('NDQ100', 'AAPL'),
196+
('NDQ100', 'MSFT'),
197+
('NDQ100', 'GOOG'),
198+
('FTSE', 'DGE.L'),
199+
('FTSE', 'TSCO.L'),
200+
('FTSE', 'GSK.L'),
201+
], dtype=[('Index', object), ('Symbol', object)])
202+
items = np.empty(n, dtype=dtype)
203+
iproduct = np.random.randint(0, len(products), n)
204+
items['Index'] = products['Index'][iproduct]
205+
items['Symbol'] = products['Symbol'][iproduct]
206+
dr = pandas.date_range(datetime.date(2000, 1, 1),
207+
datetime.date(2010, 12, 31))
208+
dates = dr[np.random.randint(0, len(dr), n)]
209+
items['Year'] = dates.year
210+
items['Month'] = dates.month
211+
items['Day'] = dates.day
212+
items['Price'] = np.random.lognormal(4.0, 2.0, n)
213+
214+
df = DataFrame(items)
215+
216+
pivoted = df.pivot_table('Price', rows=['Month', 'Day'],
217+
cols=['Index', 'Symbol', 'Year'],
218+
aggfunc='mean')
219+
220+
self.assert_(pivoted.columns.is_monotonic)
174221

175222
class TestCrosstab(unittest.TestCase):
176223

0 commit comments

Comments
 (0)