考虑从[0,T]开始按递增顺序给出的点Y.我们要将这些点视为位于圆周T上。现在考虑点X也来自[0,T)并且也位于圆周T上。
我们说X和Y之间的距离是X中每个点与Y中最近点之间的绝对距离之和,回想两者都被认为是在一个圆圈中。将此距离写为Delta(X,Y)。
我试图找到一种快速确定X旋转的方法,使这个距离尽可能小。
我的代码是用于测试一些数据
#!/usr/bin/python
import random
import numpy as np
from bisect import bisect_left
def simul(rate, T):
time = np.random.exponential(rate)
times = [0]
newtime = times[-1]+time
while (newtime < T):
times.append(newtime)
newtime = newtime+np.random.exponential(rate)
return times[1:]
对于每个点,我使用此函数来查找其最近的邻居。
def takeClosest(myList, myNumber, T):
"""
Assumes myList is sorted. Returns closest value to myNumber in a circle of circumference T.
If two numbers are equally close, return the smallest number.
"""
pos = bisect_left(myList, myNumber)
before = myList[pos - 1]
after = myList[pos%len(myList)]
if after - myNumber < myNumber - before:
return after
else:
return before
所以两个圆圈之间的距离是:
def circle_dist(timesY, timesX):
dist = 0
for t in timesX:
closest_number = takeClosest(timesY, t, T)
dist += np.abs(closest_number - t)
return dist
所以我们只做一些数据
#First make some data
T = 5000
timesX = simul(1, T)
timesY = simul(10, T)
最后通过偏移旋转圆圈时间X我们可以
timesX = [(t + offset)%T for t in timesX]
在实践中,我的timesX和timesY各有约20,000点。
给定timesX和timesY,我怎样才能快速找到(大约)timesX给出的旋转 距离时间的最小距离是什么?
答案 0 :(得分:2)
单个点和一组点之间沿圆的距离是旋转的分段线性函数。该函数的关键点是集合本身的点(零距离)和集合的相邻点之间的中间点(局部最大距离)。这种函数的线性系数是±1。
此类函数的总和再次是分段线性的,但现在具有二次数临界点。实际上所有这些函数都是相同的,除了沿参数轴移动。和的线性系数是整数。
要找到它的最小值,必须在所有关键点计算其值。
我没有办法大幅减少所需的工作量,但无论如何,1,600,000,000点并不是什么大问题,特别是如果你可以在多个处理器之间分配工作。
要计算两个此类函数的总和,请将求和表示为关键点的序列以及每个临界点左侧和右侧的相关系数。然后在添加系数时合并两个点序列。
答案 1 :(得分:2)
您可以使用扫描线算法解决(原始)问题。诀窍是使用正确的&#34;离散化&#34;。想象一下,将你的圆圈切成两条:
X: x....x....x..........x................x.........x...x
Y: .....x..........x.....x..x.x...........x.............
现在计算score = 5+0++1+1+5+9+6
。
关键的观察是,如果我们非常轻微地转动X
(右说),一些点将会改善,一些点会变得更糟。我们可以将其称为差异&#34;。在上面的例子中,差异将是1 - 1 - 1 + 1 + 1 - 1 + 1
,因为第一个点与其右边的某个东西相匹配,第二个点与它下面的东西或左边的东西相匹配等。
当然,随着我们更多地移动X
,差异将会改变。然而,只有匹配变化的次数不会超过|X||Y|
,但可能会更少。
因此,所提出的算法用于计算下一个差异变化的初始分数和时间(X位置)。转到下一个位置并再次计算得分。继续,直到你到达起始位置。
答案 2 :(得分:0)
这可能是iterative closest point(ICP)算法的一个很好的例子:
它重复匹配每个点与其最近邻居并移动所有点,使得均方距离最小化。 (请注意,这相当于最小化平方距离的和。)
import pylab as pl
T = 10.0
X = pl.array([3, 5.5, 6])
Y = pl.array([1, 1.5, 2, 4])
pl.clf()
pl.subplot(1, 2, 1, polar=True)
pl.plot(X / T * 2 * pl.pi, pl.ones(X.shape), 'r.', ms=10, mew=3)
pl.plot(Y / T * 2 * pl.pi, pl.ones(Y.shape), 'b+', ms=10, mew=3)
circDist = lambda X, Y: (Y - X + T / 2) % T - T / 2
while True:
D = circDist(pl.reshape(X, (-1, 1)), pl.reshape(Y, (1, -1)))
closestY = pl.argmin(D**2, axis = 1)
distance = circDist(X, Y[closestY])
shift = pl.mean(distance)
if pl.absolute(shift) < 1e-3:
break
X = (X + shift) % T
pl.subplot(1, 2, 2, polar=True)
pl.plot(X / T * 2 * pl.pi, pl.ones(X.shape), 'r.', ms=10, mew=3)
pl.plot(Y / T * 2 * pl.pi, pl.ones(Y.shape), 'b+', ms=10, mew=3)
建议的解决方案的重要特性是:
Y
中与X
中每个点相对的最近点。交换X
和Y
时,它可能会产生不同的匹配。X
中的点与Y
中的点之间的所有成对距离对于大点云(例如20,000点,如您所示)可能是难以处理的。因此,行D = circDist(...)
可能会被更有效的方法取代,例如没有评估所有可能的对。shift
。这可以通过median
这样的强大平均值来解决,也可以通过排除大distance
的点来克服。