指定されたバッファ内の連続したポイントの識別


8

ポイントファイルと動物の1時間ごとの再配置があり、各ポイントの周囲にバッファを配置して、バッファゾーン内にある後続のポイントの数を計算できるようにしたいと考えています。バッファゾーン内にある後続のポイントのみをカウントする、移動ウィンドウのようなポイントファイルに沿って機能する方法を探しています。

たとえば、ポイント10に1500mのバッファーを配置し、ポイント11がバッファー内にあるかどうかを知りたい場合は、ポイント12がバッファー内にあるかどうかなどを知りたいと思います。以前のすべてのポイントがバッファー内にない限り、ポイント52がバッファーゾーン内にあるかどうか知りたくありません。また、ポイント9や8などがバッファ内にあるかどうかも知りたくありません。

ポイントファイルの移動ウィンドウとして機能する「移動ウィンドウポイント分析」と呼ばれる追加のツールボックスを見つけて試しました。これはうまくいきますが、非常に遅く、連続したポイントでなくても、バッファゾーン内にあるすべてのポイントが含まれます。連続したポイントだけを見る方法が見つかりません。

この方法で確認する多くのデータポイントがあるので、出力テーブルを提供する方法が欲しいです。

私はArcGIS 10を使用しています。だれでも提供できる支援があれば、大歓迎です。


ポイントは、(x、y、time)データのリストとして発生した可能性があります。これらのデータを(ArcGISの外部で)前処理して、必要な情報を取得できますか?
whuber

それなら、間違いなく簡単になります。また、距離や方位などを計算するRのAdehabitatLTを使用してデータを処理しています。以下のSylvesterによって提案されたプロセスは理解していますが、どのツールを使用する必要があるのか​​本当にわからないので、どこから始めればよいのかわからなくなります。
James

ああ!すでにを使用しているのでR、それではRベースのソリューションを調べてみましょう。
whuber

AdehabitatLT "sliwinltr"内にスライディングウィンドウ関数がありますが、このインスタンスでの使用方法がわかりません。このように使えるかどうかさえわかりません。
James

回答:


8

点の位置のリストが与えられると(距離の計算が容易になるように、できれば投影座標で)、この問題は5つの簡単な操作で解決できます

  1. 点間距離を計算します。

  2. 各ポイントi、i = 1、2、...について、バッファー半径よりも短い距離(1500など)にあるポイントのインデックスを特定します。

  3. それらのインデックスをi以上に制限します。

  4. ブレークのない最初の連続するインデックスのグループのみを保持します。

  5. そのグループの数を出力します。

ではR、これらのそれぞれが1つの操作に対応しています。このシーケンスを各ポイントに適用するには定義する関数内にほとんどの作業カプセル化すると便利です。

#
# forward(j, xy, r) counts how many contiguous rows in array xy, starting at index j,
#                   are within (Euclidean) distance r of the jth row of xy.
#
forward <- function(j, xy, r) {
  # Steps 1 and 2: compute an array of indexes of points within distance r of point j.
  i <- which(apply(xy, 1, function(x){sum((x-xy[j,])^2) <= r^2}))
  # Step 3: select only the indexes at or after j.
  i <- i[i >= j]
  # Steps 4 and 5: retain only the first consecutive group and count it.
  length(which(i <= (1:length(i) + j)))
}

(この関数のより効率的なバージョンについては、以下を参照してください。)

この関数は、さまざまなポイントリスト(xy)とバッファー距離(r)をパラメーターとして受け入れるのに十分な柔軟性を備えています。

通常、ポイントの場所のファイルを読み取ります(必要に応じて、時間順に並べ替えます)。ここでは、この動作を示すために、サンプルデータをランダムに生成します

# Create sample data
n<-16                                     # Number of points
set.seed(17)                              # For reproducibility
xy <- matrix(rnorm(2*n) + 1:n, n, 2) * 300
#
# Display the track.
plot(xy, xlab="x", ylab="y")
lines(xy, col="Gray")

図

典型的な間隔は300 * Sqrt(2)=約500 です。この関数を配列内のポイントに適用して計算を行いますxy(そして、結果をに戻しxyます。これは、GISへのエクスポートに便利な形式であるためです。 ):

radius <- 1500
z <- sapply(1:n, function(u){forward(u,xy,radius)})
result <- cbind(xy, z)                              # List of points, counts

次に、result配列をさらに分析しRます。これを、ファイルに書き込むか、ファイルに書き込んで、他のソフトウェアにインポートします。 サンプルデータの結果は次のとおりです。

                        z
  [1,]   -4.502615  551.5413 4
  [2,]  576.108979  647.8110 3
  [3,]  830.103893 1087.7863 4
  [4,]  954.819620 1390.0754 3
...
 [15,] 4977.361529 4146.7291 2
 [16,] 4783.446283 4511.9500 1

(カウントにそれらが基づいているポイントが含まれるため、各カウントは1以上でなければなりません。)


何千ものポイントがある場合、この方法は非効率的です。不要なポイント間距離を計算しすぎます。ただし、作業をforward関数内にカプセル化しているため、非効率は簡単に修正できます。 以下は、数百以上のポイントが関係している場合によりよく機能するバージョンです

forward <- function(j, xy, r) {
   n <- dim(xy)[1]     # Limit the search to the number of points in xy
   r2 <- r^2           # Pre-compute the squared distance threshold
   z <- xy[j,]         # Pre-fetch the base point coordinates
   i <- j+1            # Initialize an index into xy (just past point j)

   # Advance i while point i remains within distance r of point j.
   while(i <= n && sum((xy[i,]-z)^2) <= r2) i <- i+1

   # Return the count (including point j).
   i-j
}

これをテストするために、以前と同じようにランダムなポイントを作成しましたが、2つのパラメーターn(ポイントの数)とそれらの標準偏差(上記の300としてハードコード化)を変化させました。標準偏差は、各バッファー内の平均ポイント数を決定します(以下の表の「平均」)。この数が多いほど、このアルゴリズムの実行に時間がかかります。(より高度なアルゴリズムを使用すると、ランタイムは各バッファーにあるポイントの数にそれほど依存しません。)次に、いくつかのタイミングを示します。

 Time (sec)    n    SD  Average  Distances checked per minute
 1.30       10^3     3  291      13.4 million
 1.72       10^4    30   35.7    12.5
 2.50       10^5   300    3.79    9.1
16.4        10^6  3000    1.04    3.8

これは完璧なソリューションのように見えます。ただし、コードは「z <-sapply(1:n)、function(u){forward(u、xy、radius)})」から実行されません。「z <-sapplyの「予期しない '、」 (1:n)は、」私はカンマを削除した場合、それはその後、言う:エラー:予期しない『機能』 『Z < - sapply(1:n)の機能を』任意のアイデアは、なぜこれがあるかもしれないので、?
ジェームズ

ごめんなさい; そこにタイプミスがあります:余分な ")"を削除します。(私はこのコードを最後に簡略化しました。認めるよりも何度もテストされています!)
whuber

1
それは素晴らしい、それは今実行されています。データをxyとして読み込んだだけで、機能することを簡単に確認できます。おっしゃったように、実行には少し時間がかかりますが、すべて正しく実行されたようです。いくつかのGISマップを手動で再確認しますが、今のところ問題はありません。これを解決してくれてありがとう、GISとRの両方で学ぶことに非常に熱心で、急な学習曲線にいます。
ジェームズ

1
返信を編集して、スケーラビリティが大幅に改善されたソリューションを提供しました。今では何百万ものポイントを含むパスを処理することができます。
whuber

1
未使用のポイントツーポイントの場所が多すぎて処理時間を延長していると言うので、元のコードを2000エントリのポイントファイルで実行しました。上記の編集はきちんとした解決策のように見え、私は同じデータでこれを試して、それがどれほど高速かを確認します。関数の作成と編集にご協力いただきありがとうございます。
ジェームズ

1

あなたの最善の策は、ArcPyを使用して小さなルーチンをスクリプト化することだと思います。私はこの疑似コードのようなものを作成します:

Select all points sorted by location-id    
Iterate for each point:
    Select points by location using a distance (no need to create buffer geometry)
    Sort points by location-id
    Set a variable to the value of your reference id
    consecutive-counter = 0
        Iterate your selection:
            Is the location-id of the first (or next) point equal to variable + 1?
            if 'yes' increment consecutive-counter by 1
            Repeat until 'no'

情報をどのように処理したいのかわかりませんが、テーブルにフィールドを作成し、連続するポイントの数で更新することができると思います(その場合、最初にフィールドを追加します)。

フィーチャレイヤーを作成することをお勧めします(データベーステーブルビューのようですが、Arcのフィーチャ用です)。元のデータから2つを作成し、最初のセットで更新カーソルを開いて、全体的な並べ替えを指定します(ESRIは完全なSQLクエリを尊重しないため)。2番目のものを使用して場所から選択し、結果の選択セットで検索カーソルを開きます。

[ジェームズの要求に応じて編集] モデルビルダーを使用して大まかに説明します。これまでにモデルビルダーを使用したことがない場合は、arcToolboxを右クリックするだけで済みます。「ツールボックスを追加」を選択します。新しいツールボックスを右クリックし、「新規->モデル」をクリックします。新しいモデルウィンドウを作成したら、必要なツールとデータをウィンドウにドラッグアンドドロップし、それらを視覚的にリンクします(小さな矢印ツールを使用)。できる限り(ここではカーソルを追加できません)完了したら、モデルビルダーの[ファイル]メニューのオプションを使用してPythonにエクスポートします。これでほとんどの方法が得られます。これは自動生成されたコードなので、少し厄介ですが機能します。次に、上記の回答のリンクを使用して、カーソルを理解して追加します。

