基于Geolife GPS轨迹数据集的用户指定时段出行时长计算方法
Geolife轨迹数据集出行时长统计实现方案
数据集说明
Geolife是记录用户移动过程的GPS轨迹数据集。本次分析基于Sina Dabiri提供的预处理版本,处理后的数据覆盖69名可用用户的GPS日志,构建为标准pandas DataFrame结构。
样例数据说明
本次选取3名用户的少量数据片段用于逻辑演示:
import pandas as pd data = {'user': [10,10,10,10,10,10,10,10,21,21,21,54,54,54,54,54,54,54,54,54], 'lat': [39.921683,39.921583,39.92156,39.13622,39.136233,39.136241,39.136246,39.136251,42.171678,42.172055, 42.172243,39.16008333,39.15823333,39.1569,39.156,39.15403333,39.15346667,39.15273333,39.14811667,39.14753333], 'lon': [116.472342,116.472315,116.47229,117.218033,117.218046,117.218066,117.218166,117.218186,123.676778,123.677365, 123.677657,117.1994167,117.2002333,117.2007667,117.2012167,117.202,117.20225,117.20255,117.2043167,117.2045833], 'date': ['2009-03-21 13:30:35','2009-03-21 13:33:38','2009-03-21 13:34:40','2009-03-21 15:30:12','2009-03-21 15:32:35', '2009-03-21 15:38:36','2009-03-21 15:44:42','2009-03-21 15:48:43','2007-04-30 16:00:20', '2007-04-30 16:05:22', '2007-04-30 16:08:23','2007-04-30 11:47:38','2007-04-30 11:48:07','2007-04-30 11:48:27','2007-04-30 12:04:39', '2007-04-30 12:04:07','2007-04-30 12:04:32','2007-04-30 12:19:41','2007-04-30 12:20:08','2007-04-30 12:20:21'] }
对应生成的DataFrame结构如下:
df = pd.DataFrame(data) df
输出结果:
user lat lon date 0 10 39.921683 116.472342 2009-03-21 13:30:35 1 10 39.921583 116.472315 2009-03-21 13:33:38 2 10 39.921560 116.472290 2009-03-21 13:34:40 3 10 39.136220 117.218033 2009-03-21 15:30:12 4 10 39.136233 117.218046 2009-03-21 15:32:35 5 10 39.136241 117.218066 2009-03-21 15:38:36 6 10 39.136246 117.218166 2009-03-21 15:44:42 7 10 39.136251 117.218186 2009-03-21 15:48:43 8 21 42.171678 123.676778 2007-04-30 16:00:20 9 21 42.172055 123.677365 2007-04-30 16:05:22 10 21 42.172243 123.677657 2007-04-30 16:08:23 11 54 39.160083 117.199417 2007-04-30 11:47:38 12 54 39.158233 117.200233 2007-04-30 11:48:07 13 54 39.156900 117.200767 2007-04-30 11:48:27 14 54 39.156000 117.201217 2007-04-30 12:04:39 15 54 39.154033 117.202000 2007-04-30 12:04:07 16 54 39.153467 117.202250 2007-04-30 12:04:32 17 54 39.152733 117.202550 2007-04-30 12:19:41 18 54 39.148117 117.204317 2007-04-30 12:20:08 19 54 39.147533 117.204583 2007-04-30 12:20:21
统计规则说明
- 按用户维度对GPS记录按时间升序排序
- 同一用户相邻两条GPS记录时间间隔超过30分钟时,判定间隔前后为两段独立行程
- 单段行程时长 = 该段最后一条记录时间 - 该段首条记录时间
- 指定时间范围内所有用户所有行程的时长总和,即为该时段总出行时长
统计示例
- 2009年3月总出行时长:该月仅用户10有出行记录,2009-03-21的记录中13:34:40与下一条15:30:12间隔超过30分钟,判定为2段独立行程,第一段时长约5分钟,第二段约19分钟,总时长为24分钟。
- 2007年4月总出行时长:该月用户21、54同日有出行记录,用户21行程时长约8分钟;用户54的记录中相邻最大间隔不足30分钟,判定为单段行程,时长约33分钟,总时长为41分钟。
- 需支持任意自定义时间范围(如2008年2月至2009年3月)的出行时长统计。
具体实现方案
实现思路
- 数据预处理:将时间字段转为datetime格式,方便时间差计算
- 范围过滤:按传入的起止时间,只保留统计区间内的GPS记录
- 排序:按用户分组,组内记录按时间升序排列
- 行程切分:计算同一用户相邻记录的时间差,时间差超过30分钟的位置标记为新行程起点
- 时长计算:为每条记录分配所属行程ID,按「用户+行程ID」分组计算每段行程的时长
- 结果汇总:累加所有符合条件的行程时长,得到指定时间段的总出行时长
完整实现代码
import pandas as pd def calc_total_travel_time(df: pd.DataFrame, start_time: str, end_time: str, gap_threshold: int = 30) -> float: """ 统计指定时间范围内的用户总出行时长 :param df: 原始GPS轨迹DataFrame,需包含user、date字段 :param start_time: 统计开始时间,支持'YYYY-MM-DD'或'YYYY-MM-DD HH:MM:SS'格式 :param end_time: 统计结束时间,格式同上 :param gap_threshold: 行程切分的时间间隔阈值,单位分钟,默认30分钟 :return: 总出行时长,单位分钟,保留2位小数 """ # 避免修改原始数据 df = df.copy() # 时间格式转换 df['date'] = pd.to_datetime(df['date']) start = pd.to_datetime(start_time) end = pd.to_datetime(end_time) # 过滤统计时间范围内的数据 df = df[(df['date'] >= start) & (df['date'] <= end)].reset_index(drop=True) if df.empty: return 0.0 # 按用户、时间排序 df = df.sort_values(by=['user', 'date']).reset_index(drop=True) # 计算同用户相邻记录的时间差,单位分钟 df['time_gap'] = df.groupby('user')['date'].diff().dt.total_seconds() / 60 # 标记新行程起点:用户第一条记录、或与上一条记录间隔超过阈值 df['is_new_trip'] = (df['time_gap'].isna()) | (df['time_gap'] > gap_threshold) # 生成每个用户内部的行程唯一ID df['trip_id'] = df.groupby('user')['is_new_trip'].cumsum() # 生成全局唯一行程ID df['global_trip_id'] = df['user'].astype(str) + '_' + df['trip_id'].astype(str) # 计算每段行程的起止时间和时长 trip_info = df.groupby('global_trip_id').agg( trip_start=('date', 'min'), trip_end=('date', 'max') ).reset_index() trip_info['duration_min'] = (trip_info['trip_end'] - trip_info['trip_start']).dt.total_seconds() / 60 # 返回总时长 return round(trip_info['duration_min'].sum(), 2) # 样例测试 if __name__ == '__main__': # 加载样例数据 data = {'user': [10,10,10,10,10,10,10,10,21,21,21,54,54,54,54,54,54,54,54,54], 'lat': [39.921683,39.921583,39.92156,39.13622,39.136233,39.136241,39.136246,39.136251,42.171678,42.172055, 42.172243,39.16008333,39.15823333,39.1569,39.156,39.15403333,39.15346667,39.15273333,39.14811667,39.14753333], 'lon': [116.472342,116.472315,116.47229,117.218033,117.218046,117.218066,117.218166,117.218186,123.676778,123.677365, 123.677657,117.1994167,117.2002333,117.2007667,117.2012167,117.202,117.20225,117.20255,117.2043167,117.2045833], 'date': ['2009-03-21 13:30:35','2009-03-21 13:33:38','2009-03-21 13:34:40','2009-03-21 15:30:12','2009-03-21 15:32:35', '2009-03-21 15:38:36','2009-03-21 15:44:42','2009-03-21 15:48:43','2007-04-30 16:00:20', '2007-04-30 16:05:22', '2007-04-30 16:08:23','2007-04-30 11:47:38','2007-04-30 11:48:07','2007-04-30 11:48:27','2007-04-30 12:04:39', '2007-04-30 12:04:07','2007-04-30 12:04:32','2007-04-30 12:19:41','2007-04-30 12:20:08','2007-04-30 12:20:21'] } df = pd.DataFrame(data) # 2009年3月统计 print(f"2009年3月总出行时长:{calc_total_travel_time(df
相关产品推荐
相关产品推荐

