如何基于位置与时间数据计算设备不同场景的时长占比
问题描述
我拥有两个DataFrame:
import pandas as pd loc_hour = pd.DataFrame({'id': ['a', 'b', 'c',"d"], 'geohash': ["sybewp", "sws101", "sxk9db","sxr4xt"],"log_date":[20210615,20211219,20210108,20210507],"hour":[12,4,5,19]}) loc_grid = pd.DataFrame({'id': ['a', 'b', 'c',"d"], 'geohash': ["sybewp", "sws101", "sxk9db","sxr4xt"], "gridtype":["Home","Other","Work","Home"]})
这两张表包含数千个不同设备的数据。其中loc_hour表存储了一整年中每小时的设备位置信息;loc_grid表记录了设备所在位置的属性(Home代表设备处于家中,Work代表设备处于工作场所)。
我需要计算设备在家庭、工作、其他场景的时长,分别占短期(1个月)和长期(3个月)总时长的百分比,期望输出如下格式的统计表格:
短期(最近1个月)统计
| id | home_percent | work_percent | other_percent | total_day_count | total_hour_count | period |
|---|---|---|---|---|---|---|
| a | 40 | 40 | 20 | 5 | 5 | last 1 month |
| b | 50 | 30 | 20 | 10 | 8 | last 1 month |
| c | 70 | 20 | 10 | 9 | 7 | last 1 month |
| ... | ... | ... | ... | ... | ... | ... |
长期(最近3个月)统计
| id | home_percent | work_percent | other_percent | total_day_count | total_hour_count | period |
|---|---|---|---|---|---|---|
| a | 40 | 40 | 20 | 5 | 5 | last 3 month |
| b | 50 | 30 | 20 | 10 | 8 | last 3 month |
| c | 70 | 20 | 10 | 9 | 7 | last 3 month |
| ... | ... | ... | ... | ... | ... | ... |
解决方案
以下是实现需求的Python代码:
import pandas as pd from datetime import datetime, timedelta # 1. 转换日期格式为datetime类型 loc_hour['log_date'] = pd.to_datetime(loc_hour['log_date'], format='%Y%m%d') # 2. 关联两张表,为每条位置记录添加上场景属性 merged_data = pd.merge(loc_hour, loc_grid, on=['id', 'geohash'], how='left') # 3. 定义统计的时间周期:以数据中最新日期为基准 latest_date = merged_data['log_date'].max() time_periods = [ ('last 1 month', latest_date - timedelta(days=30)), ('last 3 month', latest_date - timedelta(days=90)) ] result_collection = [] for period_name, cutoff_date in time_periods: # 筛选当前周期内的数据 period_data = merged_data[merged_data['log_date'] >= cutoff_date] # 按设备ID分组计算核心指标 group_stats = period_data.groupby('id').agg( total_hour_count=('hour', 'count'), total_day_count=('log_date', lambda x: x.nunique()), home_hours=('gridtype', lambda x: (x == 'Home').sum()), work_hours=('gridtype', lambda x: (x == 'Work').sum()), other_hours=('gridtype', lambda x: (x == 'Other').sum()) ).reset_index() # 计算各场景时长占比,避免除数为0的情况 group_stats['home_percent'] = group_stats.apply( lambda row: round(row['home_hours'] / row['total_hour_count'] * 100, 2) if row['total_hour_count'] > 0 else 0, axis=1 ) group_stats['work_percent'] = group_stats.apply( lambda row: round(row['work_hours'] / row['total_hour_count'] * 100, 2) if row['total_hour_count'] > 0 else 0, axis=1 ) group_stats['other_percent'] = group_stats.apply( lambda row: round(row['other_hours'] / row['total_hour_count'] * 100, 2) if row['total_hour_count'] > 0 else 0, axis=1 ) # 添加周期标识并整理列顺序 group_stats['period'] = period_name formatted_result = group_stats[['id', 'home_percent', 'work_percent', 'other_percent', 'total_day_count', 'total_hour_count', 'period']] result_collection.append(formatted_result) # 合并两个周期的统计结果 final_result = pd.concat(result_collection, ignore_index=True) # 输出最终结果 print(final_result)
代码说明
- 日期转换:将字符串格式的日期转为datetime类型,支持后续时间范围筛选。
- 表关联:通过
id和geohash两个字段关联两张表,让每条位置记录匹配对应的场景属性。 - 周期筛选:以数据中的最新日期为基准,分别截取最近1个月和3个月的数据。
- 分组统计:按设备ID分组,统计总时长、总天数,以及家庭、工作、其他场景的各自时长。
- 占比计算:计算各场景时长占总时长的百分比,处理总时长为0的异常情况。
- 结果整合:将两个周期的统计结果合并,输出符合需求的格式。
内容的提问来源于stack exchange,提问作者hello world
相关产品推荐
相关产品推荐

