如何用Pandas按月份计算登录时长?附DataFrame示例
Pandas处理登录登出时长按月统计解决方案
初始数据
| Index | ID | Event | Datetime |
|---|---|---|---|
| 1 | 1 | Login | 10.03.2023 12:00:00.000 |
| 2 | 1 | Logout | 05.04.2023 12:00:00.000 |
| 3 | 2 | Login | 20.04.2023 12:00:00.000 |
| 4 | 2 | Logout | 22.04.2023 12:00:00.000 |
| 5 | 1 | Login | 20.05.2023 12:00:00.000 |
| 6 | 1 | Login | 21.05.2023 12:00:00.000 |
| 7 | 1 | Logout | 22.05.2023 12:00:00.000 |
| 8 | 1 | Logout | 25.05.2023 12:00:00.000 |
目标结果
| ID | TimeInDays | Month |
|---|---|---|
| 1 | 21 | March |
| 1 | 5 | April |
| 1 | 6 | May |
| 2 | 2 | April |
实现方案
不需要拆分登录和登出DataFrame再合并,通过分组配对+时段拆分的方式即可完成需求,具体步骤如下:
1. 数据预处理
先将字符串类型的Datetime列转换为Pandas的datetime类型,并按ID和时间排序,保证记录的时间顺序:
import pandas as pd from datetime import timedelta # 构造初始DataFrame data = { 'Index': [1,2,3,4,5,6,7,8], 'ID': [1,1,2,2,1,1,1,1], 'Event': ['Login','Logout','Login','Logout','Login','Login','Logout','Logout'], 'Datetime': ['10.03.2023 12:00:00.000','05.04.2023 12:00:00.000','20.04.2023 12:00:00.000','22.04.2023 12:00:00.000','20.05.2023 12:00:00.000','21.05.2023 12:00:00.000','22.05.2023 12:00:00.000','25.05.2023 12:00:00.000'] } df = pd.DataFrame(data) # 转换时间列格式 df['Datetime'] = pd.to_datetime(df['Datetime'], format='%d.%m.%Y %H:%M:%S.%f') # 按ID和时间排序 df = df.sort_values(['ID', 'Datetime'])
2. 配对登录登出记录
给每个ID下的Login和Logout记录按顺序分配配对ID,确保第一个登录对应第一个登出、第二个登录对应第二个登出:
df['pair_id'] = df.groupby(['ID', 'Event']).cumcount() # 透视得到配对的登录登出时间,过滤无配对的记录 pairs = df.pivot(index=['ID', 'pair_id'], columns='Event', values='Datetime').dropna()
3. 拆分跨月时段并计算时长
定义函数将单个登录-登出时段拆分为对应月份的时长,再对每个配对时段应用该函数:
def split_period_to_months(start, end): months = [] current = start while current <= end: # 获取当月最后一天 next_month = current + pd.DateOffset(months=1) month_end = next_month - pd.DateOffset(days=1) # 确定当月实际结束日期(不超过登出时间) actual_end = min(month_end, end) # 计算当月停留天数 days = (actual_end - current).days months.append({ 'Month': current.strftime('%B'), 'TimeInDays': days }) current = next_month return pd.DataFrame(months) # 处理所有配对时段 result_list = [] for (id_, pair_id), row in pairs.iterrows(): period_df = split_period_to_months(row['Login'], row['Logout']) period_df['ID'] = id_ result_list.append(period_df)
4. 汇总结果并整理格式
合并所有拆分后的时段数据,按ID和Month汇总时长,最后按时间顺序排序:
final_result = pd.concat(result_list).groupby(['ID', 'Month'], as_index=False)['TimeInDays'].sum() # 按月份时间顺序排序(避免字母排序) final_result['Month_num'] = pd.to_datetime(final_result['Month'], format='%B').dt.month final_result = final_result.sort_values(['ID', 'Month_num']).drop('Month_num', axis=1).reset_index(drop=True) print(final_result)
运行后即可得到目标格式的DataFrame。
内容的提问来源于stack exchange,提问作者question12
相关产品推荐
相关产品推荐

