如何获得geodjango的k个最近邻居?

Posted

技术标签:

【中文标题】如何获得geodjango的k个最近邻居?【英文标题】:How do I get the k nearest neighbors for geodjango? 【发布时间】:2018-01-06 09:27:21 【问题描述】:

假设我有以下模型:

class Person:
     id       = models.BigAutoField(primary_key=True)
     name     = models.CharField(max_length=150)
     location = models.PointField()

如何使用 geodjango 按位置获取 k 个最近邻 (KNN)? 我必须为此编写自定义 SQL 吗? 我正在将 PostgreSQL 与 PostGIS 一起使用。

【问题讨论】:

【参考方案1】:

您可以使用raw() sql 查询来利用 postgis order_by 运算符:

    <-> 使用边界框的中心来计算对象间距离。

    <#> 使用边界框本身来计算对象间距离。

在您的情况下,您想要的似乎是 <-> 运算符,因此是原始查询:

knn = Person.objects.raw(
    'SELECT * FROM myapp_person 
    ORDER BY location <-> ST_SetSRID(ST_MakePoint(%s, %s),4326)',
    [location.x, location.y]
)[:k]

由于自己的愚蠢而编辑:您可以省略 [:k] 以在原始 SQL 查询中添加 LIMIT 1。 (不要像我一样使用两者!)


在回答您的另一个问题的过程中:How efficient is it to order by distance (entire table) in geodjango,可能还有另一种解决方案:

通过启用spatial indexing 并通过逻辑约束缩小查询范围(如上述链接问题的in my answer 所述),您可以实现非常快速的KNN 查询,如下所示:

current_location = me.location
people = People.objects.filter(
    location__dwithin=(current_location, D(km=50))
).annotate(
    distance=Distance('location', current_location)
).order_by('distance')[:k]

【讨论】:

对于这种场景(获取knn),使用geography列是否还有帮助?还是毫无意义 - 因为我假设涉及 &lt;-&gt; 的计算会有所不同 您可以使用地理列或几何列。加快查询速度最重要的是使用spatial_idex。有关该主题的进一步阅读,请看这里:boundlessgeo.com/2011/09/…Good lucky @Alan :) 您好,回头看看您的回答,我对knn = Person.objects.raw('SELECT * FROM myapp_person...LIMIT 1 的用途感到困惑,我们为什么需要它? @Alan 这将返回第一个最近的邻居。你可以随意改变!我也会在我的回答中对此进行编辑。 我以为[:k] 处理好了?我很困惑,因为 LIMIT K[:k] 似乎在这里服务于相同的目的

以上是关于如何获得geodjango的k个最近邻居?的主要内容,如果未能解决你的问题,请参考以下文章

K-近邻(KNN)算法

最近邻居 - k-d 树 - ***证明

在 Weka 中使用 KNN 获取数据集中每个点的 n 个最近邻

knn是啥意思

使用交叉验证为 k-最近邻分类器找到正确的 k 值

最近邻居图中第 k 个邻居的奇怪距离