繁体   English   中英

在python中查找给定点和点列表之间的最近和最远点(2D)

[英]Find the closest and the farthest points (2D) between a given point and a list of points in python

所以我正在尝试编写一个 python 函数,它可以将任何给定点说(1,2)我们可以称之为兴趣点,然后获取点列表[(6,2), (4,5), (3,4),...]函数应该返回离我们的兴趣点最近最远的点(从列表中)。

该函数应接受两个参数:

    1. Point of interest i.e. pos=(1,2)
    2. List of points i.e. ptlist=[(1,3),(6,2), (4,5), (3,4)]

该函数还应该以 ((1,3),(4,5)) 的形式返回答案,即(最近的,最远的)

这是我的代码,到目前为止它有效,但它返回 numpy 数组,而我希望我的答案是元组。 我尝试了不同的方法,无论我尝试什么,我似乎都无法做到。 也许我们可以使用除 numpy 之外的其他东西,以便我们以 ((1,3),(4,5)) 的形式获得答案。

这是我到目前为止编写的代码:

pos=(1,2)
ptlist=[(2, 6), (8,6), (5,8), (2,4)]
def get_nearest_farthest(pt, ptlist):
    pt=np.array(pt)
    ptlist=np.array(ptlist)
    dist=np.linalg.norm(ptlist-pt, axis=1)
    min_index = np.argmin(dist)
    #tuple(map(tuple,ptlist[min_index])) #Error
    max_index = np.argmax(dist)
    #tuple(map(tuple,ptlist[max_index])) #Error
    return ptlist[min_index],ptlist[max_index]

get_nearest_farthest(pt, ptlist)

你不需要numpy 您只需要带有key参数的min() / max()

distance_metric = lambda x: (x[0] - pos[0])**2 + (x[1] - pos[1])**2
closest = min(ptlist, key=distance_metric)
farthest = max(ptlist, key=distance_metric)

print(closest, farthest)

这输出:

(2, 4) (8, 6)

这将在不使用 numpy 的情况下到达那里,并且非常有效,只需对列表中的每个点进行一次距离计算。

def get_nearest_farthest(pos, pt_list):
    nearest_pt, farthest_pt = None, None
    nearest_d, farthest_d = None, None

    for pt in pt_list:
        d = (pos[0]-pt[0])**2 + (pos[1]-pt[1])**2

        if nearest_d is None or d < nearest_d:
            nearest_d = d
            nearest_pt = pt

        if farthest_d is None or d > farthest_d:
            farthest_d = d
            farthest_pt = pt

    return nearest_pt, farthest_pt

pos = (1,2)
pt_list = [(2, 6), (8,6), (5,8), (2,4)]
get_nearest_farthest(pos, pt_list)

有许多方法可以解决这个问题。 你的就是其中之一,要以元组的形式获得结果,将结果数组转换回list就足够了,并结合使用tuple()np.ndarray.tolist()

就最快的执行而言,这一切都归结为输入的大小。

在这里,我提供了一些实现(一些类似于其他答案)以及一些时间:

import numpy as np


def p_dist_np(x, y, p=2):
    if p % 2:
        return np.sum(np.abs(x - y) ** p, axis=-1)
    else:
        return np.sum((x - y) ** p, axis=-1)


def minmax_dist_np(x0, xs, d_func=p_dist_np):
    x0 = np.array(x0)
    xs = np.array(xs)
    dists = d_func(x0, xs)
    min_i = np.argmin(dists)
    max_i = np.argmax(dists)
    return tuple(xs[min_i].tolist()), tuple(xs[max_i].tolist())
import numpy as np
import numba as nb


@nb.njit
def p_dist_nb(x, y, p=2):
    if p % 2:
        return np.sum(np.abs(x - y) ** p)
    else:
        return np.sum((x - y) ** p)


