pandas 迭代最近邻搜索- Sklearn、python

ozxc1zmp  于 2023-01-28  发布在  Python
关注(0)|答案(1)|浏览(108)

我正在尝试使用sklearn.neighbors对一组名称、经度和纬度坐标进行搜索。

name        lat        long
        0   Veronica Session  11.463798   14.136215
        1      Lynne Donahoo  44.405370  -82.350737
        2      Debbie Hanley  14.928905  -91.344523
        3     Lisandra Earls  68.951464 -138.976699
        4         Sybil Leef  -1.678356   33.959323

目前,下面的代码读取第一行。取自我对previous question的回答。

nn = NearestNeighbors(metric="haversine")
nn.fit(df[["lat", "long"]])
new_example = pd.DataFrame({"lat": [0], "long": [0]})
nearest = nn.kneighbors(new_example, n_neighbors=3, return_distance=False)
nn_route = pd.DataFrame(df.iloc[nearest[0]])
nn_route_pd = pd.DataFrame(nn_route)

我希望这运行在每一组坐标,形成一个整体的“最佳”路线。以及过滤掉非唯一的位置(即最近的邻居已经确定从以前的坐标)。
我已经将其修改为while循环,但是这并没有按照需要迭代代码,并且仍然只在一组坐标上运行搜索。
我如何即兴发挥我的while循环,将NN搜索应用于每一行,并过滤掉非唯一位置?

loc= 0
new_example = pd.DataFrame({"lat": [loc], "long": [loc]})

#For loop to cycle through each row and increment by 1
while True:
   if loc < 99:
       for i in df:
           new_example
           nearest = nn.kneighbors(new_example, n_neighbors=2, return_distance=False)
           loc += 1
           nn_route = pd.DataFrame(df.iloc[nearest[0]])
           nn_route_pd = pd.DataFrame(nn_route)
   else:
       break
zwghvu4y

zwghvu4y1#

这个问题实际上是在问一个贪婪地解决旅行商问题的纬度和经度。一个复杂的问题是,这些位置可能包括近似重复的位置,而解决方案应该试图将这些近似重复的位置合并到一个单一的位置。
考虑类似这样的情况,显示包含一个"重复"点的纬度和经度数组:

from scipy.spatial.distance import euclidean
import numpy as np
from random import randint
import matplotlib.pyplot as plt

locations = np.array(
    [
        [11.463798, 14.136215],
        [11.463797, 14.136214],  # <-- similar to previous
        [44.405370, -82.350737],
        [14.928905, -91.344523],
        [68.951464, -138.976699],
        [-1.678356, 33.959323],
    ]
)

在高水平上:我们可以做到以下几点:
1.使用随机选择的位置初始化
1.保持剩余位置的"边界"
1.贪婪地选择下一个距离最小的位置
1.如果当前位置和另一个位置之间的距离小于某个预定义的阈值,我们将其标记为"重复"以进行移除。(这种阈值方法可能需要调整,或者可能需要一些先验知识。例如:如果我们正在设计递送系统,则可以考虑在步行距离内彼此相距几百米的位置,而所有其它位置应当通过汽车到达)。
1.返回路线的总距离和索引。
而使用欧几里德距离的实现可能看起来像这样:

def find_greedy_route(locations, threshold=0.01):

    indexes = list(range(locations.shape[0]))
    route = [indexes.pop(randint(0, len(indexes) - 1))]
    total_distance = 0.0

    while indexes:
        at = locations[route[-1]]
        distance, nearest = np.inf, -1
        duplicates = []

        for i in indexes:
            if (next_distance := euclidean(at, locations[i])) < distance:

                if next_distance <= threshold:
                    duplicates.append(i)
                    continue

                nearest = i
                distance = next_distance

        indexes.remove(nearest)
        route.append(nearest)
        total_distance += distance
        for d in duplicates:
            indexes.remove(d)

    route.append(route[0])
    total_distance += euclidean(locations[route[-1]], locations[route[0]])

    return total_distance, np.asarray(route)

路线取决于起始位置,因此多次运行此命令会显示:(1)总距离取决于起始位置,(2)我们的阈值化方法意味着所有路由将包含01,但不是两者都包含。
一个二个一个一个
绘制路线图还可以提供一些见解:

plt.plot(locations[route][:, 0], locations[route][:, 1])
plt.scatter(locations[route][:, 0], locations[route][:, 1])
plt.show()

相关问题