Pandas实现指定日期范围的用户登录活跃总时长计算
实现方案
核心逻辑是先按用户+自然日聚合单日活跃窗口,再通过日期边界筛选统计总时长,完全适配你提到的所有自定义范围统计需求。
步骤1:预处理聚合单日活跃数据
你的样例数据中,同一用户同一天的多条事件对应当日一段连续活跃时段,因此先分组取当日最早、最晚事件时间作为活跃窗口的起止点,计算当日活跃时长:
import pandas as pd # 完成基础时间字段转换 df['datetime'] = pd.to_datetime(df['start_time'], unit='s') # 提取自然日维度用于分组 df['day'] = df['datetime'].dt.date # 聚合得到每个用户单日的活跃窗口 daily_active = df.groupby(['id', 'day']).agg( active_start=('datetime', 'min'), active_end=('datetime', 'max') ).reset_index() # 计算当日活跃时长(单位:秒) daily_active['duration_sec'] = (daily_active['active_end'] - daily_active['active_start']).dt.total_seconds()
步骤2:封装通用范围统计函数
支持传入任意起始/结束日期,可灵活配置是否包含边界日期,直接返回总活跃时长:
def calc_total_active(start_date=None, end_date=None, include_start=True, include_end=True): """ 统计指定日期范围内的全用户活跃总时长 参数说明: - start_date: 范围起始日期,支持字符串/date/datetime类型,传None代表不限制起始时间 - end_date: 范围结束日期,支持字符串/date/datetime类型,传None代表不限制结束时间 - include_start: 统计范围是否包含起始日期当天,默认True - include_end: 统计范围是否包含结束日期当天,默认True """ filter_cond = pd.Series(True, index=daily_active.index) # 拼接起始时间过滤条件 if start_date is not None: start = pd.to_datetime(start_date).date() filter_cond &= (daily_active['day'] >= start) if include_start else (daily_active['day'] > start) # 拼接结束时间过滤条件 if end_date is not None: end = pd.to_datetime(end_date).date() filter_cond &= (daily_active['day'] <= end) if include_end else (daily_active['day'] < end) # 汇总符合条件的总时长 total_seconds = daily_active.loc[filter_cond, 'duration_sec'].sum() return pd.Timedelta(seconds=total_seconds)
场景验证
你提到的几个统计场景可以直接调用函数得到正确结果:
- 统计2016-03-31之前的活跃总时长:
calc_total_active(end_date='2016-03-31', include_end=False),返回0 days 01:13:00,即1小时13分钟 - 统计截至2016-04-02的活跃总时长:
calc_total_active(end_date='2016-04-02'),返回0 days 02:15:00,即2小时15分钟 - 统计2016-04-01至2016-04-10区间活跃总时长:
calc_total_active(start_date='2016-04-01', end_date='2016-04-10'),返回0 days 01:43:00,即1小时43分钟
补充说明
- 如果需要格式化输出
X小时Y分钟的可读格式,可以加一个简单的转换函数:
def format_duration(td): total_min = int(td.total_seconds() // 60) hour = total_min // 60 minute = total_min % 60 return f"{hour}小时{minute}分钟" # 用法示例 print(format_duration(calc_total_active(end_date='2016-04-02'))) # 输出:2小时15分钟
- 如果需要按用户维度分别统计时长,只需要在过滤后的数据上按
id分组求和即可,核心逻辑无需调整。 - 如果后续存在跨天活跃的场景(比如用户活跃从23点持续到次日1点),只需要把分组逻辑替换为连续会话切分,再计算会话和统计日期范围的重叠时长即可,当前方案是匹配你现有数据特征的最简实现。
内容的提问来源于stack exchange,提问作者arilwan
相关产品推荐
相关产品推荐

