2017-07-07 71 views
2

在DataFrameGroupBy基地行,我有以下數據框(稱爲DF):熊貓選擇在分級指數

user_id product_id probReorder 
0  1   196   1.0 
1  1  10258   0.9 
2  1  10326   0.1 
3  1  12427   1.0 
4  1  13032   0.3 
... 

對於每個DF user_id說明,我想只保留N個在「probReorder」列中具有最大值的行。另外,我想N取決於user_id。 在我目前的做法,我有一個字典「lastReordNumber」,其鍵值對是(USER_ID,INT),我選擇如下行:

predictions = [] 
for usr,data in df.groupby(by="user_id"): 
    data = data.nlargest(lastReordNumber[usr], "probReorder") 
    predictions.append(data) 
df = pd.concat(predictions) 

的問題是,這實在是太慢了。該數據幀有大約13M行和200k獨特user_id's。有更快/更好的方法嗎?

編輯:先前的代碼產生當存在對於給定的USER_IDprobReorder列重複的值意外輸出。例如:

lastReordNumber = {1:2, 2:3} 
df = pd.DataFrame({"user_id":[1,1,1,2,2,2,2],"probReorder":[0.9,0.6,0.9,0.1,1,0.5,0.4],\ 
    "product_id":[1,2,3,4,5,6,7]}) 

我得到的輸出:

probReorder product_id user_id 
0   0.9   1  1 
1   0.9   3  1 
2   0.9   1  1 
3   0.9   3  1 
4   1.0   5  2 
5   0.5   6  2 
6   0.4   7  2 

這對於USER_ID = 2是我所期望的,但對於USER_ID = 1有重複的行。 我的預期輸出是:

probReorder product_id user_id 
0   0.9   1  1 
1   0.9   3  1 
2   1.0   5  2 
3   0.5   6  2 
4   0.4   7  2 

這可以通過使用簡單的一段代碼

predictions = [] 
for usr,data in df.groupby(by="user_id"): 
    predictions.append(data.sort_values('probReorder', ascending=False).head(lastReordNumber[usr])) 
predictions = pd.concat(predictions, ignore_index=True) 

,其中每一列被完全排序,然後截斷而獲得。這也是相當高效的。 雖然我還沒有理解如何解釋nlargest()方法的結果。

+0

當你有等於最大的兩個或多個行會發生什麼? –

+0

@BobHaffner好問題。看起來nlargest不像我預期的那樣行事,並且正在複製一些行。我應該發佈測試用例的輸出嗎? – chubecca

+0

我會發布一些其他示例數據,其中包含另一個user_id。併發布您的期望輸出 –

回答

2

您可以使用sort_valuesgroupbyhead

df1 = df.sort_values('probReorder', ascending=False) 
     .groupby('user_id', group_keys=False) 
     .apply(lambda x: x.head([x.name])) 
print (df1) 
    probReorder product_id user_id 
0   0.9   1  1 
2   0.9   3  1 
4   1.0   5  2 
5   0.5   6  2 
6   0.4   7  2 

nlargest另一種解決方案:

df1 = df.groupby('user_id', group_keys=False) 
     .apply(lambda x: x.nlargest(lastReordNumber[x.name], 'probReorder')) 
print (df1) 
    probReorder product_id user_id 
0   0.9   1  1 
2   0.9   3  1 
4   1.0   5  2 
5   0.5   6  2 
6   0.4   7  2 
+0

感謝您的答案。一些評論:drop_duplicates()在這種情況下不做任何事情,因爲沒有重複的(user_id,product_id)對。您的第一個解決方案應該與我在編輯中提供的解決方案相同,但它更優雅,也許更有效。您的第二個解決方案在我的機器上無法正常工作,它會產生上述我提供的相同「錯誤」輸出。這可能是nlargest()中的一個錯誤,我必須查看它。 – chubecca

+0

我看到您的數據,似乎有一些重複。如果不是,那會更好。如果我的回答有幫助,請不要忘記[接受](http://meta.stackexchange.com/a/5235/295067) - 點擊答案旁邊的複選標記('✓')將其從灰色出來填補。謝謝。 – jezrael

+0

正如我所說的(「user_id」,「product_id」)列中沒有重複項,如果我錯了,請糾正我,因此您對drop_duplicates的調用不會執行任何操作。您的兩個解決方案與我的兩個解決方案相同,但其中一個解決方案在我的系統上的行爲不如預期。我認爲我的原始問題已經解決,但我仍然不明白nlargest()的問題。 – chubecca