显示多索引 pandas 数据框的前 10 行

Show first 10 rows of multi-index pandas dataframe

我有一个多级索引 pandas DataFrame,其中第一级是 year,第二级是 username。我只有一列已经按降序排列。我想显示每个索引级别 0 的前 2 行。

我有什么:

               count
year username                
2010 b         677
     a         505
     c         400
     d         300
 ...
2014 a         100
     b         80

我想要什么:

               count
year username                
2010 b         677
     a         505
2011 c         677
     d         505
2012 e         677
     f         505
2013 g         677
     i         505
2014 h         677
     j         505

这是一个答案。也许有更好的方法来做到这一点(使用索引?),但我认为它有效。 原理看似复杂其实很简单:

  • 按年份和用户名索引 DataFrame
  • 按年份对 DataFrame 进行分组,这是索引的第一级 (=0)
  • groupby获得的子DataFrame进行两次操作(每年一次)
    • 按计数升序排列索引sort_index(by='count')->计数多的行将在DataFrame
    • 的尾部
    • 使用负切片符号 ([-top:]) 仅保留最后 top 行(在本例中为 2 行)。也可以使用 tail 方法 (tail(top)) 来提高可读性。
  • 删除为年份 droplevel(0)
  • 创建的不必要的级别

# Test data    
df = pd.DataFrame({'year': [2010, 2010, 2010, 2011,2011,2011, 2012, 2012, 2013, 2013, 2014, 2014],
                  'username': ['b','a','a','c','c','d','e','f','g','i','h','j'],
                  'count': [400, 505, 678, 677, 505, 505, 677, 505, 677, 505, 677, 505]})
df = df.set_index(['year','username'])

top = 2
df = df.groupby(level=0).apply(lambda df: df.sort_index(by='count')[-top:])
df.index = df.index.droplevel(0)
df

               count
year username       
2010 a           505
     a           678
2011 d           505
     c           677
2012 f           505
     e           677
2013 i           505
     g           677
2014 j           505
     h           677

如果您有一个巨大的数据框,您可能不想 groupby 只是为了看一眼数据。这是获取外部索引的前五行和内部索引的前两行的另一种解决方案。

df = pd.DataFrame({'year': [2010, 2010, 2010, 2011,2011,2011, 2012, 2012, 2013, 2013, 2014, 2014],
              'username': ['b','a','a','c','c','d','e','f','g','i','h','j'],
              'count': [400, 505, 678, 677, 505, 505, 677, 505, 677, 505, 677, 505]})
df = df.set_index(['year','username'])

请注意 DataFrame 必须排序。

df = df.sort_index(level=[0,1])

df
                count
year    username    
2010    a       505
        a       678
        b       400
2011    c       677
        c       505
        d       505
2012    e       677
        f       505
2013    g       677
        i       505
2014    h       677
        j       505

现在开始魔术:

def head_mi(df, n1=5, n2=2):

    #get top n of outer index
    top_lev_0 = df.index.levels[0].values[:n1] 

    #get top n of inner index
    top_lev_1 = [df.loc[ind].index.values[:n2] for ind in top_lev_0 ] 
    #top_lev_1 is a list of the inner index values

    #iterate over outer index and get slice from inner index
    acc = []
    for count0, ind0 in enumerate(top_lev_0):
        acc.append(df.loc[(top_lev_0[count0], slice(top_lev_1[count0][0], top_lev_1[count0][-1])),:]) 

    return pd.concat(acc)

head_mi(df)  

这给出:

                count
year    username    
2010    a       505
        a       678
2011    c       677
        c       505
2012    e       677
        f       505
2013    g       677
        i       505
2014    h       677
        j       505 

我 运行 遇到了同样的问题,并在文档(pandas 版本 1.0.1)中找到了更简洁的答案:GroupBy: taking the first rows of each group。这是技巧,假设您的数据框被称为 df:

df.groupby(level=0).head(2)