title: Pandas DataFrame : How to groupby and sort "by blocks"?
body: <p>I'm working with a DataFrame containing data as follows, and group the data two different ways.</p>
  <pre><code>&gt;&gt;&gt; d = {
       &quot;A&quot;: [100]*7 + [200]*7,
       &quot;B&quot;: [&quot;one&quot;]*4 + [&quot;two&quot;]*3 + [&quot;one&quot;]*3 + [&quot;two&quot;]*4,
       &quot;C&quot;: [&quot;foo&quot;]*3 + [&quot;bar&quot;] + [&quot;foo&quot;] + [&quot;bar&quot;]*2 + [&quot;foo&quot;]*2 + [&quot;bar&quot;] + [&quot;foo&quot;]*3 + [&quot;bar&quot;],
       &quot;D&quot;: [&quot;yay&quot;] + [&quot;nay&quot;]*2 + [&quot;yay&quot;] + [&quot;nay&quot;]*3 + [&quot;yay&quot;] + [&quot;nay&quot;] + [&quot;yay&quot;]*3 + [&quot;nay&quot;] + [&quot;yay&quot;],
       &quot;X&quot;: [2, 8, 3, 5, 1, 4, 3, 2, 6, 5, 1, 2, 4, 7]
      }
  
  &gt;&gt;&gt; df = pd.DataFrame(d)
  &gt;&gt;&gt; df
  
       A    B    C    D    X
  0  100  one  foo  yay    2
  1  100  one  foo  nay    8
  2  100  one  foo  nay    3
  3  100  one  bar  yay    5
  4  100  two  foo  nay    1
  5  100  two  bar  nay    4
  6  100  two  bar  nay    3
  7  200  one  foo  yay    2
  8  200  one  foo  nay    6
  9  200  one  bar  yay    5
  10 200  two  foo  yay    1
  11 200  two  foo  yay    2
  12 200  two  foo  nay    4
  13 200  two  bar  yay    7
  
  &gt;&gt;&gt; df_grp = df.groupby(['A', 'B'])
  &gt;&gt;&gt; df_grp_sorted = df_grp.sum().sort_values('X', ascending = False)
  &gt;&gt;&gt; df_grp_long = df.groupby(['A', 'B', 'C', 'D'])
  &gt;&gt;&gt; df_grp_sorted_long = df_grp_long.sum().sort_values('X', ascending = False)
  </code></pre>
  <p>This gives us :</p>
  <pre><code>&gt;&gt;&gt; df_grp_sorted
  
              X
  100  one   18
  200  two   14
       one   13
  100  two    8
  
  
  &gt;&gt;&gt; df_grp_sorted_long
  
                        X
  100  one  foo  nay   11
       two  bar  nay    7
  200  two  bar  yay    7
       one  foo  nay    6
  100  one  bar  yay    5
  200  one  bar  yay    5
       two  foo  nay    4
                 yay    3
  100  one  foo  yay    2
  200  one  foo  yay    2    
  100  two  foo  nay    1
  </code></pre>
  <p>Now, I would like to have the detail from df_grp_sorted_long, with the structure of df_grp_sorted. That would be :</p>
  <pre><code>&gt;&gt;&gt; df_result
  
                        X
  100  one  foo  nay   11
                 yay    5
            foo  yay    2
  200  two  bar  yay    7
            foo  nay    4
                 yay    3
       one  foo  nay    6
            bar  yay    5
            foo  yay    2    
  100  two  bar  nay    7
            foo  nay    1
            
  </code></pre>
  <p>I have done this with the following code (which goes against <a href="https://stackoverflow.com/a/56746204/4909087">this post</a>'s advice) :</p>
  <pre><code>&gt;&gt;&gt; col_names = ['A', 'B', 'C', 'D']
  &gt;&gt;&gt; df_result = pd.DataFrame(columns=col_names)
  &gt;&gt;&gt; for (i, (a, b)) in enumerate(df_grp_sorted.index):
          df_result = pd.concat(
              (
                  df_result,
                  (df[(df['A']==a) &amp; (df['B']==b)]
                  .groupby(col_names)
                  .sum()
                  .sort_values('X', ascending=False)
                  )
              )
          )
  &gt;&gt;&gt; df_result = df_result[&quot;X&quot;]
  </code></pre>
  <p>This gives the right answer, but is very slow for big data sets. I'm also wondering if there's a native way to do such a combination of grouping/sorting.</p>
  <p>Also, maybe this approach is not the right one and there's a much simpler way to obtain this result of an equivalent one?</p>