如何为 pandas 数据框中的不同组分配唯一 ID?

Posted

技术标签:

【中文标题】如何为 pandas 数据框中的不同组分配唯一 ID?【英文标题】:How to assign a unique ID for different groups in pandas dataframe? 【发布时间】:2019-11-20 12:47:34 【问题描述】:

如何根据特定条件为在 pandas 数据框中创建的组分配唯一 ID。 例如:我有一个名为 df 的数据框,其结构如下:Name 标识用户,datetime 标识用户访问资源的日期/时间。

Name         Datetime 
Bob          26-04-2018 12:00:00 
Claire       26-04-2018 12:00:00 
Bob          26-04-2018 12:10:00 
Bob          26-04-2018 12:30:00 
Grace        27-04-2018 08:30:00 
Bob          27-04-2018 09:30:00 
Bob          27-04-2018 09:40:00 
Bob          27-04-2018 10:00:00 
Bob          27-04-2018 10:30:00 
Bob          27-04-2018 11:30:00

我想为用户创建会话,以便为具有相同名称和日期时间值的用户访问资源不超过 30 分钟分配一个唯一会话。但是,如果用户在访问资源时显示某些不活动超过 30 分钟,则同一用户将被分配不同的会话以供下次用户访问资源时使用。

我的预期输出将如图所示。

用户 Bob 于 2018 年 4 月 27 日,在 9.30 访问资源,第二次 @ 9.40,第三次 @ 10.00,第四次 @10.30 -> 都使用会话 4。但是下次用户 Bob 访问 @ 11.30 所以时差超过 30 分钟,因为 Bob 已经超过 30 分钟不活动,所以下一个会话将分配给他。

Name         Datetime                    Id
Bob          26-04-2018 12:00:00          1
Claire       26-04-2018 12:00:00          2
Bob          26-04-2018 12:10:00          1
Bob          26-04-2018 12:30:00          1
Grace        27-04-2018 08:30:00          3
Bob          27-04-2018 09:30:00          4
Bob          27-04-2018 09:40:00          4
Bob          27-04-2018 10:00:00          4
Bob          27-04-2018 10:30:00          4
Bob          27-04-2018 11:30:00          5

感谢您的帮助! 上一个问题的链接:How to compare value of second column with same values of first column in pandas dataframe?

【问题讨论】:

也刚刚意识到这似乎与您的其他问题相同,只是有一个更好的示例(此处)。 @SergeBallesta 在他对唯一标签组的回答中提供了正确的逻辑。我的解决方案结果非常相似,只是稍微紧凑一些,并且没有合并。您可以考虑在那里接受他的解决方案,或者作为副本关闭。 【参考方案1】:

sort 并找出连续动作的时间差 ('td')。 cumsum 一个布尔系列,在最后一个动作的 30 分钟内形成一组连续动作。 ngroup 标记组。

如果您不关心组获得哪个标签,则可以删除 groupby 之前的 sort_index,但这可确保根据原始顺序对它们进行排序。

df = df.sort_values(['Name', 'Datetime'])
df['td'] = df.Datetime.diff().mask(df.Name.ne(df.Name.shift()))
                             # Only calculate diff within same Name
df['Id'] = (df.sort_index()
              .groupby(['Name', df['td'].gt(pd.Timedelta('30min')).cumsum()], sort=False)
              .ngroup()+1)
df = df.sort_index()

输出:

td 为清楚起见留下了

     Name            Datetime       td  Id
0     Bob 2018-04-26 12:00:00      NaT   1
1  Claire 2018-04-26 12:00:00      NaT   2
2     Bob 2018-04-26 12:10:00 00:10:00   1
3     Bob 2018-04-26 12:30:00 00:20:00   1
4   Grace 2018-04-27 08:30:00      NaT   3
5     Bob 2018-04-27 09:30:00 21:00:00   4
6     Bob 2018-04-27 09:40:00 00:10:00   4
7     Bob 2018-04-27 10:00:00 00:20:00   4
8     Bob 2018-04-27 10:30:00 00:30:00   4
9     Bob 2018-04-27 11:30:00 01:00:00   5

【讨论】:

【参考方案2】:

您在底部的解释对理解它非常有帮助。

您需要在NamegroupID 上进行分组(不要将此groupID 与您的最终Id 混淆)并调用ngroup 以返回Id。主要是如何定义这个groupID。要创建groupID,您需要sort_values 将每个NameDatetime 分隔为升序。 Groupby Name 并找出Datetime 每组Name 内连续行之间的差异(在同一Name 内)。使用gt 检查超过 30 分钟,使用cumsum 获得groupIDsort_index 反转回原始顺序并分配给s,如下所示:

s = df.sort_values(['Name','Datetime']).groupby('Name').Datetime.diff() \
      .gt(pd.Timedelta(minutes=30)).cumsum().sort_index()

接下来,groupby Name and s with sort=False 保留原始订单并致电ngroup 加1。

df['Id'] = df.groupby(['Name', s], sort=False).ngroup().add(1)

Out[834]:
     Name            Datetime  Id
0     Bob 2018-04-26 12:00:00   1
1  Claire 2018-04-26 12:00:00   2
2     Bob 2018-04-26 12:10:00   1
3     Bob 2018-04-26 12:30:00   1
4   Grace 2018-04-27 08:30:00   3
5     Bob 2018-04-27 09:30:00   4
6     Bob 2018-04-27 09:40:00   4
7     Bob 2018-04-27 10:00:00   4
8     Bob 2018-04-27 10:30:00   4
9     Bob 2018-04-27 11:30:00   5

【讨论】:

以上是关于如何为 pandas 数据框中的不同组分配唯一 ID?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 Spark RDD 中的元素分配唯一的连续编号

如何为R中的重复值分配唯一的等级编号

Excel:如何为唯一组合分配值/检查大型数据集中的唯一组合

如何为列表框中的每个项目设置不同的工具提示文本?

如果没有插入值,如何为 SQL Server 中的列字段分配唯一值?

Python Pandas数据框中的行排序/计数