DataFrame 新列按时差拆分会话 - pandas

DataFrame New Column to split sessions by time difference - pandas

我有以下排序的 DataFrame:

import pandas as pd

hits = {'id': ['A','A','A','A','B','B','C','C'],
        'datetime': ['2010-01-02 03:00:00','2010-01-02 03:05:10','2010-01-02 03:51:35','2010-01-02 04:40:20',
                    '2010-01-02 03:29:10','2010-01-02 03:29:15','2010-01-02 03:45:20','2010-01-02 06:10:05'],
        'value': [1,2,2,1,1,3,2,4]
       }

df = pd.DataFrame(hits, columns = ['id', 'datetime','value'])

df['datetime'] =  pd.to_datetime(df['datetime'], format='%Y-%m-%d %H:%M:%S')

print (df)


  id            datetime  value
0  A 2010-01-02 03:00:00      1
1  A 2010-01-02 03:05:10      2
2  A 2010-01-02 03:51:35      2
3  A 2010-01-02 04:40:20      1
4  B 2010-01-02 03:29:10      1
5  B 2010-01-02 03:29:15      3
6  C 2010-01-02 03:45:20      2
7  C 2010-01-02 06:10:05      4

id 列允许我区分唯一用户,但我想更进一步,能够按会话对点击进行分组。一次会话定义为所有用户 activity 在 activity.

中不超过 30 分钟

在我的 DataFrame 中,所需的输出应该是:

  id            datetime  value  session
0  A 2010-01-02 03:00:00      1        1
1  A 2010-01-02 03:05:10      2        1
2  A 2010-01-02 03:51:35      2        2
3  A 2010-01-02 04:40:20      1        3
4  B 2010-01-02 03:29:10      1        1
5  B 2010-01-02 03:29:15      3        1
6  C 2010-01-02 03:45:20      2        1
7  C 2010-01-02 06:10:05      4        2

SQL 中,我首先使用 lag 来计算 partition by id order by datetime asc 上点击之间的差异,然后在新查询中我将 sum(case when diff > 30min then 1 else 0 end),按 id 分区也是。

Pandas 中有类似的东西吗?

diff上使用cumsum与阈值比较来识别由阈值分隔的块是一种常用技术。类似于:

series.diff().gt('30Min').cumsum()

因为你想通过 id 找到块,你只需要将它包装在 groupby():

df['session'] = (df.groupby('id')['datetime']
                   .transform(lambda x: x.diff().gt('30Min').cumsum())
                )

输出:

  id            datetime  value  session
0  A 2010-01-02 03:00:00      1        0
1  A 2010-01-02 03:05:10      2        0
2  A 2010-01-02 03:51:35      2        1
3  A 2010-01-02 04:40:20      1        2
4  B 2010-01-02 03:29:10      1        0
5  B 2010-01-02 03:29:15      3        0
6  C 2010-01-02 03:45:20      2        0
7  C 2010-01-02 06:10:05      4        1

你可以双打.groupby:

  1. 您可以创建一个名为 sboolean series,它在 id 和 returns True 或 [=17= 上使用 .groupby ] 对于每个组中的每一行,如果大于 30 分钟。
  2. 然后,您可以再次对您在步骤 1 中创建的 id 进行分组,并 return 使用 .cumsum 的累积计数并加 1,这样您就可以从 1 开始计数共 0

df['session'] = (df.assign(session=(df.groupby('id')['datetime'].diff() > '00:30:00')
                                      .astype(int))
                   .groupby('id')['session'].cumsum() + 1)
Out[1]: 
  id            datetime  value  session
0  A 2010-01-02 03:00:00      1        1
1  A 2010-01-02 03:05:10      2        1
2  A 2010-01-02 03:51:35      2        2
3  A 2010-01-02 04:40:20      1        3
4  B 2010-01-02 03:29:10      1        1
5  B 2010-01-02 03:29:15      3        1
6  C 2010-01-02 03:45:20      2        1
7  C 2010-01-02 06:10:05      4        2