Как сгруппировать объекты по долготе / широте, используя laravel / php - PullRequest
0 голосов
/ 11 сентября 2018

У меня есть группа пользователей. Число пользователей может быть 50 или 2000. У каждого должен быть длинный / лат, полученный из Google Geo api.

Мне нужно запросить их все, и сгруппировать их по близости и определенному количеству. Скажем, количество 12, и у меня в группе 120 пользователей. Я хочу сгруппировать людей по тому, насколько они близки (long / lat) к другим людям. Так что я попадаю с 10 группами людей, которые находятся рядом.

У меня в настоящее время есть настройка API Google Geo Coding и я бы предпочел использовать это.

ТИА.

- Обновление Я уже давно гуглю по этому поводу, и похоже, что я ищу пространственный запрос, который возвращает группы по близости.

Ответы [ 3 ]

0 голосов
/ 14 сентября 2018

Имейте в виду, что эта проблема растет экспоненциально с каждым добавляемым пользователем, так как количество вычислений расстояний связано с квадратом количества пользователей (на самом деле это N*(N-1) расстояний ... так что 2000 пользователей означаютпочти 4 миллиона вычислений расстояния на каждом проходе. Имейте это в виду при выборе необходимых вам ресурсов

Хотите ли вы сгруппировать их по прямому (на самом деле большому кругу) расстоянию или по пешеходной / дорожной дистанции??

Если первое, расстояние по большому кругу может быть аппроксимировано простой математикой, если вы можете допустить небольшой предел погрешности и хотите предположить, что земля - ​​это сфера. Из GCMAP.com:

Гипотетическая форма Земли называется геоидом и аппроксимируется эллипсоидом или сплюснутым сфероидом. Более простая модель - использовать сферу, которая довольно близка и намного упрощает математику. Предполагая сферу радиуса6371,2 км, преобразовать долготу и широту в радианы (умножить на pi / 180) aЗатем используйте следующую формулу:

theta = lon2 - lon1
dist = acos(sin(lat1) × sin(lat2) + cos(lat1) × cos(lat2) × cos(theta))
if (dist < 0) dist = dist + pi
dist = dist × 6371.2

Полученное расстояние выражено в километрах.

Теперь, если вам нужны точные расчеты и вы готовы потратитьциклы процессора, необходимые для сложной математики, вы можете использовать формулы Винсенти, в которых используется эталонная эллипсоидная модель Земли WGS-84, которая используется для навигации, составления карт и тому подобного.Подробнее ЗДЕСЬ

Что касается самого алгоритма, вам необходимо построить матрицу to-from с результатом каждого вычисления.Каждая строка и столбец будут представлять каждый узел.Вы можете рассмотреть два упрощения:

  1. Расстояние не зависит от направления движения, поэтому $dist[n][m] == $dist[m][n] (не нужно вычислять всю матрицу, только половину ее)
  2. Расстояние отузел для себя всегда равен 0, так что нет необходимости вычислять его, но, поскольку вы собираетесь группировать по близости, чтобы избежать группирования пользователя с самим собой, вы можете захотеть всегда принудительно $dist[m][m] принудительно определять произвольно и ненормальнобольшая константа (например, $dist[m][m] = 22000 (miles). Будет работать, пока все ваши пользователи находятся на планете)

После выполнения всех расчетов используйте метод сортировки массива, чтобы найти X ближайших узлов к каждомуузел и вот он у вас (вы можете или не хотите запретить группировку пользователей в более чем одну группу, но это просто бизнес-логика)

Фактический код будет слишком много, чтобы предоставить его в настоящее времяне видя вначале своего прогресса, но это в основном то, что вам нужно делать алгоритмически.

0 голосов
/ 19 сентября 2018

Использовать алгоритм GeoHash [1].Есть реализация PHP [2].Вы можете предварительно вычислять геошэши с разной точностью, сохранять их в базе данных SQL вместе со значениями lat-lon и выполнять запросы с использованием собственного GROUP BY.

  1. https://en.wikipedia.org/wiki/Geohash
  2. https://github.com/lvht/geohash
0 голосов
/ 13 сентября 2018

... похоже, что я ищу пространственный запрос, который возвращает группы по близости....

Вы можете использовать hdbscan.Ваши группы на самом деле являются кластерами в формулировке hdbscan.Вам нужно работать с min_cluster_size и min_samples, чтобы получить правильные группы.

https://hdbscan.readthedocs.io/en/latest/parameter_selection.html

https://hdbscan.readthedocs.io/en/latest/

Похоже, что hdbscan работает под Python.

Вот две ссылки о том, как вызвать Python из PHP: Вызов Python в PHP , Запуск скрипта Python из PHP

Вот еще немного информации окакой алгоритм кластеризации выбрать: http://nbviewer.jupyter.org/github/scikit-learn-contrib/hdbscan/blob/master/notebooks/Comparing%20Clustering%20Algorithms.ipynb

http://scikit -learn.org / stable / modules / clustering.html # clustering

...