Python Pandas,根据条件选择和删除基于多列分组的行

3
假设我有一个带有以下列和数据的pandas DataFrame:
    user            time           session         time_diff
0   21.0    2022-12-16 14:03:08        5           NaN
1   21.0    2022-12-16 14:03:10        5           2.0
2   21.0    2022-12-16 14:03:12        6           2.0
3   21.0    2022-12-16 14:03:13        6           1.0
4   21.0    2022-12-28 14:49:54        16          1039601.0
5   30.0    2022-12-16 14:03:16        5           1039598.0
6   30.0    2022-12-16 14:03:18        5           2.0
7   30.0    2022-12-16 14:03:20        6           2.0

我想选择那些在同一用户和会话中时间差(以秒为单位的time_diff列)小于某个阈值(例如10秒)的行。这将导致以下输出:
    user            time           session         time_diff
1   21.0    2022-12-16 14:03:10        5           2.0
3   21.0    2022-12-16 14:03:13        6           1.0
6   30.0    2022-12-16 14:03:18        5           2.0

我可以遍历每一行,并选择id = 前一行的id和session = 前一行的session的记录,但我认为这不是最优的方法。
df.groupby(['user', 'session']).filter(lambda x: (x.time_diff <= 10).any()) 

也没有产生预期的结果。
1个回答

3

选项1

  • ["user", "session"]进行分组(df.groupby),并检查"time"列的.diff
  • 对于生成的Series,使用Series.lt检查是否小于10秒。
  • 最后,使用生成的Series(包含TrueFalse)进行布尔索引以检索所需的子集。
out = df[df.groupby(["user", "session"])['time'].diff()
         .lt(pd.Timedelta('00:00:10'))]
out

   user                time  session  time_diff
1  21.0 2022-12-16 14:03:10        5        2.0
3  21.0 2022-12-16 14:03:13        6        1.0
6  30.0 2022-12-16 14:03:18        5        2.0

选项2
(假设您的数据已经按照“用户”和“会话”正确排序。)
Series.diff应用于列"time",并检查是否小于10秒。 现在,还要检查usersession的行值是否都等于前一行的值(df.eq)。使用df.shift将所有移动到新组的行使用df.all逐行获取False。 最后,使用位运算符&df应用布尔索引,选择满足两个条件都为True的行。
out2 = df[df.time.diff().lt(pd.Timedelta('00:00:10')) & 
          df[['user','session']].eq(df[['user','session']].shift(1)).all(axis=1)]

out2.equals(out)
# True

性能比较

选项1将是最快的。两者都比@AndrejKesely提供的solution更快。

# opt1: 1.75 ms ± 176 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
# opt2: 3.1 ms ± 133 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# AK:   7.02 ms ± 300 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

使用的数据

import pandas as pd
import numpy as np

data = {'user': {0: 21.0, 1: 21.0, 2: 21.0, 3: 21.0, 4: 21.0, 5: 30.0, 6: 30.0, 
                 7: 30.0}, 
        'time': {0: '2022-12-16 14:03:08', 1: '2022-12-16 14:03:10', 
                 2: '2022-12-16 14:03:12', 3: '2022-12-16 14:03:13', 
                 4: '2022-12-28 14:49:54', 5: '2022-12-16 14:03:16', 
                 6: '2022-12-16 14:03:18', 7: '2022-12-16 14:03:20'}, 
        'session': {0: 5, 1: 5, 2: 6, 3: 6, 4: 16, 5: 5, 6: 5, 7: 6}, 
        'time_diff': {0: np.nan, 1: 2.0, 2: 2.0, 3: 1.0, 4: 1039601.0, 5: 2, 
                      6: 2.0, 7: 2.0}}

df = pd.DataFrame(data)

df['time'] = pd.to_datetime(df['time'])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接