2016-12-04 55 views
2

我有一個數據幀,看起來像這樣:在熊貓中,如何在DataFrame中排名前十組數據?

import pandas as pd 
import numpy as np 
rand = np.random.RandomState(1) 
df = pd.DataFrame({'A': ['foo', 'bar', 'baz'] * 10, 
        'B': [rand.choice(['cat', 'dog', 'fish', 'pig', 'cow']) for i in range(30)], 
        'C': 1}) 

>> df.head(5) 
    A B C 
0 foo pig 1 
1 bar cow 1 
2 baz cat 1 
3 foo dog 1 
4 bar pig 1 

我再由不同的組合組獲得計數,這是我爲了按組下降,就像這樣:

>> d = df.groupby(['A','B']).sum(); 
>> d = d.groupby(level=0, group_keys=False).apply(lambda x: x.sort_values('C', ascending=False)); d 

      C 
A B  
bar dog 4 
    cow 2 
    fish 2 
    cat 1 
    pig 1 
baz cow 4 
    cat 3 
    fish 2 
    dog 1 
foo dog 4 
    cow 3 
    pig 2 
    cat 1 

我現在想什麼對於A中的每個組,保持排名前2位,並將剩下的數字總結爲「其他」。我有一個函數summarise()哪種類型的作品:

def summarise(l, n=10, name='Other'): 
    h = l.head(n) 

    idx = l.index[0] 
    if isinstance(idx, (list, tuple)): 
     prefix = list(idx[:-1]) 
    else: 
     prefix = [] 
    return h.append(pd.DataFrame([l.tail(-n).sum()], columns=l.columns, index=[tuple(prefix+[name])])) 

>> summarise(d, n=2) 
      C 
A B   
bar dog  4 
    cow  2 
    Other 24 

但是,如果我嘗試使用適用於做它每次炸燬組。看來該函數通過Series而不是?

我想輸出的是以下幾點:

A  B C 
bar dog 4 
bar cow 2 
bar Other 4 
baz cow 4 
baz cat 3 
baz Other 3 
foo dog 4 
foo cow 3 
foo Other 3 

我還以爲那d.groupby('A').tail(-2).sum()會的工作,但它不會做什麼我的期望。

編輯:感謝我的答案,我想出了以下功能,應該可以幫助未來的人。有點煩人,1列和更多列的情況是不同的,但也是如此。支持每組最高N,但也是一個截止百分比。有了這個功能,我可以很容易地以多種方式切分和裁切數據。

def top_per_group(df, cols, n=None, p=None, name='Other'): 
    d=df.groupby(cols).size().sort_values(ascending=False) 
    if len(cols) > 1: 
     d = d.sortlevel(0, sort_remaining=False) 

    d = d.reset_index() 

    if n: 
     if len(cols) > 1: 
      sel_list = d.groupby(cols[:-1]).cumcount()<n 
     else: 
      sel_list = d.index<n 
    else: 
     if len(cols) > 1: 
      sel_list = d.groupby(cols[:-1])[0].apply(lambda x: x/float(x.sum())) >= p 
     else: 
      sel_list = d[0].div(d[0].sum()) >= p 

    grouper = d[cols[-1]].where(sel_list, name) 
    return d.groupby(cols[:-1] + [grouper], sort=False).sum().reset_index() 
+0

作爲@juanpa還指出申請是低效的有而你實際上並不需要C列。它可以用'df.groupby(list('AB'))。size()。sort_values(ascending = False).sortlevel(0,sort_remaining = False)' – ayhan

回答

2

如果重置索引,您可以創建累計次數石斑魚:

d = d.reset_index() 
grouper = d['B'].where(d.groupby('A').cumcount()<2, 'Other') 
d.groupby(['A', grouper], sort=False).sum() 
Out: 
      C 
A B  
bar dog 4 
    cow 2 
    Other 4 
baz cow 4 
    cat 3 
    Other 3 
foo dog 4 
    cow 3 
    Other 3 

或者與reset_index:

d.groupby(['A', grouper], sort=False).sum().reset_index() 
Out: 
    A  B C 
0 bar dog 4 
1 bar cow 2 
2 bar Other 4 
3 baz cow 4 
4 baz cat 3 
5 baz Other 3 
6 foo dog 4 
7 foo cow 3 
8 foo Other 3 
+0

明顯地我完全錯了。我不確定我完全瞭解您的解決方案如何工作,但它確實如此。謝謝。 – kleptog