Как отсортировать уровень MultiIndex по количеству строк на дочернем уровне - PullRequest
2 голосов
/ 24 мая 2019

У меня есть исторические данные о количестве и сумме (сколько было списано в транзакции) для товаров, проданных компанией множеству различных клиентов. Я собираюсь провести анализ временных рядов по этим данным, но хочу сделать это на уровне покупателя.

Вот мои необработанные данные:

      Year         Month   Day      Qty           Amount     Item   Customer
0     2003         9       1         30.0         220.80     N2719  3110361
1     2003         9       1          1.0          75.17     X1046  3126034
2     2003         9       1        240.0         379.20     D5853  0008933
3     2003         9       1       2112.0        2787.84     D5851  0008933
4     2003         9       1       3312.0        4371.84     D5851  0008933
...
...
<2.7M rows>

Это данные транзакций, отсортированные по году / месяцу / дню и фиксирующие, какой товар был продан какому клиенту, а также количество и сумму в этой продаже.

Поскольку я хочу проанализировать временные ряды по номеру товара и клиенту, я применяю к нему мультииндекс:

df.set_index(['Item', 'Customer', 'Year', 'Month', 'Day'], inplace=True, drop=True)
df.sortlevel(inplace=True)

Это дает мне хорошо отсортированный фрейм данных, который выглядит следующим образом:

Item      Customer     Year   Month   Day   Qty      Amount
X1046     3126034      2003   9       1     1.0      75.17
                       < ...  other transactions for X1046/3126034 item/customer combination ...>
          3126035      2005   1       2     50.0     500.00
                        < ...  other transactions for X1046/3126035 item/customer combination ...>
      < ... 48 other customers for X1046 ...>

N2719     3110361      2003    9      1     30.0      220.80   
                       < ...  other transactions for N2719/3110361 item/customer combination ...>
          3110362      2004    9      10     9.0     823.00
                       < ...  other transactions for N2719/3110362 item/customer combination ...>
      < ... 198 other customers for N2719 ... >
< ... 6998 other items ... >

Как видите, поскольку у меня 7000 различных товаров, и у каждого может быть несколько десятков или сотен покупателей, я бы хотел сосредоточиться только на тех товарах, которые имеют значительную клиентскую базу. В наборе данных содержится много элементов, которые, возможно, когда-то были куплены одним клиентом в прошлом, и, возможно, были сняты с производства и т. Д.

Для сортировки товаров по количеству клиентов используйте следующее:

item_by_customers = df.reset_index().groupby('Item')['Customer'].nunique().sort_values(ascending=False)

Что дает мне предметы, отсортированные по количеству покупателей в виде панд. Серия:

Item
N2719    200
X1046     50
<... 6998 other rows ...>

Теперь я хочу применить этот порядок сортировки к моему DataFrame, чтобы сначала отображались данные для элемента N2719 (сохраняя все уровни MultiIndex внутри него), затем X1046 и так далее.

Я не могу понять, как это сделать.

Вот что я пробовал до сих пор:

sorted_data = df.set_index(item_by_customers.index)
< ... gives me ValueError: Length mismatch: Expected axis has 2.7M elements, new values have 7000 elements ...>

Я понимаю, почему я получаю эту ошибку, потому что у меня есть 7000 элементов в индексе и 2,7 миллиона строк в DataFrame.

Я также попробовал переиндексацию:

sorted_data = df.reindex(index=item_by_customers.index, columns=['Item'])
< ... gives me Exception: cannot handle a non-unique multi-index! ...>

Существует также sort_index(), который по существу сортирует столбец индекса по его собственным значениям, а не по некоторым другим критериям.

Я ищу руководство по применению item_by_customers.index к DataFrame, поэтому я получаю DataFrame, который выглядит следующим образом:

Item      Customer     Year   Month   Day   Qty      Amount
N2719     3110361      2003    9      1     30.0      220.80   
                       < ...  other transactions for N2719/3110361 item/customer combination ...>
          3110362      2004    9      10     9.0     823.00
                       < ...  other transactions for N2719/3110362 item/customer combination ...>
      < ... 198 other customers for N2719 ... >

X1046     3126034      2003   9       1     1.0      75.17
                       < ...  other transactions for X1046/3126034 item/customer combination ...>
          3126035      2005   1       2     50.0     500.00
                        < ...  other transactions for X1046/3126035 item/customer combination ...>
      < ... 48 other customers for X1046 ...>

< ... 6998 other items ... >

Ответы [ 2 ]

1 голос
/ 24 мая 2019

transform

df.assign(nu=df.groupby('Item').Customer.transform('nunique')) \
   .sort_values(['nu', 'Item'], ascending=[False, True])
0 голосов
/ 24 мая 2019

Вот как вы можете достичь того, что ищете:

import pandas as pd

df = pd.DataFrame({
    'Item':['X1046','X1046','N2719','N2719','N2719'],
    'Customer':['3126034','3126035','3110361','3110362','3110363'],
    'Year':[2003,2005,2003,2004,2004],
    'Month':[9,1,9,9,9],
    'Day':[1,2,1,10,10],
    'Qty':[1,50,30,9,9],
    'Amount':[75.17,500,220,823,823]
})

df.set_index(['Item', 'Customer', 'Year', 'Month', 'Day'], inplace=True, drop=True)
df.sort_index(inplace=True)

item_by_customers = df.reset_index().groupby('Item')['Customer'].nunique().sort_values(ascending=False).rename('Unique_Customers')

df = df.join(item_by_customers, on='Item').sort_values('Unique_Customers', ascending=False)

print(df)

Это дает вывод как:

                               Qty  Amount  Unique_Customers
Item  Customer Year Month Day
N2719 3110361  2003 9     1     30  220.00                 3
      3110362  2004 9     10     9  823.00                 3
      3110363  2004 9     10     9  823.00                 3
X1046 3126034  2003 9     1      1   75.17                 2
      3126035  2005 1     2     50  500.00                 2

Итак, основная стратегия состоит в том, чтобы добавить уникальное количество клиентов в виде столбца к исходному кадру данных, а затем отсортировать по желанию.

...