2016-05-02 74 views
0

我有一個非常大的熊貓數據框,我需要基於另一列的組內排序。我知道如何遍歷組,對組執行操作,然後將所有這些組合併到一個數據框中,但這很慢,我覺得有更好的方法來實現這一點。這是輸入和我想要的。輸入:在分組數據框中進行高效的操作熊貓

ID price 
1 100.00 
1 80.00 
1 90.00 
2 40.00 
2 40.00 
2 50.00 

輸出:

ID price order 
1 100.00 3 
1 80.00 1 
1 90.00 2 
2 40.00 1 
2 40.00 2 (could be 1, doesn't matter too much) 
2 50.00 3 

由於這是在大約5KK記錄有大約250,000 ID的效率是很重要的。

回答

1

您可以使用rank

df["order"] = df.groupby("ID")["price"].rank(method="first") 
df 
Out[47]: 
    ID price order 
0 1 100.0 3.0 
1 1 80.0 1.0 
2 1 90.0 2.0 
3 2 40.0 1.0 
4 2 40.0 2.0 
5 2 50.0 3.0 

需要大約30秒的5個行與25萬ID的數據集(i5-3330):

df = pd.DataFrame({"price": np.random.rand(5000000), "ID": np.random.choice(np.arange(250000), size = 5000000)}) 
%time df["order"] = df.groupby("ID")["price"].rank(method="first") 
Wall time: 36.3 s 
+0

非常感謝!這工作得非常好 –

+0

不客氣。很高興它有幫助。 – ayhan

2

如果速度是你想要什麼,然後以下應該是相當不錯的,儘管它更復雜一些,因爲它使用numpy中的複雜數字排序。這與在包0123'中編寫聚合排序方法時使用的方法(我的)類似。

# get global sort order, for sorting by ID then price 
full_idx = np.argsort(df['ID'] + 1j*df['price']) 

# get min of full_idx for each ID (note that there are multiple ways of doing this) 
n_for_id = np.bincount(df['ID']) 
first_of_idx = np.cumsum(n_for_id)-n_for_id 

# subtract first_of_idx from full_idx 
rank = np.empty(len(df),dtype=int) 
rank[full_idx] = arange(len(df)) - first_of_idx[df['ID'][full_idx]] 
df['rank'] = rank+1 

這需要我的機器,這大約是100倍比使用groupby.rank從大熊貓(雖然我沒有實際運行使用5M行大熊貓的版本,因爲它會花費太長的時間快上5米行2秒,我我不知道@ayhan是如何設法在30秒內完成的,或許是熊貓版本的差異?)。

如果你確實使用這個,那麼我建議徹底測試它,因爲我沒有。

+0

@hanhan他的解決方案可能足以滿足我的用例,但如果不是,我會研究它,謝謝! –

+0

這實際上比'rank'快得多。它的方式給出了相同的結果。 http://i.imgur.com/7UejPRI.png – ayhan

+0

請注意,這種方法假定ID是ints> = 0,而不是過大。如果情況並非如此,則需要一些額外的工作或稍微不同的方法(但總體方法仍然有效)。 –