2016-03-07 24 views
2

說我有這個數據幀,我想每一個唯一的用戶ID基於日期戳有它自己的等級值:添加等級字段通過獨特的羣體和多列排序,以大熊貓數據幀

In [93]: 
df = pd.DataFrame({ 
'userid':['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b'], 
'date_stamp':['2016-02-01', '2016-02-01', '2016-02-04', '2016-02-08', '2016-02-04', '2016-02-10', '2016-02-10', '2016-02-12'], 
'tie_breaker':[1,2,3,4,1,2,3,4]}) 

df['date_stamp'] = df['date_stamp'].map(lambda x: datetime.datetime.strptime(x, "%Y-%m-%d")) 
df['rank'] = df.groupby(['userid'])['date_stamp'].rank(ascending=True, method='min') 
df 

Out[93]: 
date_stamp tie_breaker userid rank 
0 2016-02-01 1 a 1 
1 2016-02-01 2 a 1 
2 2016-02-04 3 a 3 
3 2016-02-08 4 a 4 
4 2016-02-04 1 b 1 
5 2016-02-10 2 b 2 
6 2016-02-10 3 b 2 
7 2016-02-12 4 b 4 

所以這是很好,但是如果我想在有兩個相同的日期時添加另一個場來作爲決勝局,那該怎麼辦呢?我希望事情會是一樣簡單:

df['rank'] = df.groupby(['userid'])[['date_stamp','tie_breaker']].rank(ascending=True, method='min') 

但是,這並不工作 - 任何想法?

理想輸出:

date_stamp tie_breaker userid rank 
0 2/1/16 1 a 1 
1 2/1/16 2 a 2 
2 2/4/16 3 a 3 
3 2/8/16 4 a 4 
4 2/4/16 1 b 1 
5 2/10/16 2 b 2 
6 2/10/16 3 b 3 
7 2/12/16 4 b 4 

編輯以有真實數據
貌似頂部的解決方案在這裏正確tie_breaker場不處理零 - 任何想法,這是怎麼回事?

df = pd.DataFrame({ 
'userid':['10010012083198581013', '10010012083198581013', '10010012083198581013', '10010012083198581013','10010012083198581013'], 
'date_stamp':['2015-12-26 13:24:37', '2015-11-25 11:24:13', '2015-10-25 12:13:59', '2015-02-16 22:59:58','2015-08-17 11:43:43'], 
'tie_breaker':[460000156735858, 460000152444239, 460000147374709, 11083155016444116916,0]}) 
df['date_stamp'] = df['date_stamp'].map(lambda x: datetime.datetime.strptime(x, "%Y-%m-%d %H:%M:%S")) 
df['userid'] = df['userid'].astype(str) 
df['tie_breaker'] = df['tie_breaker'].astype(str) 

def myrank(g): 
    return pd.DataFrame(1 + np.lexsort((g['tie_breaker'].rank(), 
            g['date_stamp'].rank())), 
        index=g.index) 

df['rank']=df.groupby(['userid']).apply(myrank) 
df.sort('date_stamp') 

Out[101]: 
date_stamp tie_breaker userid rank 
3 2015-02-16 11083155016444116916 10010012083198581013 2 
4 2015-08-17 0 10010012083198581013 1 
2 2015-10-25 460000147374709 10010012083198581013 3 
1 2015-11-25 460000152444239 10010012083198581013 5 
0 2015-12-26 460000156735858 10010012083198581013 4 

回答

1

有了這個數據幀:

df = pd.DataFrame({ 
'userid':['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b'], 
'date_stamp':['2016-02-01', '2016-02-01', '2016-02-04', '2016-02-08', 
'2016-02-04', '2016-02-10', '2016-02-10', '2016-02-12'], 
'tie_breaker':[1,2,3,4,1,2,3,4]}) 

一種方式來做到這一點是:

def myrank(g): 
    return pd.DataFrame(1 + np.lexsort((g['tie_breaker'].rank(), 
             g['date_stamp'].rank())), 
         index=g.index) 


df['rank']=df.groupby(['userid']).apply(myrank) 

輸出:

date_stamp tie_breaker userid rank 
0 2016-02-01   1  a  1 
1 2016-02-01   2  a  2 
2 2016-02-04   3  a  3 
3 2016-02-08   4  a  4 
4 2016-02-04   1  b  1 
5 2016-02-10   2  b  2 
6 2016-02-10   3  b  3 
7 2016-02-12   4  b  4 
+0

酷,謝謝你的幫忙。看起來這不起作用,但我用一些新數據更新了原始問題。任何想法解決? –

+0

哈,是的,我是希望得到一個解決方案,不必假設這種排序會在排名前後保持一致,但它可能是我唯一的選擇! –

+0

@JohnE對於您的解決方案,我認爲它在您的示例中使用so ['date_stamp']之後選擇的字段重新排序。不知道這將如何影響排名前發生的排序。在A.P.的解決方案中,我嘗試將tie_breaker轉換爲float,並且沒有運氣。 –