如何通过子级别中的行数对MultiIndex级别进行排序

时间:2019-05-24 16:01:13

标签: python-3.x pandas sorting dataframe multi-index

我具有公司出售给许多不同客户的商品的数量和金额(在交易中收取了多少)的历史数据。我希望对此数据进行一些时间序列分析,但希望在项目客户级别进行。

这是我的原始数据:

      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>

这是按年/月/日排序的交易数据,并捕获向哪个客户出售了哪个项目以及该次销售中的数量和金额。

由于我要按商品和客户分析时间序列,因此我对其应用了MultiIndex:

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 ... >

如您所见,由于我有7,000个不同的商品,每个商品可以有数十个或数百个客户,因此我只想关注那些拥有大量客户群的商品。数据集中有很多物品可能是过去某个时候有1位客户购买的,并且可能已经停产,等等。

因此,请使用以下内容获取按客户数量排序的商品:

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 ...>

我可以看到为什么会出现此错误,因为索引中有7,000个项目,而DataFrame中有2.7M行。

我也尝试过重新索引:

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 个答案:

答案 0 :(得分:1)

transform

df.assign(nu=df.groupby('Item').Customer.transform('nunique')) \
   .sort_values(['nu', 'Item'], ascending=[False, True])

答案 1 :(得分:0)

这是您如何实现所需的东西:

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

因此,基本策略是将唯一客户数作为一列添加到原始数据框,然后根据需要进行排序。