Сортировка нескольких индексов в Pandas
У меня есть мультииндексный DataFrame, созданный с помощью операции groupby. Я пытаюсь сделать сложный вид, используя несколько уровней индекса, но я не могу найти функцию сортировки, которая делает то, что мне нужно.
Первоначальный набор данных выглядит примерно так (ежедневный подсчет количества различных продуктов):
Date Manufacturer Product Name Product Launch Date Sales
0 2013-01-01 Apple iPod 2001-10-23 12
1 2013-01-01 Apple iPad 2010-04-03 13
2 2013-01-01 Samsung Galaxy 2009-04-27 14
3 2013-01-01 Samsung Galaxy Tab 2010-09-02 15
4 2013-01-02 Apple iPod 2001-10-23 22
5 2013-01-02 Apple iPad 2010-04-03 17
6 2013-01-02 Samsung Galaxy 2009-04-27 10
7 2013-01-02 Samsung Galaxy Tab 2010-09-02 7
Я использую groupby для получения суммы по диапазону дат:
> grouped = df.groupby(['Manufacturer', 'Product Name', 'Product Launch Date']).sum()
Sales
Manufacturer Product Name Product Launch Date
Apple iPad 2010-04-03 30
iPod 2001-10-23 34
Samsung Galaxy 2009-04-27 24
Galaxy Tab 2010-09-02 22
До сих пор так хорошо!
Теперь последнее, что я хочу сделать, это сортировать каждый продукт производителя по дате запуска, но держать их иерархически иерархически под Производитель - здесь все, что я пытаюсь сделать:
Sales
Manufacturer Product Name Product Launch Date
Apple iPod 2001-10-23 34
iPad 2010-04-03 30
Samsung Galaxy 2009-04-27 24
Galaxy Tab 2010-09-02 22
Когда я пытаюсь sortlevel(), я теряю приятную иерархию для каждой компании, которой я раньше:
> grouped.sortlevel('Product Launch Date')
Sales
Manufacturer Product Name Product Launch Date
Apple iPod 2001-10-23 34
Samsung Galaxy 2009-04-27 24
Apple iPad 2010-04-03 30
Samsung Galaxy Tab 2010-09-02 22
sort() и sort_index() просто сбой:
grouped.sort(['Manufacturer','Product Launch Date'])
KeyError: u'no item named Manufacturer'
grouped.sort_index(by=['Manufacturer','Product Launch Date'])
KeyError: u'no item named Manufacturer'
Кажется, что простая операция, но я не могу это понять.
Я не привязан к использованию MultiIndex для этого, но с тех пор, как groupby() возвращает то, с чем я работал.
Кстати, код для создания исходного DataFrame:
data = {
'Date': ['2013-01-01', '2013-01-01', '2013-01-01', '2013-01-01', '2013-01-02', '2013-01-02', '2013-01-02', '2013-01-02'],
'Manufacturer' : ['Apple', 'Apple', 'Samsung', 'Samsung', 'Apple', 'Apple', 'Samsung', 'Samsung',],
'Product Name' : ['iPod', 'iPad', 'Galaxy', 'Galaxy Tab', 'iPod', 'iPad', 'Galaxy', 'Galaxy Tab'],
'Product Launch Date' : ['2001-10-23', '2010-04-03', '2009-04-27', '2010-09-02','2001-10-23', '2010-04-03', '2009-04-27', '2010-09-02'],
'Sales' : [12, 13, 14, 15, 22, 17, 10, 7]
}
df = DataFrame(data, columns=['Date', 'Manufacturer', 'Product Name', 'Product Launch Date', 'Sales'])
Ответы
Ответ 1
Взломом будет изменение порядка уровней:
In [11]: g
Out[11]:
Sales
Manufacturer Product Name Product Launch Date
Apple iPad 2010-04-03 30
iPod 2001-10-23 34
Samsung Galaxy 2009-04-27 24
Galaxy Tab 2010-09-02 22
In [12]: g.index = g.index.swaplevel(1, 2)
Sortlevel, который (как вы нашли) сортирует уровни MultiIndex в порядке:
In [13]: g = g.sortlevel()
И поменяйте обратно:
In [14]: g.index = g.index.swaplevel(1, 2)
In [15]: g
Out[15]:
Sales
Manufacturer Product Name Product Launch Date
Apple iPod 2001-10-23 34
iPad 2010-04-03 30
Samsung Galaxy 2009-04-27 24
Galaxy Tab 2010-09-02 22
Я считаю, что sortlevel не должен сортировать оставшиеся метки по порядку, поэтому создаст проблему github.:) Хотя стоит упомянуть docnote о "необходимость сортировки" .
Примечание: вы можете избежать первого swaplevel
путем изменения порядка начальной группы:
g = df.groupby(['Manufacturer', 'Product Launch Date', 'Product Name']).sum()
Ответ 2
Этот лайнер работает для меня:
In [1]: grouped.sortlevel(["Manufacturer","Product Launch Date"], sort_remaining=False)
Sales
Manufacturer Product Name Product Launch Date
Apple iPod 2001-10-23 34
iPad 2010-04-03 30
Samsung Galaxy 2009-04-27 24
Galaxy Tab 2010-09-02 22
Обратите внимание, это тоже работает:
groups.sortlevel([0,2], sort_remaining=False)
Это не сработало бы, когда вы первоначально разместили более двух лет назад, потому что уровень сортировки по умолчанию сортируется по ВСЕМ индексам, которые портят иерархию вашей компании. sort_remaining, который отключает это поведение, был добавлен в прошлом году. Вот ссылка для фиксации для ссылки: https://github.com/pydata/pandas/commit/3ad64b11e8e4bef47e3767f1d31cc26e39593277
Ответ 3
Если вы хотите избежать множественных свопов в очень глубоком MultiIndex, вы также можете попробовать:
- Нарезка по уровню X (по понятию списка +.loc + IndexSlice)
- Сортировка желаемого уровня (sortlevel (2))
- Конкатенация каждой группы индексов уровня X
Здесь у вас есть код:
import pandas as pd
idx = pd.IndexSlice
g = pd.concat([grouped.loc[idx[i,:,:],:].sortlevel(2) for i in grouped.index.levels[0]])
g
Ответ 4
Если вы не обеспокоены сохранением индекса (я часто предпочитаю произвольный целочисленный индекс), вы можете просто использовать следующий однострочный:
grouped.reset_index().sort(["Manufacturer","Product Launch Date"])
Ответ 5
Чтобы отсортировать MultiIndex по "столбцам индекса" (иначе .sort_index()
уровням), вам нужно использовать метод .sort_index()
и установить его аргумент level
. Если вы хотите сортировать по нескольким уровням, аргумент должен быть установлен в список имен уровней в последовательном порядке.
Это должно дать вам DataFrame вам нужно:
df.groupby(['Manufacturer', 'Product Name', 'Launch Date']).sum().sort_index(level=['Manufacturer','Launch Date'])