更高维度的凸包,找到多面体的顶点
Posted
技术标签:
【中文标题】更高维度的凸包,找到多面体的顶点【英文标题】:Convex hull in higher dimensions, finding the vertices of a polytope 【发布时间】:2015-03-09 11:42:02 【问题描述】:假设我有一个在 6 维空间中给出的点云,我可以根据需要将其变得密集。这些点最终位于低维多面体的表面上(即点向量 (x1, x2, ... x6) 似乎是共面的)。
我想找到这个未知多面体的顶点,我目前的尝试通过 Python 中的 scipy 接口使用 qhull 算法。一开始我只会收到错误消息,显然是由低维输入和/或许多退化点引起的。我尝试了几种蛮力方法来消除退化点,但不是很成功,所以最后,我认为所有这些点都必须位于凸包上。
This question 非常有帮助,因为它建议通过主成分分析进行降维。如果我将点投影到 4D 超平面,qhull 算法运行没有错误(对于任何更高的维度它都不会运行)。
from scipy.spatial import ConvexHull
from sklearn.decomposition import PCA
model = PCA(n_components=4).fit(initial_points)
proj_points = model.transform(initial_points)
hull = ConvexHull(proj_points, qhull_options = "Qx")
上述问题的答案提到,在计算投影点的凸包后,需要将单纯形转换回来。但是 qhull 输出仅包含索引,为什么这些与初始点的索引不匹配?
现在我的问题是我不知道使用哪种精度来实际获得正确的顶点。无论我制作的点云有多密集,获得的顶点都以不同的精度不同。例如,对于我得到的 (10000, 6) 数组中的初始点(其中 E0.03 是它的最大值):
hull1 = ConvexHull(proj_points, qhull_options = "Qx, E0.03")
print len(hull1.vertices)
print hull1.vertices
5
[ 437 2116 3978 7519 9381]
并将其绘制在轴 0、1、2 的一些(信息量不大)投影中(其中蓝色点代表初始点云的选择):
但是为了更高的精度(当然)我得到了不同的集合:
hull2 = ConvexHull(proj_points, qhull_options = "Qx, E0.003")
print len(hull2.vertices)
print hull2.vertices
29
[ 74 75 436 437 756 1117 2116 2366 2618 2937 3297 3615 3616 3978 3979
4340 4561 4657 4659 4924 5338 5797 6336 7519 7882 8200 9381 9427 9470]
相同的投影(只是角度略有不同):
我怀疑第一张图片没有足够的顶点,而第二张图片可能有太多。虽然我当然无法从这些图中提取严格的信息。但是有没有一种很好的方法来找出使用哪种精度?或者也许是一种完全不同的方法来解决这个问题(我已经尝试了一些)?
【问题讨论】:
有趣的问题。我没有现成的答案,但同意第一个例子肯定看起来(肉眼)有太少的顶点。我猜,后一个总是倾向于沿着投影多面体的“边缘”(如果术语不好,而不是我的专业领域)有很多顶点,只是因为初始点是随机的 - 你不太可能在您所说的存在的多面体的“真实”顶点上获得一个。如果您有时间进行实验 - 您是否尝试过 Q8 选项,该选项似乎忽略了“几乎在内部”点。 感谢您的评论。事实证明,Qhull 中的大多数不同选项都会产生相同(不同)的答案,Q8 也是如此。唯一一个给出稍微不同的数字(但在不同的精度下仍然不稳定)是 Q9。集合不太可能包含预期的“真实”顶点是正确的,但由于它们非常接近,我觉得应该有一种方法来获得它们。 我想得越多,我就越感兴趣。看来这仍然是数学论文的主题。 This 显示了一种方法(2D),其中它们的 alpha 参数似乎对您的精度有类似的影响。问题是,根据定义,船体是可以包含点的最小多面体,但我们假设“真实”顶点可能位于样本集之外,并且在某种意义上,多面体具有比高精度估计产生的“更简单的形状”。肉眼看,好的,算法上,很难。 我还没有完全理解在船体上的所有点的重要性:也许可以使用识别点云中的(超)平面的技术。这些平面的交叉点可能会为您提供您正在寻找的简单船体。之后可以检查所有点都在上面或里面。我找到了为此引用的RANSAC algorithm。 1, 2 没关系,我认为下面@timothyshields 描述的算法使用梯度下降代替了你想要的。 【参考方案1】:在这个答案中,我假设您已经使用 PCA 将数据近乎无损地压缩为 4 维数据,其中减少的数据位于概念上很少面的 4 维多面体中。我将描述一种方法来解决这个多面体的面,这反过来会给你顶点。
设 R4 中的 xi, i = 1, ..., m, 是 PCA 减少的数据点。
令 F = (a, b) 为 face,其中 a 在 R4 中带有 • a = 1 且 b 在 R 中。
我们定义人脸loss函数L如下,其中λ+, λ- 0是你选择的参数。 λ+ 应该是一个非常小的正数。 λ- 应该是一个非常大的正数。
L(F) = sumi(λ+ • max(0, a • xi + b) - λ - • min(0, a • xi + b))
我们想要找到关于损失函数 L 的最小面 F。所有最小面的小集合将描述您的多面体。您可以通过随机初始化 F 然后使用偏导数 ∂L / ∂aj、j = 1、2、3、4 和 ∂L / ∂b 执行梯度下降来求解最小面。在梯度下降的每一步,约束一个 • a 通过归一化为 1。
∂L / ∂aj = sumi(λ+ • xj • [ a • xi + b > 0] - λ- • xj • [a • xi + b
∂L / ∂b = sumi(λ+ • [a • xi + b > 0] - λ - • [a • xi + b
注意Iverson brackets:如果 P 为真,则 [P] = 1,如果 P 为假,则 [P] = 0。
【讨论】:
在实际应用中,我仍然无法理解一些细节,但理论上我真的很喜欢这个想法。首先,我必须承认我不太清楚如何获得这些面孔。您能否解释一下(或指出某个来源),条件 a • a = 1 的由来? 向量 a 是(有向)面 F 的法线。条件 a • a = 1 只是限制法线 a 的长度为 1;也就是说,||a|| = 1. 啊,对。这就说得通了。 b 究竟是由什么决定的?我还没有完全实现这个想法,但我认为接受这一点是有道理的。 b 是面 F 沿其法线 a 的偏移量。当 b = 0 时,面通过原点。当 b = 5 时,人脸距离原点 5。 @Denor 我将部分渐变添加到答案的末尾。以上是关于更高维度的凸包,找到多面体的顶点的主要内容,如果未能解决你的问题,请参考以下文章