web-dev-qa-db-ja.com

互いに「近い」緯度/経度のポイントをグループ化する方法は?

ユーザーが送信した緯度/経度のポイントのデータベースがあり、「近い」ポイントをグループ化しようとしています。 「閉じる」は相対的ですが、今のところは500フィート程度です。

最初は、最初の小数点以下3桁が同じ緯度/経度の行でグループ化できるように見えました(約300x300のボックス。赤道から離れると変化することを理解しています)。

しかし、その方法はかなり欠けているようです。 「近さ」は、小数点以下の各桁が表す距離と大きく異なることはできません。 2つの場所の小数点以下3桁目(または任意)の桁が異なる場合があることを考慮に入れていませんが、その桁が表す距離(33.1239および33.1240)。

私はまた、ポイントAとポイントCが両方ともポイントBに「近い」(ただしお互いにではない)状況について考察しました-それらを一緒にグループ化する必要がありますか?もしそうなら、ポイントDがポイントCに「近い」場合(他のポイントがない場合)に何が起こりますか?グループ化されている場合も同様です。確かに私は望ましい振る舞いを決定する必要がありますが、どちらを実装するのですか?

これをどのように行うことができ、どのような方法/アプローチを使用できるかについて、誰かが私に正しい方向を示すことができますか?

明らかな何かが足りないような気がします。

現在、データはMySQLデータベースであり、PHPアプリケーションによって使用されます。ただし、これを達成するための重要な部分である場合は、他のストレージメソッドを利用できます。ここにあります。

27
Tim Lytle

2点間の距離を決定する方法はいくつかありますが、2次元グラフに点をプロットするには、おそらく ユークリッド距離 が必要です。 (x1, y1)は最初のポイントを表し、(x2, y2)は秒を表し、距離は

d = sqrt( (x2-x1)^2 + (y2-y1)^2 )

グループ化に関しては、ある種の2次元の平均を使用して、物同士がどの程度「近い」かを判断することができます。たとえば、3つのポイントがある場合、(x1, y1)(x2, y2)(x3, y3)、これらの3つのポイントの中心は、単純な平均化によって見つけることができます。

x(mean) = (x1+x2+x3)/3
y(mean) = (y1+y2+y3)/3

次に、それぞれが中心にどれだけ近いかを見て、それが「クラスター」の一部であるかどうかを判断します。


クラスターを定義する方法はいくつかありますが、そのすべてが クラスタリングアルゴリズム のバリアントを使用しています。私は今ラッシュにいるので要約する時間はありませんが、リンクとアルゴリズムをチェックしてください。うまくいけば、他の人々がより詳細を提供できるようになるでしょう。幸運を!

8
eykanal

質問で概説した方法と同様の方法を使用して、おおよその結果セットを取得し、適切な計算を行って、そのおおよそのセットを削り取ります。グリッドサイズ(つまり、座標を四捨五入する量)を正しく選択した場合、グリッドサイズを管理する必要がありますが、少なくとも、実行する作業の量を許容レベルまで減らすことができます。

たとえば、PostgreSQLのearthdistance拡張は、緯度/経度のペアを(x、y、z)デカルト座標に変換し、地球を均一な球体としてモデル化することで機能します。 PostgreSQLには、これらの座標またはその周囲のボックスをRツリーにインデックス付けできるようにする高度なインデックスシステムがありますが、それがなくても有用なものをまとめることができます。

(x、y、z)を3倍にして丸める(つまり、何らかの係数を掛けて整数に切り捨てる)と、3つの整数を連結して、「ボックス名」を生成できます。ポイントがあるグリッド」。

一部のターゲットポイントからX km以内のすべてのポイントを検索する場合は、そのポイントの周りのすべての「ボックス名」を生成します(ターゲットポイントを(x、y、z)トリプルに変換した後も、簡単です)、地球の表面と交差しないすべてのボックスを削除します(トリッカーですが、x^2+y^2+z^2=R^2各コーナーの式でわかります)ターゲットポイントを含むことができるボックスのリストが表示されるので、これらのボックスのいずれかに一致するすべてのポイントを検索すると、追加のポイントも返されます。したがって、最終段階として、ターゲットポイントまでの実際の距離を計算して一部を削除する必要があります(これも、デカルト座標で作業し、ターゲットの大円距離半径を割線距離に変換することで高速化できます)。

いじくり回すと、あまり多くのボックスを検索する必要がないことを確認できますが、同時にあまり多くの余分なポイントを持ち込まないでください。いくつかの異なるグリッド(たとえば、1Km、5Km、25Km、125Kmなどの解像度)で各ポイントにインデックスを付けると便利です。理想的には、1つのボックスだけを検索したい場合、ターゲットの半径がグリッドサイズを超えるとすぐに、ボックスが少なくとも27まで拡大することを覚えておいてください。

この手法を使用して、SQLデータベースで計算を行うのではなく、Luceneを使用して空間インデックスを構築しました。設定には多少手間がかかりますが、インデックスの生成には時間がかかり、非常に大きくなります。 Rツリーを使用してすべての座標を保持する方がはるかに優れたアプローチですが、より多くのカスタムコーディングが必要になります。この手法では、基本的に高速なハッシュテーブルルックアップが必要なだけです(したがって、最近激怒し、SQLデータベースでも使用できるはずです)。

7
araqnid

多分やり過ぎかもしれませんが、私には クラスタリングの問題 :距離 measure が2つの要素の類似度の計算方法を決定するようです。それほど単純ではない解決策が必要な場合は、 データマイニング:実用的な機械学習のツールとテクニック を試して、 Weka または Orange を使用してください。

5
Roberto Russo

緯度と経度を考慮している場合、リアルタイムデータで考慮すべきいくつかの要素があります。河川や湖などの障害物や、橋やトンネルなどの施設です。それらを単純にグループ化することはできません。単純なアルゴリズムをkとして使用すると、それらをグループ化できなくなります。空間クラスタリング手法はパーティション分割CLARANS手法にすべきだと思います。

3
Deepak Upreti

私がそれに取り組むなら、私はグリッドから始めます。各ポイントをグリッド上の正方形に配置します。密集しているグリッドを探します。隣接するグリッドが入力されていない場合は、まともなグループがあります。

隣接する密集したグリッドがある場合は、常に各グリッドの中心に円をドロップし、円の面積と(円内のポイント数*調整可能な重み)を最適化できます。完璧ではありませんが、簡単です。より良いグループ化は、はるかに複雑な最適化問題です。

2
patros