@nb.njit
def _minmax_dist_nb(x0, xs, d_func=p_dist_nb):
    min_i = max_i = 0
    min_d = max_d = d_func(x0, xs[min_i])
    for i, x in enumerate(xs[1:], 1):
        d = d_func(x0, x)
        if d < min_d:
            min_d = d
            min_i = i
        elif d > max_d:
            max_d = d
            max_i = i
    return min_i, max_i


def minmax_dist_nb(x0, xs, d_func=p_dist_nb):
    x0 = np.array(x0)
    xs = np.array(xs)
    min_i, max_i = _minmax_dist_nb(x0, xs, d_func=d_func)
    return tuple(xs[min_i].tolist()), tuple(xs[max_i].tolist())
def p_dist(x, y, p=2):
    if p % 2:
        return sum(abs(x_i - y_i) ** p for x_i, y_i in zip(x, y))
    else:
        return sum((x_i - y_i) ** p for x_i, y_i in zip(x, y))


def minmax_dist_loop(x0, xs, d_func=p_dist):
    i_xs = iter(xs)
    min_i = max_i = 0
    min_d = max_d = d_func(x0, next(i_xs))
    for i, x in enumerate(i_xs, 1):
        d = d_func(x0, x)
        if d < min_d:
            min_d = d
            min_i = i
        elif d > max_d:
            max_d = d
            max_i = i
    return xs[min_i], xs[max_i]
def minmax_dist_key(x0, xs, d_func=p_dist):
    return (
        min(xs, key=lambda x: d_func(x, x0)),
        max(xs, key=lambda x: d_func(x, x0)))

以及获取时间的代码:

x0 = (1, 2)
xs = [(2, 6), (8, 6), (5, 8), (2, 4)]


funcs = minmax_dist_np, minmax_dist_loop, minmax_dist_key, minmax_dist_nb
for n in (1, 10, 100, 1000):
    nxs = xs * n
    print(f"N = {n * len(xs)}")
    base = funcs[0](x0, nxs)
    for func in funcs:
        res = func(x0, nxs)
        print(f"{func.__name__:>24}  {base == res}", end='  ')
        %timeit -n 50 func(x0, nxs)
# N = 4
#           minmax_dist_np  True  50 loops, best of 5: 16.2 µs per loop
#         minmax_dist_loop  True  50 loops, best of 5: 6.11 µs per loop
#          minmax_dist_key  True  50 loops, best of 5: 11.6 µs per loop
#           minmax_dist_nb  True  50 loops, best of 5: 18.1 µs per loop
# N = 40
#           minmax_dist_np  True  50 loops, best of 5: 39.6 µs per loop
#         minmax_dist_loop  True  50 loops, best of 5: 54.3 µs per loop
#          minmax_dist_key  True  50 loops, best of 5: 107 µs per loop
#           minmax_dist_nb  True  50 loops, best of 5: 43.2 µs per loop
# N = 400
#           minmax_dist_np  True  50 loops, best of 5: 232 µs per loop
#         minmax_dist_loop  True  50 loops, best of 5: 550 µs per loop
#          minmax_dist_key  True  50 loops, best of 5: 1.07 ms per loop
#           minmax_dist_nb  True  50 loops, best of 5: 281 µs per loop
# N = 4000
#           minmax_dist_np  True  50 loops, best of 5: 2.28 ms per loop
#         minmax_dist_loop  True  50 loops, best of 5: 5.7 ms per loop
#          minmax_dist_key  True  50 loops, best of 5: 11.3 ms per loop
#           minmax_dist_nb  True  50 loops, best of 5: 2.78 ms per loop

表明对于足够小的输入, minmax_dist_loop()是最快的,但是一旦输入变大, minmax_dist_np()minmax_dist_nb()以相当大的优势接管。 相反, minmax_dist_key()逐渐变得最慢,主要是因为它需要计算两倍于minmax_dist_loop()的昂贵距离函数。 虽然对于minmax_dist_np()也计算了两次循环,但距离的计算只进行了一次(以创建可能很大的临时对象为代价)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM