[英]Pandas groupby based on a condition from another column
我有一個 df,例如下面的示例,我正在尋找在給定時間段內發送相同文本的用戶,例如 <= 60 分鍾的示例:
user = [1,2,3,4,5,6]
text = ['hello','hello','whats up','not now','not now','hello']
times = ['2010-09-14 16:51:00','2010-09-14 15:59:00',
'2010-09-14 15:14:00','2010-09-14 14:55:00','2010-09-14 15:47:00','2010-09-14 15:29:00']
df = pd.DataFrame({'userid':user,'message':text,'time':times})
我當前的方法通過給每個文本發送消息的用戶列表對文本進行分組:
group = df.groupby('message')['userid'].apply(list)
然后我從每個列表中返回所有可能的用戶 ID 組合作為對值的數組,然后檢索每個實例的用戶 ID 文本作為從原始 df 檢索每對的每條消息的時間的鍵
這種方法有效,但我一直試圖找到一種更好的方法,根據每個實例之間的時間是否小於指定的時間段(例如本例中的 60 分鍾),有條件地對每個不同文本的用戶進行分組,作為差異在來自用戶的兩條消息之間。 因此,用戶 1 和 2 的“hello”相隔不到 60 分鍾,因此通過條件並將其添加到“hello”列表中。
因此,該示例的預期 output 將是:
userid
"hello" [1,2,6]
"not not" [4,5]
我還沒有找到任何確切或類似的解決方案,因此非常感謝任何幫助。 可能是我解決問題的方法是錯誤的!
一種選擇是使用groupby
按時間順序查找下一條匹配消息,將其merge
到原始 dataframe 中,然后過濾到消息間隙小於 1 小時的事物:
In [402]: df2 = df.merge(df.sort_values("time").groupby("message").shift(), left_index=True, right_index=True, suffixes=["_source", "_target"])
In [403]: df2.loc[df2['time_source'].sub(df2['time_target']).lt("1h"), ["message", "userid_source", "userid_target"]].astype('O')
Out[403]:
message userid_source userid_target
0 hello 1 2
1 hello 2 6
4 not now 5 4
請注意,在您當前的數據中,2 和 6 消息hello
相隔 30 分鍾,也出現在此處。
不確定這是最優雅的解決方案 - 但這是使用group-by
和rolling
的解決方案。 這種方法的優點是它可以處理大量數據。 它不會創建發送相同消息的所有用戶和時間的完整笛卡爾積。
res = []
def collect_users(x):
if len(x) > 1:
s = set(x)
if res and res[-1].issubset(s):
res.pop()
res.append(set(x))
return 0
df.groupby("message").rolling("3600s").agg(collect_users)
結果以集合列表的形式出現:
[{1.0, 2.0, 6.0}, {4.0, 5.0}]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.