【问题标题】:Choosing subset of farthest points in given set of points在给定的点集中选择最远点的子集
【发布时间】:2023-03-06 20:22:01
【问题描述】:

假设你在 3 维中得到了 n 个点的集合 S。任何两点之间的距离都是简单的欧几里得距离。您想从该集合中选择 k 个点的子集 Q,使它们彼此相距最远。换句话说,不存在其他 k 个点的子集 Q',使得 Q 中所有成对距离的 min 小于 Q'。

如果 n 约为 1600 万,k 约为 300,我们如何有效地做到这一点?

我的猜测是这个 NP-hard 所以我们可能只想专注于近似。我能想到的一个想法是使用多维缩放对一条线上的这些点进行排序,然后使用二进制搜索的版本来获取这条线上相距最远的点。

【问题讨论】:

  • k 约为 300。
  • 积分分布有什么信息吗?如果点的图看起来像圆形或椭圆形的云,那么您可能会将椭圆形拟合到云上;计算出圆周上的 k' 个等距点,然后找到最接近 k' 的 k 个点。有一种数据结构可以加速在另一个点附近找到点 - 目前不记得名称。椭圆的大小可能也需要迭代以更好地贴合。
  • 确实,在二维中,圆上的点有一个 O(N) 解。可以扩展到球体或其他一些近似凸面。
  • 更一般地说,我会非常担心分布,因为由于 N>>k 对于许多分布,很容易排除许多点作为集合的一部分。
  • 如果你有一个有代表性的更小的点样本,你和其他人可以研究算法......

标签: python algorithm computational-geometry dimensionality-reduction multi-dimensional-scaling


【解决方案1】:

这被称为离散 p 色散 (maxmin) 问题。

White (1991)Ravi et al. (1994) 中证明了最优性界限,为问题提供了因子 2 的近似值,后者证明了这种启发式方法是最好的(除非 P=NP)。

因子 2 近似

因子 2 的近似值如下:

Let V be the set of nodes/objects
Let i and j be two nodes at maximum distance
Let p be the number of objects to choose
p = set([i,j])
while size(P)<p:
  Find a node v in V-P such that min_{v' in P} dist(v,v') is maximum
  \That is: find the node with the greatest minimum distance to the set P
  P = P.union(v)
Output P

你可以像这样在 Python 中实现它:

#!/usr/bin/env python3

import numpy as np

p = 50
N = 400

print("Building distance matrix...")
d = np.random.rand(N,N) #Random matrix
d = (d + d.T)/2         #Make the matrix symmetric

print("Finding initial edge...")
maxdist  = 0
bestpair = ()
for i in range(N):
  for j in range(i+1,N):
    if d[i,j]>maxdist:
      maxdist = d[i,j]
      bestpair = (i,j)

P = set()
P.add(bestpair[0])
P.add(bestpair[1])

print("Finding optimal set...")
while len(P)<p:
  print("P size = {0}".format(len(P)))
  maxdist = 0
  vbest = None
  for v in range(N):
    if v in P:
      continue
    for vprime in P:
      if d[v,vprime]>maxdist:
        maxdist = d[v,vprime]
        vbest   = v
  P.add(vbest)

print(P)

精确解

您也可以将其建模为 MIP。对于 p=50、n=400,在 6000 秒后,最优差距仍为 568%。近似算法花费了 0.47 秒来获得 100%(或更少)的最优差距。一个朴素的 Gurobi Python 表示可能如下所示:

#!/usr/bin/env python
import numpy as np
import gurobipy as grb

p = 50
N = 400

print("Building distance matrix...")
d = np.random.rand(N,N) #Random matrix
d = (d + d.T)/2             #Make the matrix symmetric

m = grb.Model(name="MIP Model")

used  = [m.addVar(vtype=grb.GRB.BINARY) for i in range(N)]

objective = grb.quicksum( d[i,j]*used[i]*used[j] for i in range(0,N) for j in range(i+1,N) )

m.addConstr(
  lhs=grb.quicksum(used),
  sense=grb.GRB.EQUAL,
  rhs=p
)

# for maximization
m.ModelSense = grb.GRB.MAXIMIZE
m.setObjective(objective)

# m.Params.TimeLimit = 3*60

# solving with Glpk
ret = m.optimize()

缩放

显然,初始点的 O(N^2) 缩放是不好的。通过认识到这对必须位于数据集的凸包上,我们可以更有效地找到它们。这为我们提供了一种 O(N log N) 方法来找到该对。一旦我们找到它,我们就会像以前一样继续(使用 SciPy 进行加速)。

最好的缩放方法是使用 R*-tree 来有效地找到候选点 p 和集合 P 之间的最小距离。但这在 Python 中不能有效地完成,因为仍然涉及for 循环.