Pythonを初めて使用する場合は、コードを書くことに怯えないでください。Pythonは、結果をすばやく得るための非常に簡単なスクリプト言語です。Esriにもいくつかのガイダンスがあります。

コードに行き詰まった場合は、このフォーラムに投稿して、助けを求めてください。助けてくれる人がたくさんいます。警告が1つあります。ESRIの適切なヘルプを使用してください。彼らはバージョン9.xと10の間でPython APIを大幅に変更しました(それぞれarcgisscriptingとarcpy)。したがって、ArcGIS 9.xを使用している場合は、同等のリンクを見つけてください。


これは私がやりたいことのように見えます。ただし、私は現在、ArcGIS内のコードを使用しておらず、単に定義済みのオプションから選択しています。上記の推奨方法をどのように使用/生成し始めますか?出力を新しいテーブルにするか、連続するポイントの数を含むテーブルに追加した新しいフィールドにしたいです。
James

私のメインの投稿の編集を参照してください。
MappaGnosis、2012

JTB、コメントを投稿できるように、この質問の投稿に使用したのと同じアカウントを使用してログオンしてください。(簡単にするために、JTBアカウントとJamesアカウントをマージしました。)
whuber

アカウントの変更について申し訳ありません。元の質問を新しいユーザーとして投稿しましたが、パスワードなどを持っていなかったため、そのアカウントに戻ることができませんでした。そのため、今後(おそらく)使用する別のアカウントJTBを作成しました。シルベスターの提案に従ってモデルビルダーを起動しますが、これまで使用したことがないため、慣れるまでに少し時間がかかり、使用するツールなどを検討するのに少し時間がかかる場合があります。進捗と質問で戻ってきます。おかげで
ジェームズ

シルベスター-私はプロセスを理解していると思いますが、どのツールから始めなければならないのか迷ってしまいます。距離?バッファ?近く?上記のことを行うこの問題に適切なツールがあるかどうかさえわかりません。私は学びたいと思っていますが、最初はとても好きです。
James

1

ArcGISのモデルビルダーを使用して、連続したID値を見つけることができます。モデルをpythonスクリプトとしてエクスポートしました。コードは、連続したID値を持つ新しいshpを生成します。!ID!ベースIDフィールドです。大文字と小文字を一致させるには、point2.shpのパス、名前、IDフィールド名を更新する必要があります。

# Import arcpy module
import arcpy


# Local variables:
point2_shp = "C:\\temp\\point2.shp"
point2_shp__2_ = "C:\\temp\\point2.shp"
point2_shp__4_ = "C:\\temp\\point2.shp"
Freq_dbf__2_ = "C:\\temp\\Freq.dbf"
point2_shp__5_ = "C:\\temp\\point2.shp"
point2__2_ = "C:\\temp\\point2.shp"
point2__4_ = "C:\\temp\\point2.shp"
Freq_dbf = "C:\\temp\\Freq.dbf"
PointConsecutive_shp = "C:\\temp\\PointConsecutive.shp"

# Process: Add Field
arcpy.AddField_management(point2_shp, "AUTOID", "LONG", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field
arcpy.CalculateField_management(point2__2_, "AUTOID", "autoIncrement()", "PYTHON_9.3", "rec=0\\ndef autoIncrement():\\n global rec\\n pStart = 1 #adjust start value, if req'd \\n pInterval = 1 #adjust interval value, if req'd\\n if (rec == 0): \\n  rec = pStart \\n else: \\n  rec = rec + pInterval \\n return rec\\n")

# Process: Add Field (2)
arcpy.AddField_management(point2_shp, "DIFF", "LONG", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field (2)
arcpy.CalculateField_management(point2__4_, "DIFF", "!ID! - !AUTOID!", "PYTHON_9.3", "")

# Process: Frequency
arcpy.Frequency_analysis(point2_shp__2_, Freq_dbf, "DIFF", "")

# Process: Join Field
arcpy.JoinField_management(point2_shp__4_, "DIFF", Freq_dbf__2_, "DIFF", "")

# Process: Select
arcpy.Select_analysis(point2_shp__5_, PointConsecutive_shp, "\"FREQUENCY\" >1")

上記のコードが何をするのか、それが私のクエリにどのように答えるかはわかりません。私は助けに感謝しますが、Pythonやモデルビルダーを使用したことがないので、これはまったく新しいことです。リストされている各プロセスのIDフィールドをデータセットのIDに変更しますか?
ジェームズ

@ James、IDが変更されたかどうかによって異なります。コードを使用するには、上記のコードをコピーして貼り付け、空のtxtファイルに保存します。point.shpの名前とパスに一致するようにコードを更新します。次に、[フィールドの計算(2)]コードセクションのID名を、point.shp IDフィールドと一致するように変更します。txtファイルを保存し、Windowsエクスプローラーでファイルの名前を.py拡張子に変更します。ファイルを右クリックし、python.exeで開いてテストします。
アートワーク

理想的には、このスクリプトは、バッファリングと機能選択を処理するスクリプトツールにプラグインできます。 help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/...
artwork21
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.