【Matlab】基于改进的 Hausdorf 距离的DBSCAN船舶航迹聚类

【Matlab】基于改进的 Hausdorff 距离的DBSCAN船舶航迹聚类

  • 一、模型简介
    • 1.1问题背景
    • 1.2具体内容
      • AIS数据的预处理
      • 船舶轨迹分割
      • 船舶轨迹相似度度量
      • 船舶轨迹表达方式
      • 船舶轨迹相似度量方法
      • 改进的 Hausdorff 距离
      • 船舶轨迹聚类及轨迹提取
      • 基于改进DBSCAN算法轨迹聚类
      • 船舶典型轨迹的提取
      • 船舶轨迹聚类效果对比
  • 二、代码分享
    • 2.1主函数
    • 2.1 计算H距离
    • 2.2 DBSCAN聚类
    • 2.3提取典型轨迹
    • 2.4 根据聚类结果 进行航迹预测
    • 三、结果展示
      • 3.1DBSCAN聚类结果
      • 3.2 典型航迹提取
      • 3.2 航迹阈值分类
      • 3.2 最佳分类阈值
    • 四、代码分享

一、模型简介

1.1问题背景

作者复现了《基于轨迹聚类的船舶异常行为识别研究_胡智辉》的文章内容,对模型感兴趣的朋友可以下载文章深入研究。本文主要是分享复现过程中的算法实现。

1.2具体内容

本模型通过处理AIS数据得到船舶轨迹,通过计算改进的 Hausdorff 距离,对轨迹进行DNSCAN聚类,得到不同类型的航迹簇。主要包含以下内容

AIS数据的预处理

船舶轨迹分割

船舶轨迹相似度度量

船舶轨迹表达方式

船舶轨迹相似度量方法

改进的 Hausdorff 距离

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

船舶轨迹聚类及轨迹提取

基于改进DBSCAN算法轨迹聚类

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

船舶典型轨迹的提取

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

船舶轨迹聚类效果对比

在这里插入图片描述
在这里插入图片描述

二、代码分享

具体的代码原理比较繁琐,笔者时间精力有限,难以详尽描述,有需要的可以私信咨询。这里就直接分享部分源码

2.1主函数

% clc
% close all
% clear all
% % %%
% % global noisenum
% % % %% 数据路径
% % % path='AIS1246-1.CSV';
% % % %% 计算H距离
% % % [data1,px,tempMapDis,tempMapV,tempMapHeading]=myHuasdoff(path);
% % % Hdist = (tempMapDis + tempMapV + tempMapHeading) / 3;
% % % %% 取距离中的较小值
% % % for i = 1 : size(Hdist,1)
% % %     for j = i + 1 : size(Hdist,2)
% % %         max1 = Hdist(i,j);
% % %         if max1 < Hdist(j,i)
% % %             max1 = Hdist(j,i);
% % %         end
% % %         Hdist(i,j) = max1;
% % %         Hdist(j,i) = max1;
% % %     end
% % % end
% load data.mat
% %% 设置聚类参数
% eps=0.056;
% MinNum=18;
% %% DBscan 聚类
% cluster_label=DBSCAN(Hdist,eps,MinNum);
% %% 计算聚类数
% cluster_num=max(cluster_label);
% %% 计算轨迹平均位置
% meanpos=zeros(length(cluster_label),2);
% for i=1:length(cluster_label)
%     meanpos(i,1)=mean(data1(data1(:,1)==i,2));
%     meanpos(i,2)=mean(data1(data1(:,1)==i,3));
% end
% %% 画图
% % %% plot trace
% figure
% Plottrace(data1,cluster_label)
% title(sprintf(['DBSCAN聚类结果(航迹示意图) \n邻域距离 = ' num2str(eps) ', 最小样本数 = ' num2str(MinNum) '\n航迹类别:' num2str(cluster_num) '类,噪声航迹:' num2str(noisenum) '条']));
% xlabel('经度')
% ylabel('纬度')
% %% plot meanpos
% % figure
% % Plotmeanpos(meanpos, cluster_label);
% % title(sprintf(['DBSCAN聚类结果(航迹平均坐标示意图) \n邻域距离 = ' num2str(eps) ', 最小样本数 = ' num2str(MinNum) '\n航迹类别:' num2str(cluster_num) '类,噪声航迹:' num2str(noisenum) '条']));
% % xlabel('经度')
% % ylabel('维度')
% % 逐类计数典型轨迹
% filename='典型轨迹数据.xlsx';
% DXcolor={'black','magenta'};
% DXindexlist=[15,36];
% Legendslist={'主航道出口船舶典型轨迹','主航道进口船舶典型轨迹'};
% 
% for k=1:cluster_num
%     data_ind=[];
%     temp_trace_ind=find(cluster_label==k);
%     for t=1:length(temp_trace_ind)
%         data_ind1=find(data1(:,1)==temp_trace_ind(t));
%         data_ind=[data_ind;data_ind1];
%     end
%     %     Legendsname = ['第' num2str(k) '类航迹的典型航迹'];
%     Legendsname=Legendslist{k};
%     [DXfinalData{k},DXdatanew{k},DXpx{k},DXfData{k},DXMapDis{k},DXMapV{k},DXMapHeading{k}]=DXGJ(data1(data_ind,:),DXcolor{k},Legendsname,DXindexlist(k));
%     datawriter(filename,DXfData{k},Legendsname)% end
% end
% 
% % %%
% % addpath '识别数据集'
% % filename_train_in1='进口正常行为数据.xlsx';
% % filename_train_in0='进口异常行为数据.xlsx';
% addpath '正常与异常数据'
% filename_train_in1='进口正常轨迹数据.xlsx';
% filename_train_in0='进口异常轨迹数据.xlsx';
% [data_in1,finalData_in1]=makeData(filename_train_in1);
% [data_in0,finalData_in0]=makeData(filename_train_in0);
% stepNum=20;
% DistThre=linspace(1,250,stepNum);
% SogThre=linspace(1,8,stepNum);
% CogThre=linspace(1,8,stepNum);
% %
% % DistThre=1:0.01:250;
% DXTrace=DXfData{2};
% % ACC_P=[];
% % ACC_S=[];
% % ACC_C=[];
% for i=1:stepNum
%     tDistThre=DistThre(i);
%     tSogThre=SogThre(i);
%     tCogThre=CogThre(i);
%     [ACC_P(i),ACC_S(i),ACC_C(i)]=drawErrerRate(finalData_in1,finalData_in0,DXTrace,tDistThre,tSogThre,tCogThre);
% end
% %% 
filename='阈值.xlsx';
data=xlsread(filename);
figure
plot(DistThre,[ACC_P.r],'-gp','DisPlayName','准确率')
hold on
plot(DistThre,1-[ACC_P.r],'-rd','DisPlayName','误警率')
xlabel('位置偏差')
legend
figure
plot(SogThre,[ACC_S.r],'-gp','DisPlayName','准确率')
hold on
plot(SogThre,1-[ACC_S.r],'-rd','DisPlayName','误警率')
xlabel('航速偏差')
legend
figure
plot(CogThre,[ACC_C.r],'-gp','DisPlayName','准确率')
hold on
plot(CogThre,1-[ACC_C.r],'-rd','DisPlayName','误警率')
xlabel('航向偏差')
legend
%% 2类:进口 1类出口
global DistThre SogThre CogThre
DistThre=60;
SogThre=2.8;
CogThre=3.8;
addpath '正常与异常数据'
filename_in='验证进口道船舶异常行为.xlsx';
tracetype=input('请选择要验证的船舶类型:1(出口)/ 2(进口)');
try
DXTrace=DXfData{tracetype};
catch
    disp('输入错误')
    return
end
checkTrace(filename_in,DXTrace);```



2.1 计算H距离

function [data1,px,tempMapDis,tempMapV,tempMapHeading]=myHuasdoff(datapath)
data1 = xlsread(datapath); 
[sy,sx] = size(data1);
tempx = 1;tempy = 1;
global finalData;
finalData{1,1} = data1(1,:);
px(1,1) = 1;
px(1,2) = data1(1,1);
for i = 2 : sy
    if data1(i,1) ~= data1(i - 1,1)
        tempx = tempx + 1;
        px(tempx,1) = tempx;px(tempx,2) = data1(i,1);
        finalData{tempx,1} = data1(i,:);
        tempy = 1;
    else
        tempy = tempy + 1;
        finalData{tempx,tempy} = data1(i,:);
    end
end
global n;
global yy;
xx = size(finalData,1);
yy = size(finalData,2);
n = xx;
tempMapDis = zeros(n,n);
tempMapV = zeros(n,n);
tempMapHeading = zeros(n,n);
%%计算最小值
for i = 1 : xx
    for j = 1 : xx
       ......
    end
end
%%归一化
for i = 1 : n
    for j = 1 : n
... ...
        end
    end
end
disGy = disGy - disMin;
vGy = vGy - vMin;
headingGy = headingGy - headingMin;
for i = 1 : n
    for j = 1 : n
 ......
    end
end

end

2.2 DBSCAN聚类

function [labels, isnoise]=DBSCAN(D,epsilon,MinPts)
    C=0;
    n=size(D,1);
    labels=zeros(n,1);
%     D=pdist2(X,X);
%     D=X;
    visited=false(n,1);
    isnoise=false(n,1);
    for i=1:n
        if ~visited(i)
            visited(i)=true;
            
            Neighbors=RegionQuery(i);
            if numel(Neighbors)<MinPts
                % X(i,:) is NOISE
                isnoise(i)=true;
            else
                C=C+1;
                ExpandCluster(i,Neighbors,C);
            end
            
        end
    
    end
    
    function ExpandCluster(i,Neighbors,C)
        labels(i)=C;
        
        k = 1;
        while true
            j = Neighbors(k);
            
            if ~visited(j)
                visited(j)=true;
                Neighbors2=RegionQuery(j);
                if numel(Neighbors2)>=MinPts
                    Neighbors=[Neighbors Neighbors2];   %#ok
                end
            end
            if labels(j)==0
                labels(j)=C;
            end
            
            k = k + 1;
            if k > numel(Neighbors)
                break;
            end
        end
    end
    
    function Neighbors=RegionQuery(i)
    end

2.3提取典型轨迹

%求同一簇典型轨迹
function [finalData1,data1,px,fData,tempMapDis,tempMapV,tempMapHeading]=DXGJ(data1,DXcolor,DXlegend,DXindex)
% function main()
%%数据预处理
% data1 = xlsread(path); %xls xlsx
%    data1 = csvread('1.csv'); %csv
[sy,sx] = size(data1);
tempx = 1;tempy = 1;
global finalData;
finalData=[];
finalData{1,1} = data1(1,:);
px(1,1) = 1;
px(1,2) = data1(1,1);
for i = 2 : sy
    if data1(i,1) ~= data1(i - 1,1)
        tempx = tempx + 1;
        px(tempx,1) = tempx;px(tempx,2) = data1(i, 1);
        finalData{tempx,1} = data1(i,:);
        tempy = 1;
    else
        tempy = tempy + 1;
        finalData{tempx,tempy} = data1(i,:);
    end
end

finalData1 = finalData;
%画出船舶轨迹线
% for i = 1 : length(data1(:,1)) - 1
%     if data1(i,1) == data1(i + 1,1)
%         line([data1(i,2) data1(i + 1,2)],[data1(i,3) data1(i + 1,3)]);
%         hold on
%     end
% end
% hold on

global a;
a=DXindex;
global xx;
global yy;
xx = size(finalData,1);
yy = size(finalData,2);
tempX = [];
tempY = [];
tempH = [];
tempV = [];

%%计算交点
for k = 1 : yy
    if isempty(finalData{a,k})
        break;
    end
    [t1,t2,t3,t4] = toIntersection(k);
    if t1 == -1
        continue;
    end
    tempX = [tempX,t1];
    tempY = [tempY,t2];
    tempH = [tempH,t3];
    tempV = [tempV,t4];
end
hold on;
plot(tempX,tempY,'Color',DXcolor,'LineWidth',1,'DisPlayName',DXlegend) %典型轨迹的划线
hold on;
fData ={};
for i = 1 : size(tempX,2)
    temp = [tempX(i),tempY(i),tempH(i),tempV(i)];
    fData{1,i} = temp;
    temp = [1,temp];
    finalData{xx + 1,i} = temp;
end
xx = size(finalData,1);
yy = size(finalData,2);
n = xx;
tempMapDis = zeros(1,n - 1);
tempMapV = zeros(1,n - 1);
tempMapHeading = zeros(1,n - 1);

%%计算最小值
for j = 1 : xx - 1
    totalDis = 0;
    totalV = 0;
    totalHeading = 0;
    len = 0;
    for k = 1 : yy
        if isempty(finalData{xx,k})
            break;
        end
        min1 = 999999999;
        minl = -1;
        for l = 1 : yy
            if isempty(finalData{j,l})
                break;
            end
            if min1 > osDis(xx,k,j,l)
                min1 = osDis(xx,k,j,l);
                minl = l;
            end
        end
        [t1,t2,t3] = toMinDis(xx,k,j,minl);
        t2 = abs(t2 - finalData{xx,k}(4));
        t3 = abs(t3 - finalData{xx,k}(5));
        totalDis = totalDis + t1;
        totalHeading = totalHeading + t2;
        totalV = totalV + t3;
        len = len + 1;
    end
    tempMapDis(1,j) = totalDis / len;
    tempMapV(1,j) = totalV / len;
    tempMapHeading(1,j) = totalHeading / len;
end
end

2.4 根据聚类结果 进行航迹预测

function [ACC_P,ACC_S,ACC_C]=drawErrerRate(finalData_in1,finalData_in0,DXTrace,DistThre,SogThre,CogThre)
% DistThre=60;
% SogThre=2.8;
% CogThre=3.8;
% filename_train_in1='进口正常轨迹数据.xlsx';
% filename_train_in0='进口异常轨迹数据.xlsx';
% [data_in1,finalData_in1]=makeData(filename_train_in1);
% [data_in0,finalData_in0]=makeData(filename_train_in0);
% pred_label_in1_P=zeros(length(finalData_in1),1);
% pred_label_in0_P=zeros(length(finalData_in0),1);
% pred_label_in1_S=zeros(length(finalData_in1),1);
% pred_label_in0_S=zeros(length(finalData_in0),1);
% pred_label_in1_C=zeros(length(finalData_in1),1);
% pred_label_in0_C=zeros(length(finalData_in0),1);
TP_P=0;
FP_P=0;
TN_P=0;
FN_P=0;

TP_S=0;
FP_S=0;
TN_S=0;
FN_S=0;

TP_C=0;
FP_C=0;
TN_C=0;
FN_C=0;
for ind=1:size(finalData_in1,1)
    currentTrace=finalData_in1(ind,:);

    % DXTrace=DXfData{t};
    [DevPosition,DevSog,DevCog]=getDev(currentTrace,DXTrace);
        pred_label_in_P=zeros(length(DevPosition),1);
    pred_label_in_S=zeros(length(DevSog),1);
    pred_label_in_C=zeros(length(DevCog),1);
    for node=1:length(DevPosition)
        if DevPosition(node)<DistThre
            pred_label_in_P(node)=1;
        end
        if DevSog(node)<SogThre
            pred_label_in_S(node)=1;
        end
        if DevCog(node)<CogThre
            pred_label_in_C(node)=1;
        end
    end
    %% 找到偏离点
    errerind_P=find(pred_label_in_P==0);
    diff1_P=diff(diff(errerind_P));
    if isempty(find(diff1_P==0))
        TP_P=TP_P+1;
%         max(DevPosition)
    else
        FN_P=FN_P+1;
    end
    %%
    %% 找到偏离点
    errerind_S=find(pred_label_in_S==0);
    diff1_S=diff(diff(errerind_S));
    if isempty(find(diff1_S==0))
        TP_S=TP_S+1;
    else
        FN_S=FN_S+1;
    end
    %%
    %% 找到偏离点
    errerind_C=find(pred_label_in_C==0);
    diff1_C=diff(diff(errerind_C));
    if isempty(find(diff1_C==0))
        TP_C=TP_C+1;
    else
        FN_C=FN_C+1;
    end
end

%%
for ind=1:size(finalData_in0,1)
    currentTrace=finalData_in0(ind,:);

    % DXTrace=DXfData{t};
    [DevPosition,DevSog,DevCog]=getDev(currentTrace,DXTrace);
        pred_label_in_P=zeros(length(DevPosition),1);
    pred_label_in_S=zeros(length(DevSog),1);
    pred_label_in_C=zeros(length(DevCog),1);
    for node=1:length(DevPosition)
        if DevPosition(node)<DistThre
            pred_label_in_P(node)=1;
        end
        if DevSog(node)<SogThre
            pred_label_in_S(node)=1;
        end
        if DevCog(node)<CogThre
            pred_label_in_C(node)=1;
        end
    end
    %% 找到偏离点
    errerind_P=find(pred_label_in_P==0);
    diff1_P=diff(diff(errerind_P));
    if isempty(find(diff1_P==0))
        FP_P=FP_P+1;
    else
        TN_P=TN_P+1;
    end
    %%
    %% 找到偏离点
    errerind_S=find(pred_label_in_S==0);
    diff1_S=diff(diff(errerind_S));
    if isempty(find(diff1_S==0))
        FP_S=FP_S+1;
    else
        TN_S=TN_S+1;
    end
    %%
    %% 找到偏离点
    errerind_C=find(pred_label_in_C==0);
    diff1_C=diff(diff(errerind_C));
    if isempty(find(diff1_C==0))
        FP_C=FP_C+1;
    else
        TN_C=TN_C+1;
    end
end

ACC_P.r=(TP_P+TN_P)/(TP_P+TN_P+FP_P+FN_P);
ACC_S.r=(TP_S+TN_S)/(TP_S+TN_S+FP_S+FN_S);
ACC_C.r=(TP_C+TN_C)/(TP_C+TN_C+FP_C+FN_C);
ACC_P.TP=TP_P;
ACC_P.TN=TN_P;
ACC_P.FP=FP_P;
ACC_P.FN=FN_P;

ACC_S.TP=TP_S;
ACC_S.TN=TN_S;
ACC_S.FP=FP_S;
ACC_S.FN=FN_S;

ACC_C.TP=TP_C;
ACC_C.TN=TN_C;
ACC_C.FP=FP_C;
ACC_C.FN=FN_C;

三、结果展示

本文的过程相对来说比较复杂,结果也比较多,主要将后期可视化的结果进行展示,完整的数据处理过程和相关结果见第四部分代码分享。

3.1DBSCAN聚类结果

DBSCAN<a class=聚类结果" />
在这里插入图片描述

3.2 典型航迹提取

在这里插入图片描述

3.2 航迹阈值分类

在这里插入图片描述

3.2 最佳分类阈值

在这里插入图片描述

四、代码分享

源码链接:C币下载
需要免费分享的关注+点赞+收藏的 私聊领取
完整的项目内容
包含:
模型文件和航迹数据
DBSCAN代码
H距离计算代码
航迹提取代码
基于H距离的阈值分类代码
阈值寻优代码
均可直接运行

可以结合这个案例,学习DBSCAN距离算法和H距离的计算方法,掌握了航迹分类的大致流程,取得了较好的聚类效果,并基于航迹聚类进行航迹偏离预测,经检测准确率较高。
需要学习DBSCAN的朋友可以当作一个应用案例来学习,船舶航迹研究方向的朋友可以通过替换数据和相关模块实现拓展成自己的模型实现

在这里插入图片描述

参考文献
[1]:基于轨迹聚类的船舶异常行为识别研究
胡智辉
[2]:Typical trajectory extraction method for ships based on AIS data
and trajectory clustering
Huaipeng Li∗
Beijing Industry University, Beijing, China


http://www.niftyadmin.cn/n/293695.html

相关文章

求中位数?

文章目录 如何求一个中位数&#xff1f;[295. 数据流的中位数](https://leetcode.cn/problems/find-median-from-data-stream/)常规思路&#xff1a;解决思路&#xff1a; 如何求一个中位数&#xff1f; 如果输入一个数组&#xff0c;让你求中位数&#xff0c;简单的解决方法就…

docker rm rmi操作

1、rm 删除容器&#xff0c;要删除镜像&#xff0c;首先要删除容器 docker rm 295 2、rmi 删除镜像 docker rmi c69 docker rmi nvidia:v1 3、批量操作 # 批量停止容器 docker stop docker ps -a -q # 批量删除容器 docker rm docker ps -a -q # 批量删除镜像 docker rmi …

栈和队列OJ题思路分享之括号匹配(C语言实现)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:刷题分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你刷更多C语言和数据结构的题!   &#x1f51d;&#x1f51d; 栈和队列刷题分享 1. 前言&…

《微服务实战》 第一章 Java线程池技术应用

前言 介绍Java的线程、线程池等操作 1、Java创建线程方式回顾 1.1、继承Thread类(只运行一次) public class ThreadTest extends Thread{Overridepublic void run() {System.out.println(Thread.currentThread().getName());}public static void main(String[] args) {new …

UE4打通UDP接口,实施案例1

最近跟进的一个汽车相关的项目。UE4开发的HMI原型软件&#xff0c;需UDP通信接口打通&#xff0c;之前没碰过UE4&#xff0c;特记录一下实施过程。 1、下载安装ue4。下载前注册Epic Games账号&#xff08;此账号可以用来购买虚幻商城的产品&#xff0c;有素材有游戏。素材有不…

预制菜,巨头们的新赛场

俗话说“民以食为天”&#xff0c;饮食对于大众的重要性自然是无需赘述。然而&#xff0c;随着生活节奏的加快&#xff0c;越来越多年轻人没有时间和精力去烹制菜肴&#xff0c;这也是外卖行业持续火热的重要原因之一。尽管如此&#xff0c;随着消费者健康意识的持续提升&#…

SpringCloud01-微服务、服务拆分、远程调用(java代码发Http)、Eureka注册服务、服务发现、Ribbon负载均衡、IRule负载均衡策略、Nacos注册中心

文章目录 SpringCloud011.认识微服务1.0.学习目标1.1.单体架构1.2.分布式架构1.3 微服务1.3.1 微服务的架构特征&#xff1a;1.3.2 几种微服务技术的对比&#xff1a;1.3.3 企业需求 1.4.SpringCloud1.5.总结 2.服务拆分和远程调用2.1.服务拆分原则2.2.服务拆分示例2.2.1.导入S…

8086CPU汇编环境安装

之前是使用XP虚拟机中的DOS窗口&#xff0c;后来在B站上逛到的视频【《汇编语言》速成指南(全程敲代码)】中介绍了DOSBox这个软件&#xff0c;觉得很好用&#xff0c;使用方式记录在这里。 软件下载好是这样&#xff1a; 一、安装BOX程序 双击exe安装 &#xff0c;默认下一步…