import numpy as np
from scipy.spatial import ConvexHull
from scipy.spatial.distance import cdist

p = 300
N = 16000000

# Find a convex hull in O(N log N)
points = np.random.rand(N, 3)   # N random points in 3-D

# Returned 420 points in testing
hull = ConvexHull(points)

# Extract the points forming the hull
hullpoints = points[hull.vertices,:]

# Naive way of finding the best pair in O(H^2) time if H is number of points on
# hull
hdist = cdist(hullpoints, hullpoints, metric='euclidean')

# Get the farthest apart points
bestpair = np.unravel_index(hdist.argmax(), hdist.shape)

P = np.array([hullpoints[bestpair[0]],hullpoints[bestpair[1]]])

# Now we have a problem
print("Finding optimal set...")
while len(P)<p:
  print("P size = {0}".format(len(P)))
  distance_to_P        = cdist(points, P)
  minimum_to_each_of_P = np.min(distance_to_P, axis=1)
  best_new_point_idx   = np.argmax(minimum_to_each_of_P)
  best_new_point = np.expand_dims(points[best_new_point_idx,:],0)
  P = np.append(P,best_new_point,axis=0)

print(P)

【讨论】:

    【解决方案2】:

    我也很确定问题是 NP-Hard,我发现的最相似的问题是 k-Center Problem。如果运行时间比正确性更重要,那么贪心算法可能是您的最佳选择:

    Q ={}
    while |Q| < k
        Q += p from S where mindist(p, Q) is maximal
    

    旁注:在类似的问题中,例如set-cover problem,可以证明贪婪算法的解决方案至少比最优解决方案好 63%。

    为了加快速度,我看到了 3 种可能性:

    1. 首先在R-Tree 中索引您的数据集,然后执行贪心搜索。 R-Tree 的构建是 O(n log n),但尽管它是为最近邻搜索而开发的,但它也可以帮助您找到 O(log n) 中的一组点的最远点。这可能比简单的 O(k*n) 算法更快。

    2. 从 1600 万个点中抽取一个子集,然后对子集执行贪心算法。无论如何,您都是近似的,因此您可以节省更多的准确性。您也可以将其与 1. 算法结合使用。

    3. 使用迭代方法并在时间不够时停止。这里的想法是从 S 中随机选择 k 个点(我们称这个集合为 Q')。然后在每个步骤中,您将点 p_ 从 Q' 切换到 Q' 中具有最小距离的另一个点,并带有来自 S 的随机点。如果结果集 Q'' 最好继续 Q'',否则重复 Q' .为了不被卡住,如果您在几次迭代中找不到合适的替代品,您可能希望从 Q' 中选择另一个点而不是 p_。

    【讨论】:

      【解决方案3】:

      如果你能负担得起 ~ k*n 距离计算,那么你可以

      1. 找到点分布的​​中心。
      2. 选择离中心最远的点。 (并将其从一组未选择的点中删除)。
      3. 找到距离所有当前选定点最远的点并选择它。
      4. 重复 3. 直到以 k 点结束。

      【讨论】:

      • 第 3 步是问题的症结所在。这种幼稚的算法不会适用于较大的 n。
      • 我认为你的贪心算法在这里行不通。假设k=3Q 是同一平面上的 6 个点。它们都属于一个圆的圆周并且均匀分布在那里(2个“邻居”之间的距离是R)。选择第一个点后,您的算法将采用最远的点,即直径另一端的点。最后一点,您必须选择“邻居”(因此您的最小距离将为R),而最佳解决方案将选择创建等边三角形的点(因此最小距离为R*sqrt(3))。
      • 嗨@BUZZY,这是贪婪算法的本质,你想要一个能给出足够好的结果的算法,但不能保证它们是通过检查所有可能性找到的最佳结果。
      • 我明白这一点。我的问题是您的回答并没有说明这是尽力而为的算法,而不是实际的解决方案。此外,如果这只是一个近似值,那么值得添加一个注释,它可能与最佳解决方案相差多远。否则,这只是随机选取的一组点,至少对我来说是这样。
      • 好的@BUZZY,。在阅读这个问题时,我想到了“我的猜测是这个 NP-hard 所以我们可能只想专注于近似”,并假设所有答案都被认为是非最优的。
      【解决方案4】:

      找到所有点的最大范围。拆分为 7x7x7 体素。对于体素中的所有点,找到最接近其中心的点。返回这些 7x7x7 点。一些体素可能不包含点,希望不会太多。

      【讨论】:

        猜你喜欢
        • 2013-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-02
        • 1970-01-01
        • 1970-01-01
        • 2017-02-16
        • 1970-01-01
        相关资源
        最近更新 更多