如何在Pandas中提取用户操作时段的起止时间?
问题描述
我有如下Pandas DataFrame,其中delta列是Submission_Ended列的行间时间差,当差值超过20分钟时new period标记为True,代表用户休息后重新使用的新时段:
+----------+-------------------+---------------------+----------+------------+ | UserName | MainOperationName | Submission_Ended | delta | new period | +----------+-------------------+---------------------+----------+------------+ | User1 | Record submission | 2017-07-31 00:08:25 | 00:00:00 | False | | User1 | Record submission | 2017-07-31 00:12:02 | 00:03:37 | False | | User1 | Record submission | 2017-07-31 00:14:51 | 00:02:49 | False | | User1 | Record submission | 2017-07-31 00:17:27 | 00:02:36 | False | | User1 | Record submission | 2017-07-31 00:23:42 | 00:06:15 | False | | User1 | Record submission | 2017-07-31 00:25:35 | 00:01:53 | False | | User1 | Record submission | 2017-07-31 00:26:01 | 00:00:26 | False | | User1 | Record submission | 2017-07-31 01:59:11 | 01:33:10 | True | | User1 | Record submission | 2017-07-31 02:00:37 | 00:01:26 | False | | User1 | Record submission | 2017-07-31 02:03:12 | 00:02:35 | False | | User1 | Record submission | 2017-07-31 02:21:22 | 00:18:10 | False | | User1 | Record submission | 2017-07-31 02:30:28 | 00:09:06 | False | | User1 | Record submission | 2017-07-31 02:36:03 | 00:05:35 | False | | User1 | Record submission | 2017-07-31 03:25:43 | 00:49:40 | True | +----------+-------------------+---------------------+----------+------------+
我的需求是:
- 把每个用户的第一行
new period设为True,因为它是新时段的开始 - 提取每个用户的各个使用时段的起止时间,最终输出类似:
真实数据包含数百个用户,需要兼容多用户场景。User1: start: 2017-07-31 00:08:25 ; stop: 2017-07-31 00:26:01 start: 2017-07-31 01:59:11 ; stop: 2017-07-31 02:36:03 start: 2017-07-31 03:25:43 ; stop: ...
解决方案
没问题,这个需求用Pandas的分组和累积操作就能轻松实现,而且完全适配多用户的场景,具体步骤如下:
1. 确保时间列格式正确
首先得把Submission_Ended转成datetime类型,不然后续的时间操作会出问题:
df['Submission_Ended'] = pd.to_datetime(df['Submission_Ended'])
2. 修正new period列,标记用户首行为新时段
我们可以通过分组后标记首行,再把首行的new period设为True:
# 给每个用户的第一行打标记 df['is_first_row'] = df.groupby('UserName').cumcount() == 0 # 把首行的new period设为True,和原来的True做或运算 df['new period'] = df['new period'] | df['is_first_row'] # 删掉临时列(也可以保留,看你需求) df = df.drop('is_first_row', axis=1)
3. 为每个时段生成唯一分组ID
利用new period的累积求和,给同一个用户内的连续使用时段分配唯一ID,这样就能把同一个时段的行归为一组:
df['period_id'] = df.groupby('UserName')['new period'].cumsum()
4. 聚合提取每个时段的起止时间
按用户和时段ID分组,取每个组内最早的时间作为start,最晚的作为stop:
periods = df.groupby(['UserName', 'period_id']).agg( start=('Submission_Ended', 'min'), stop=('Submission_Ended', 'max') ).reset_index(drop=True)
5. 格式化输出结果
如果需要像你预期的那样打印每个用户的时段,可以用这段代码:
for user in periods['UserName'].unique(): user_periods = periods[periods['UserName'] == user] print(f"{user}:") for idx, row in user_periods.iterrows(): # 最后一个时段如果没有后续数据,就用...代替stop stop_str = row['stop'].strftime('%Y-%m-%d %H:%M:%S') if idx != len(user_periods)-1 else '...' print(f"start: {row['start'].strftime('%Y-%m-%d %H:%M:%S')} ; stop: {stop_str}")
运行效果(针对示例数据)
执行后会输出:
User1: start: 2017-07-31 00:08:25 ; stop: 2017-07-31 00:26:01 start: 2017-07-31 01:59:11 ; stop: 2017-07-31 02:36:03 start: 2017-07-31 03:25:43 ; stop: ...
这个方案不管你有多少用户,都能自动按用户分组处理,完美适配你的真实数据场景。
内容的提问来源于stack exchange,提问作者pawelty
相关产品推荐
相关产品推荐

