簡體   English   中英

Pandas groupby 基於另一列的條件

[英]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-byrolling的解決方案。 這種方法的優點是它可以處理大量數據。 它不會創建發送相同消息的所有用戶和時間的完整笛卡爾積。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM