GPS軌跡の外れ値の検出と修正


9

latitude longitude 後処理中に軌跡の外れ値ポイントを検出できるアルゴリズムまたは方法を見つける必要があります。これは、その後修正できます(近傍に基づいて軌跡のパスに戻されます)。

検出して修正したい異常点の種類の例として、次のことを示す画像を添付しました。

青の生データ。

無香料のカルマンフィルターを使用してデータを可能な限り平滑化しようとしましたが、これはより極端な外れ値(生データが青で、平滑化されたデータが赤)では十分に機能しないようです。

青の生データ、赤のUKF平滑化データ。

私のUKFは適切に調整されていない可能性があります(しかし、私はそれが確かであることをかなり確信しています)。

軌道は、歩行者、ランナー、サイクリストの軌道です。人力による動きで、開始や停止はできますが、速度や位置が急激または急激に変化することはありません。

タイミングデータに依存しない(位置データのみに依存する)ソリューションは、非常に便利です(処理されるデータに常にタイミングデータが含まれるとは限らないため)。しかし、私はこの種の解決策が存在する可能性がどれほどありそうもないことを知っているので、私は同様にどんな解決策でも幸せです!

理想的には、ソリューションは異常値を検出し、それを修正して軌道を修正することができます。

緑色の生データを修正しました。


私がふるいにかけたリソース:

回答:


1

河川ネットワークを処理するためのツールの一部として、ネットワーク内の「スパイク」を検索するための品質管理ツールを作成しました。私が川のネットワークを処理するためのツールを使用するように勧めているわけではありませんが、私が行ったことのイメージを示すヘルプファイルを紹介します

コサイン法則を使用して、ポリラインの各ラインセグメント間の連続する角度を特定するコードを開発しました。このアイデアを中心に独自のコードを開発し、ポリラインに沿って歩き、極端な角度を特定することができます。


私はあなたが説明した方法(コサインの法則を使用)を使用し、ポイント間の距離を含めて外れ値をより正確に特定しましたが、それは非常にうまく機能しているようです。ありがとうございました!
JP

8

私が使用するアルゴリズム。

  1. ポイントのユークリッド最小全域木を計算します。

ここに画像の説明を入力してください

  1. このネットワーク上で互いに最も離れている2点を見つける

ここに画像の説明を入力してください

  1. それらの間の最短ルートを見つける:

ここに画像の説明を入力してください

ご覧のように、鋭い曲がり角で角を切るかもしれません。

上記のアルゴリズムのArcGIS python実装があり、networkxモジュールを使用しています。これが重要かどうかを教えてください。スクリプトで回答を更新します

更新:

# Connects points to make polyline. Makes 1 line at a time
# Tool assumes that 1st layer in Table of Conternt is TARGET polyline feature class,
# second layer in TOC is SOURCE point fc.
# If no selection found in SOURCE layer, works on entire dataset

import arcpy, traceback, os, sys
import itertools as itt
from math import sqrt
sys.path.append(r'C:\Users\felix_pertziger\AppData\Roaming\Python\Python27\site-packages')
import networkx as nx
from networkx import dijkstra_path_length

try:
    def showPyMessage():
        arcpy.AddMessage(str(time.ctime()) + " - " + message)
    def CheckLayerLine(infc):
        d=arcpy.Describe(infc)
        theType=d.shapeType
        if theType!="Polyline":
            arcpy.AddWarning("\nTool designed to work with polylines as TARGET!")
            raise NameError, "Wrong input\n"
        return d
    def CheckLayerPoint(infc):
        d=arcpy.Describe(infc)
        theType=d.shapeType
        if theType!="Point":
            arcpy.AddWarning("\nTool designed to work with points as SOURCE!")
            raise NameError, "Wrong input\n"
        return d
    mxd = arcpy.mapping.MapDocument("CURRENT")
    layers = arcpy.mapping.ListLayers(mxd)
    if len(layers)<=1:
        arcpy.AddWarning("\nNot enough layers in the view!")
        raise NameError, "Wrong input\n"
    destLR, sourceLR=layers[0],layers[1]
    a = CheckLayerPoint(sourceLR);d = CheckLayerLine(destLR)

#  copy all points to manageable list
    g=arcpy.Geometry()
    geometryList=arcpy.CopyFeatures_management(sourceLR,g)
    nPoints=len(geometryList)
    arcpy.AddMessage('Computing minimum spanning tree')
    list2connect=[p.firstPoint for p in geometryList]
#  create network    
    p=list(itt.combinations(range(nPoints), 2))
    arcpy.SetProgressor("step", "", 0, len(p),1)
    G=nx.Graph()
    for f,t in p:
        p1=list2connect[f]
        p2=list2connect[t]
        dX=p2.X-p1.X;dY=p2.Y-p1.Y
        lenV=sqrt(dX*dX+dY*dY)
        G.add_edge(f,t,weight=lenV)
        arcpy.SetProgressorPosition()
    arcpy.AddMessage(len(G.edges()))
    mst=nx.minimum_spanning_tree(G)
    del G

#  find remotest pair
    arcpy.AddMessage(len(mst.edges()))
    length0=nx.all_pairs_dijkstra_path_length(mst)
    lMax=0
    for f,t in p:
        lCur=length0[f][t]
        if lCur>lMax:
            lMax=lCur
            best=(f,t)
    gL=nx.dijkstra_path(mst,best[0],best[1])
    del mst
    nPoints=len(gL)
    ordArray=arcpy.Array()
    for i in gL: ordArray.add(list2connect[i])

#  append line to TARGET
    curT = arcpy.da.InsertCursor(destLR,"SHAPE@")
    curT.insertRow((arcpy.Polyline(ordArray),))
    arcpy.RefreshActiveView()
    del curT

except:
    message = "\n*** PYTHON ERRORS *** "; showPyMessage()
    message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
    message = "Python Error Info: " +  str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()            

うーん面白いアプローチ..これを共有してくれてありがとう!実用的な例はきっと大事だと思います!
ニックス2015

1
このアプローチの結果と、入力データをたどるだけで得られる結果との間のある種の区分的比較により、「スパイク」を取り除きながらコーナーを維持するしきい値を設定できる場合があります。これは、いくつかのログから自然に発生する各ポイントに関連付けられた時間情報もある場合に特に役立ちます。
Doug McClean

1
けっこうだ。相互にn時間間隔のノード間にリンクを作成しないことで、スクリプトを変更するのは簡単です。GPSパスではなく、他のものにスクリプトを使用しています。グラフのリンク数を大幅に削減する三角形分割など、他にも改善の方法があります
FelixIP

2
この方法はいくつかのケースで機能しますが、一部の軌道の形状は、この方法を使用することが私のユースケースでは実行できないことを意味します。(たとえば、多くのノードが無視されてジグザグになっているために、軌道がそれ自体で2重に戻ると問題が発生します。同様に、そのセクションの入口/出口が十分に近い場合、軌道のセクション全体を無視できます)。
JP

1
逆方向のパスの@JPは、未加工ラインを1番目に高密度化するのに役立つ可能性があります
FelixIP

4

1つのアイデアは、パスのすべてのセグメントの角度(および長さも)をリストするスクリプトを作成することです。これで、すべてのセグメントの値をその直接の近傍(およびおそらく精度を上げるために2番目の近傍)と比較し、値が指定されたしきい値を超えるすべてのポイントを選択できます。最後に、単純にパスからポイントを削除します。


私は@Hornbyddによって記述された同様の方法を使用しましたが、これは余弦の法則を使用してこれを実現し、角度も決定します。これには、ポイント間の距離も組み込まれます。提案ありがとうございます。
JP

2

Median-5法も一見の価値があります。

各x(またはy)座標は、その周囲の5つのx(またはy)値の中央値(つまり、それ自体、以前の2つの値と後続の2つの値)に設定されます。

例:x3 = median(x1、x2、x3、x4、x5)y3 = median(y1、y2、y3、y4、y5)など

メソッドは迅速で、ストリーミングデータでも簡単に使用できます。



0

データをExcelにインポートしたり、パンダとフラグを使用したり、非現実的な距離のしきい値を超える前のポイントからの距離をすべて削除したりできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.