数据挖掘在轨迹信息上的应用实验

文章目录

    • 1. 实验概览
    • 2. 数据集下载
    • 3. 数据预处理
      • 3.1 异常点去除
      • 3.2 停留点检测与环绕点检测
      • 3.3 轨迹分段
    • 4. 基于轨迹信息的数据挖掘
      • 4.1 路口检测
        • 4.1.1 地图分割与轨迹点速度计算
      • 4.2 偏好学习

通常,我们将一个连续的GPS信号点序列称为一个轨迹(Trajectory),在拥有GPS数据轨迹的情况下,我们能通过这些数据信息挖掘出哪些有效信息是数据挖掘在轨迹信息上的重要研究内容。在该实验中我们使用UCI上公开数据集,利用该轨迹数据集尝试挖掘其中的隐藏信息,在信息挖掘之前,我们需要对原始数据信息进行数据预处理,以保证算法拥有较为优质的输入数据。

1. 实验概览

通常,我们将一个连续的GPS信号点序列称为一个轨迹(Trajectory),在拥有GPS数据轨迹的情况下,我们能通过这些数据信息挖掘出哪些有效信息是数据挖掘在轨迹信息上的重要研究内容。在该实验中我们使用UCI上公开数据集,利用该轨迹数据集尝试挖掘其中的隐藏信息,在信息挖掘之前,我们需要对原始数据信息进行数据预处理,以保证算法拥有较为优质的输入数据,因此整个实验一共分为以下几个步骤:

  • 下载轨迹数据集
  • 对轨迹数据集进行数据预处理
  • 相关信息挖掘

接下来,我们按照该顺序进行依次讲解。

2. 数据集下载

本次实验我们选用UCI上的公开数据集(链接),数据集中共包括两个文件:go_track_tracks.csv 和 go_track_trackpoints.csv,两个文件内容分别如下所示:

可以分析出,go_track_tracks.csv 文件中存放的是每一条 trajectory 的全局信息,例如该条 trajectory 的 id、该条 trajectory 是属于车辆的轨迹还是公共汽车的轨迹、平均速度等(具体细节参考前文UCI链接);而与之对应的,go_track_trackpoints.csv 文件中存放的是每一条 trajectory 中每一个轨迹点的记录信息,例如经纬度、时间戳等。

我们对轨迹数据进行解析,利用 OSMNX 将数据集中的轨迹做可视化,这里挑出其中一个轨迹,可视化结果如下:

通过可视化可以看出,原始的轨迹信息十分杂乱,甚至会出现一些因为GPS设备误差而生成的不合理轨迹点。如上图中所示,可以看到一条轨迹中参杂了一个偏离非常远的轨迹点,使得整个轨迹非常突兀,因此在进行数据挖掘前,我们首先需要对这些原始数据集做数据预处理工作。

3. 数据预处理

数据预处理是在进行数据分析之前非常重要的一个步骤,对于轨迹数据的预处理,该实验中一共经历了3个阶段:

  • 异常点去除
  • 停留点与围绕点的检测与去除
  • 轨迹分段

下面,我们就依照这个顺序将数据集中的轨迹数据进行一步步的清洗。

3.1 异常点去除

异常点是指因为GPS设备误差或者其他原因等产生的不合理的一些噪声信号点,识别异常点的一个方法是根据相邻两个点之间的间隔时间与间隔距离计算出行驶速度,将明显不符合实际速度的轨迹点给清除掉,部分代码如下:

    # 遍历计算坐标轨迹中所有相邻点的距离和间隔时间并计算出速度,与最大速度阈值比较,筛选出符合正常速度区间的轨迹点for i in range(1, len(origin_positions)):distance = geodesic(origin_positions[i-1], origin_positions[i]).kmhours_used = get_hours_from_two_time_string(time_list[i-1], time_list[i])speed = max_speed_threshold if hours_used == 0 else distance / hours_usedif speed < max_speed_threshold:result_positions.append(origin_positions[i])result_time_list.append(time_list[i])result = {track_id: {'positions': result_positions, 'time_list': result_time_list, 'mean_speed': mean_speed}}

下图是我们未进行异常点去除和进行了异常点去除之后的对比图,可以看出,经过最大速度值为 150km/h 的条件筛选后,右下角的异常数据点已经被清除掉,轨迹变得比清洗前连续性显得更好。

3.2 停留点检测与环绕点检测

在轨迹数据中,我们需要分析用户在运动过程中在哪些地点进行了停留。“停留” 一共存在两种情况:一种是用户在原地停留,轨迹点间隔很近;另一种是用户会围绕某一点进行徘徊,例如景观点的附近会存在较多环绕点。我们需要分别对这两种类型的点进行检测筛选。

对于原地停留的情况比较容易检测,我们直接判断轨迹点中相邻点之间的距离差即可,但对于 “环绕停留” 的情况,我们需要使用 Stop Point Detection 的相关算法完成检测,论文链接参考这里。

如上图所示,P3点为原地停留的情况,而右侧 P5,P6,P7,P8 四个点为 “环绕停留” 点,红色 Stay Point 2 为这些环绕点的中心点。为了使得整个轨迹更加平滑,我们通常会将使用红色点来代替原轨迹中的环绕点。那么,环绕停留点如何去检测呢?论文中采用了如下方法:

我们定义一个步进距离阈值 distThreh 和一个间隔时间阈值 timeThreh,遍历整个轨迹,判断当后面某个点与当前点的距离超过了距离阈值且时间间隔大于了时间阈值时,这个轨迹片段中的所有点都被判定为围绕停留点。举例来说,假设当前点遍历到了P5,则我们判断 P6,P7,P8 到 P5 的距离都没有超过距离阈值,直到计算到 P9 点时,发现 P9 和 P5 之间的距离超过了预设距离阈值,此时判断 P9 点和 P5 点之间的时间间隔是否大于时间阈值,若间隔时间大于了预设时间阈值,则 P5,P6,P7,P8 四个点均为环绕等待点,使用四个点的中心点作为拟合路径点,填入到原轨迹中去。

具体实现代码如下:

    points_without_around_points = [points_without_stop_points[0]]time_list_without_around_points = [time_list_without_stop_points[0]]i = 0# 遍历所有轨迹点,将点多个点围绕的情况替换成其中心点while i < len(points_without_stop_points):j = i + 1# 从 i+1 开始,一直向后遍历,找到距离大于最小阈值的最近轨迹点while j < len(points_without_stop_points):distance = geodesic(points_without_stop_points[i], points_without_stop_points[j]).km# 若当前点(j点)到i点距离大于预设判断距离,则对该轨迹片段进行类型判断if distance >= min_delta_dist:# 求从i点到最近大于距离阈值点j共消耗的时间delta_time = get_hours(time_list_without_stop_points[i], time_list_without_stop_points[j])# 若时间大于预设停留时间,则代表该轨迹片段为围绕轨迹,替换这些轨迹点为中心围绕点if delta_time > min_delta_time:points_sequence = np.array(points_without_stop_points[i:j+1])centroid = [np.mean(points_sequence[:, 0]), np.mean(points_sequence[:, 1])]# 只有该中心点与之前拟合出的中心点隔的比较远,才将这个新的中心点加入中心点列表中 if len(around_points_centroids) == 0 or get_distance(centroid, around_points_centroids[-1]) > min_centroid_threshold:around_points_centroids.append(centroid)points_without_around_points.append(centroid)time_list_without_around_points.append(time_list_without_stop_points[j])# 若时间小于预设停留时间,则代表该轨迹片段不是围绕轨迹,保留该轨迹段中的所有轨迹点else:points_without_around_points.extend(points_without_stop_points[i+1:j+1])time_list_without_around_points.extend(time_list_without_stop_points[i+1:j+1]) i = jbreakj += 1if j == len(points_without_stop_points):break

下图为算法执行后的效果图,图左为只执行停留点检测的结果,蓝色标记处为存在长时间停留的检测点;图右为使用了围绕停留点检测的结果图,绿色标记为多个围绕点拟合出的中心标记点,明显可以看出,使用拟合点拟合围绕停留点后,整个轨迹看起来要简洁明了许多。

3.3 轨迹分段

轨迹分段是数据预处理中比较重要的一个步骤,从前两章可以看出,一个完整的轨迹大多时候是比较混乱的。包含自相交、重复行走和突然变向等情况,类似的情况会使得我们在做轨迹数据可视化的时候,轨迹显得混乱不堪,并不利于我们做数据分析。因此,我们需要将一个完整轨迹按照某种规律切分为多个不同的轨迹段,便于我们下一步的分析。

在轨迹分段中,我们通常选用 “时间” 和 “转弯角” 这两个因素作为切割因素,若一个轨迹段中出现 “急转弯” 、 “时间间隔较久” 或是 “空间间隔过大” 的这三种情况,我们都将其切分为一个独立的子轨迹段。下图是我们进行轨迹分段后的结果,图左为未进行数据分段的可视化效果图,图右为执行数据分段后的效果图,可以看出,地图左半部分的区域在未执行数据分段之前较为较混乱,执行分段后不再出现自相交的情况。

数据分段的部分代码如下:

    for i in range(len(origin_positions)):# 若该 segment 中轨迹点数目还不足2个,则填满2个后再计算if len(temp_segment) < 2:# 若新点和旧点之间的距离大于分割距离,则把旧点给弹出删掉if len(temp_segment) == 1 and geodesic(temp_segment[-1], origin_positions[i]).km > segment_distance:temp_segment.pop(0)temp_time_list.pop(0)temp_segment.append(origin_positions[i])temp_time_list.append(time_list[i])continue# 求该 segment 中最后两个点形成的 headingrelative_pos = Utils.get_relative_pos(temp_segment[-2], temp_segment[-1])temp_heading, _ = Utils.transfer2polar(relative_pos[0], relative_pos[1])# 求新点与上一个点形成的 heading 以及从上一点到新点耗费的时间new_relative_pos = Utils.get_relative_pos(temp_segment[-1], origin_positions[i])new_heading, _ = Utils.transfer2polar(new_relative_pos[0], new_relative_pos[1])time_used = get_hours_from_two_time_string(temp_time_list[-1], time_list[i])distance = geodesic(temp_segment[-1], origin_positions[i]).km# 如果转向超过阈值或等待时间超过阈值,则划分为新的一段 segmentif abs(new_heading - temp_heading) > math.radians(segment_angle) or time_used > segment_time or distance > segment_distance:segments.append(temp_segment)segments_time.append(temp_time_list)temp_segment = [origin_positions[i]]temp_time_list = [time_list[i]]# 否则,将该点加入到当前轨迹段中else:temp_segment.append(origin_positions[i])temp_time_list.append(time_list[i])

4. 基于轨迹信息的数据挖掘

至此,我们的数据预处理工作就暂告一个段落,接下来我们就可以在现有数据集上尝试进行相关信息的数据挖掘尝试了。在该实验中,我们主要从路口检测和偏好学习两方面进行入手,接下来我们分别对两个实验做出相应的介绍。

4.1 路口检测

路口检测是指,利用现有用户行径数据来判断哪些位置可能存在路口。路口检测通常可以用于地图的实时更新,当挖掘出的路口与地图数据不匹配时,可以帮助我们快速的发现一些现实世界的变更信息(如某个地区新修建了一个路口等)。通常在路口的时候,汽车会存在转弯的行为,因此路口处的速度方向应该比普通直行道路上的速度方向更加丰富。我们考虑利用聚类算法,将各个区域的点按照速度方向进行聚类,类别比较丰富的区域更有可能存在路口。

4.1.1 地图分割与轨迹点速度计算

首先,我们按照 100mx100m 的正方形对地图进行分割,并将每一个轨迹点分类到其对应的格子中。如下所示,为验证轨迹点归类算法的正确性,我们对每一个格子随机生成一种颜色,同一个格子中的轨迹点使用相同颜色进行绘制:

在确认归类算法无误后,我们将整个地图中的点连同其速度矢量一起绘制到地图上,线段方向代表速度方向,线段长短代表速度大小:

基于此,我们依照速度的方向和大小,使用 DBSCAN 算法对每个网格中的轨迹点进行聚类。DBSCAN 的好处在于不用人为定义类别个数,同时,GPS 的噪声也能正好被 DBSCAN 算法给融合。我们对同一个网格下,不同类别的路径点使用不同颜色进行区分,结果如下所示:

值得一提的是,在我们选择聚类时,需要先选择聚类的指标,也就是说我们需要使用哪些特征对轨迹点进行聚类。我们挑选出了3种待选的方案:

  1. 使用速度的原始 Vx,Vy
  2. 将速度转换为方向角 r
  3. 将速度转换为极坐标系,即方向角 r 和速度标量 d(由于r,d数量级相差较大,因此需要归一化)

为了验证这3个指标哪一个更为合理,我们挑选较有代表性的几个地图格,并分别对这几个地图格使用上述三种指标进行可视化分析。我们首先选择一个可能存在路口的地图格,使用该地图格中的轨迹点进行3种不同指标的聚类,结果如图所示。

图中第一列、第二列、第三列分别为速度原始值、速度方向角、速度极坐标(归一化后)的数据分布图,第一行和第二行分别代表各指标原始数据分布图和数据聚类后的结果图。可以看出,在地图格当中我们可以看到轨迹点应该大致被分为3类(从左到右、从右到左、从上到下),而第一列(使用原始速度)和第二列(速度方向角)最后的聚类结果也在3类,因此比较符合真实结果。但第三列(使用方向角和速度值)最后归一化出了5类,不是很合理。因此在该次实验中,我们选择速度原始值或速度方向角指标更为合理。

随即,我们选择一个非路口地图格,但该格中存在多种不同速度方向的轨迹点,我们对地图格中的轨迹点进行3种不同指标的聚类,并展示结果。

从地图格中,我们可以看出速度应被分为两类(从下到上、从上到下)。对比前两列聚类结果,按照速度原始值聚类结果为3类,按照方向角聚类结果为4类(-1类代表噪声类)。因此我们可以发现,再这种情况下,使用速度原始值分类可以更加贴近真实结果,如果只考虑方向角而步考虑速度大小可能会使得聚类结果偏多。对于第三列结果,可以看到虽然聚类结果被分类为了2类,但其实是噪声类+有效类,实际只被聚出了一类,因此我们发现在两种实验场景下,使用极坐标法(归一化)都不具备较好的效果。

最后,我们进行潜在路口的筛选。我们筛选出所有网格中聚类数目大于 3 的网格(DBSCAN 中会将异常类标志为 -1 类别),将这些网格视为路口可能出现的潜在单元格,并在地图中利用特殊矩形框标记识别出,结果如下所示:

我们挑选出几个潜在网格查看,这些潜在网格中并不是所有网格的判断都是正确的。由于缺乏数据,某些路口未能被正常识别出;此外,由于依赖速度转向做聚类结果,某些双行道同样也有可能被判断为是路口网格。因此,使用聚类方法只是为我们提供了哪些网格可能是包含路口的潜在网格,具体是否确实包含路口还需要在预测结果的基础上进一步的进行判断。

4.2 偏好学习

(Work In Process)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290303.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Avalonia跨平台入门第二十三篇之滚动字幕

在前面分享的几篇中咱已经玩耍了Popup、ListBox多选、Grid动态分、RadioButton模板、控件的拖放效果、控件的置顶和置底、控件的锁定、自定义Window样式、动画效果、Expander控件、ListBox折叠列表、聊天窗口、ListBox图片消息、窗口抖动、语音发送、语音播放、语音播放问题、玩…

oracle dba 手动创建数据实例

2019独角兽企业重金招聘Python工程师标准>>> 1.手动建库大致步骤 设置环境变量.bash_profile创建目录结构创建参数文件(位置:$ORACLE_HOME/dbs)生成密码文件执行建库脚本创建数据字典其他设置2.DBCA 脚本创建 2.1设置系统环境变量 ORACLE_HOME/app/oracle/11g/11.2.…

asp 强制转换浮点数值_C/C++中浮点数的编码存储

浮点数也称做实型数据(实数)&#xff0c;形式上就是数学中的小数。浮点型数据有两种表达方式&#xff1a; 一种是用数字和小数点表示的&#xff0c;如123.456&#xff1b; 另一种是用指数方式表示&#xff0c;如1.2e-6 或1.2E-6(1.2*10-6)。在计算机中实数是如何存储的呢&#…

PaddleNLP实战——信息抽取(InfoExtraction)

[ 文章目录 ]1. 信息抽取任务是什么&#xff1f;2. 基于PaddleNLP的信息抽取任务2.1 训练任务概览2.2 Predicate列表2.3 SPO列表2.4 代码解析1. 信息抽取任务是什么&#xff1f; 在NLP任务中&#xff0c;通常当我们拿到一段文本时&#xff0c;我们希望机器去理解这段文本描述的…

ThinkPad X220i 刷白名单BIOS,改装第三方无线网卡

ThinkPad X220i自带的网卡是REALTEK RTL8188CE&#xff0c;这张卡在Mac下目前是无解的.国外网站有该卡liunx、unix内核的驱动&#xff0c;但还是没有高人编译出来. 不等了,这卡没戏.正好手边有一台Dell E6400,E6400的无线网卡是DELL Wireless 1397 WLAN Mini-Card,具体型号是&a…

C# 离线人脸识别 ArcSoft

人脸识别&比对发展到今天&#xff0c;已经是一个非常成熟的技术了&#xff0c;而且应用在生活的方方面面&#xff0c;比如手机、车站、天网等。虹软人脸识别服务是免费的。最重要的是它还支持离线识别&#xff0c;并且提供Android、iOS、C、C#版SDK&#xff0c;现在已经升级…

【mongoDB运维篇③】replication set复制集

介绍 replicattion set 多台服务器维护相同的数据副本,提高服务器的可用性,总结下来有以下好处: 数据备份与恢复读写分离MongoDB 复制集的结构以及基本概念 正如上图所示&#xff0c;MongoDB 复制集的架构中&#xff0c;主要分为两部分&#xff1a;主节点&#xff08;Primary&a…

c++ long 转 short_C精品编程之——C语言的数据类型、运算符、表达式,精品课程...

在前边的文章分享中&#xff0c;我们已经看到程序中使用的各种变量都应预先加以说明&#xff0c;即先说明&#xff0c;后使用。对变量的说明可以包括三个方面&#xff1a;数据类型存储类型作用域在本课中&#xff0c;我们只介绍数据类型说明。其它说明在以后各章中陆续介绍。所…

李宏毅Reinforcement Learning强化学习入门笔记

文章目录Concepts in Reinforcement LearningDifficulties in RLA3C Method Brief IntroductionPolicy-based Approach - Learn an Actor (Policy Gradient Method)1. Decide Function of Actor Model (NN? ...)2. Decide Goodness of this Function3. Choose the best functi…

《BI项目笔记》数据源视图设置

原文:《BI项目笔记》数据源视图设置目的数据源视图是物理源数据库和分析维度与多维数据集之间的逻辑数据模型。在创建数据源视图时&#xff0c;需要在源数据库中指定包含创建维度和多维数据集所需要的数据表格和视图。BIDS与数据库连接&#xff0c;读取表格和视图定义&#xff…

201521123070 《JAVA程序设计》第13周学习总结

1. 本章学习总结 以你喜欢的方式&#xff08;思维导图、OneNote或其他&#xff09;归纳总结多网络相关内容。 2. 书面作业 Q1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn&#xff0c;分析返回结果有何不同&#xff1f;为什么会有这样的不同&#xff1f; 1.2 t…

.NET 7 预览版2 的亮点之 NativeAOT 回顾

.NET 中备受追捧和期待已久的功能NativeAOT终于出现在本周的.NET 7 预览版2中&#xff0c;该项目的工作仍在继续&#xff0c;该版本将 NativeAOT 从实验性的 dotnet/runtimelab repo 中移出合并进入稳定的运行时库 dotnet/runtime repo&#xff0c;但尚未在 dotnet SDK 中添加足…

c语言十佳运动员有奖评选系统_2019年沃德十佳内饰解读

​2019年沃德十佳内饰解读​mp.weixin.qq.com在这个世界上&#xff0c;要判定一件事物的成功与否并不容易&#xff0c;仅靠主观判断远远不够&#xff0c;而是需要能够进行量化判断的标准和成果。正如运动员需要金牌和冠军积淀&#xff0c;导演和演员需要奖项傍身一样&#xff0…

Mybatis——返回类型为 集合嵌套集合 应该如何处理

2019独角兽企业重金招聘Python工程师标准>>> 最近在练习时 遇到了类似于 企鹅里的好友分组功能&#xff0c;使用的持久层框架是mybatis 第一次处理这种关系 记录一下 备忘。。 首先是表结构&#xff1a; <user_group > 好友分组 、 <t_group> 用户与好友…

为什么用 windbg 看 !address 显示出的Free是128T 大小?

总是被朋友问&#xff0c;用 !address -summary 显示出上面的 Free ≈ 128T 到底是什么意思&#xff1f;我的空闲内存不可能有这么大,不管怎么说&#xff0c;先上命令。0:009> !address -summary--- Usage Summary ---------------- RgnCount ----------- Total Size ------…

DeepMind 的马尔可夫决策过程(MDP)课堂笔记

DeepMind Teaching by David Silver 视频课程链接&#xff08;Youtube资源&#xff0c;需梯子&#xff09;&#xff1a;https://youtu.be/lfHX2hHRMVQ 文章目录DeepMind Teaching by David Silver1. 马尔可夫过程&#xff08;Markov Processes&#xff09;2. 马尔可夫回报过程…

深入Java集合学习系列:ConcurrentHashMap之实现细节

http://www.iteye.com/topic/344876 ConcurrentHashMap是Java 5中支持高并发、高吞吐量的线程安全HashMap实现。在这之前我对ConcurrentHashMap只有一些肤浅的理解&#xff0c;仅知道它采用了多个锁&#xff0c;大概也足够了。但是在经过一次惨痛的面试经历之后&#xff0c;我觉…

基于小波变换的信号降噪处理及仿真研究_信号处理方法推荐--1(转载自用,侵删)...

综述作者&#xff1a;aresmiki链接&#xff1a;https://www.zhihu.com/question/23701194/answer/167005497来源&#xff1a;知乎著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。非平稳信号处理应该是现在信号处理技术最新的也是最热的研究方…

js温故而知新11(AJAX)——学习廖雪峰的js教程

Asynchronous JavaScript and XML&#xff0c;意思就是用JavaScript执行异步网络请求。 如果仔细观察一个Form的提交&#xff0c;你就会发现&#xff0c;一旦用户点击“Submit”按钮&#xff0c;表单开始提交&#xff0c;浏览器就会刷新页面&#xff0c;然后在新页面里告诉你操…

最流行的 .NET 开源项目合集

Github 上有很多优秀的 .NET 开源项目&#xff0c;它们很适合用来学习 .NET 、设计模式和架构。nopCommerce https://github.com/nopSolutions/nopCommercestar: 7k ⭐nopCommerce 是最受欢迎最好的开源电子商务购物车解决方案之一&#xff0c;它基于 ASP.NET Core&#xff…