【发布时间】:2011-11-30 09:37:50
【问题描述】:
我正在尝试将多个点减少并合并到这些位置的中心点。现在我通过找到最接近的对来强制它,将它们组合并重复直到我将它减少到我的目标(旁注:实际上我通过(lat*lat+long*long)排序然后在任一侧搜索10%来减少问题每个点的距离,我的测试总是找到该范围内的最短距离)。
例如,我想将 4000 个点减少到 1000 个,理想情况下将最近的点组合到这些最近点的中心。基本上是为了建立反映该区域地址数量的标记点。
有没有更好的算法可以给我尽可能准确的结果?还是更快的距离算法?我想它只需要在短距离内准确
现在我正在寻找距离(维基百科在“球形地球投影到平面”下有它):
double dLat = pos2.LatitudeR - pos1.LatitudeR;
double dLon = pos2.LongitudeR - pos1.LongitudeR;
double cosLatM = Math.Cos((pos2.LatitudeR + pos1.LatitudeR)/2) * dLon;
double a = dLat*dLat + cosLatM*cosLatM;
我考虑过将彼此距离为 x 的所有点分组,然后扩展 x 直到达到我的目标最终点数,但我不知道如何让它像我的完美主义想要的那样准确它。这就是我能想到的所有方式,具体取决于输入点列表的顺序。
编辑以描述我当前的算法如何处理(这是找到我想要的结果的理想方式,但更快的近似值是值得的):
线性描述它,如果你有x=1,4,5,6,10,20,22
- 它将结合 4+5=4.5 [找到的第一个 1.0 距离]
- (4.5*2+6)/3=5 --
x=1,5,10,20,22[1.5 距离] - 20+22=21 --
x=1,5,10,21[2.0 距离] - (5*3+1)/4=4 --
x=4,10,21[4.0 距离] - (4*4+10)/5.2 -- 所以你最终会得到
x=5.2,21。 (它会跟踪 CombineCount,因此它可以通过这种方式找到正确的平均中心)
结果: 这是我当前的距离函数,为 cos^2 生成查找表。还没来得及检查我的点有多接近,所以还没有实施乔伊关于近似 cos^2 的建议,但这可以提高此处查找表的速度。
我尝试的 K-Cluster 算法(请参阅我对该答案的评论)并没有按照我的意愿将它们组合在一起,它最终在地图中心附近有大量点,而在边缘则有少量点。因此,除非我能纠正我使用的算法较慢。
public static double Distance(AddressCoords pos1, AddressCoords pos2, DistanceType type)
{
if (LookupTable == null) LookupTable = BuildLookup();
double R = (type == DistanceType.Miles) ? 3960 : 6371;
double dLat = pos2.LatitudeR - pos1.LatitudeR;
double dLon = pos2.LongitudeR - pos1.LongitudeR;
double LatM = ((pos2.LatitudeR + pos1.LatitudeR)/2);
if (LatM < 0) LatM = -LatM; //Don't allow any negative radian values
double cosLatM2 = LookupTable[(int)(LatM * _cacheStepInverse)];
double a = dLat*dLat + cosLatM2 * dLon*dLon;
//a = Math.Sqrt(a);
double d = a * R;
return d;
}
private const double _cacheStep = 0.00002;
private const double _cacheStepInverse = 50000;
private static double[] LookupTable = null;
public static double[] BuildLookup()
{
// set up array
double maxRadian = Math.PI*2;
int elements = (int)(maxRadian * _cacheStepInverse) + 1;
double[] _arrayedCos2 = new double[elements];
int i = 0;
for (double angleRadians = 0; angleRadians <= maxRadian;
angleRadians += _cacheStep)
{
double cos = Math.Cos(angleRadians);
_arrayedCos2[i] = cos*cos;
i++;
}
return _arrayedCos2;
}
【问题讨论】:
-
只是为了更好地理解您的要求,如果您的 4000 个点完全均匀地分布在网格中会怎样?
-
如果是这种情况,我的要求不会关心它选择组合哪些对...如果它们都是正方形,我认为我当前的算法会将前两个组合在一起找到一个中心点。中途会有矩形,然后结合那些最接近的对以获得 4 个点的中心点。如果不是以 2 的幂次方减少,则取决于点的顺序
-
如果你有 3 个点与其他点相距很远,你希望发生什么?把两个结合起来,让另一个不理会?结合两个,然后将另一个与一个很远的地方结合起来?还有什么?
-
是的,我想你已经理解了,但为了确保我添加了当前代码每次迭代的示例
标签: c# performance algorithm