JS - 基于密度

时间:2016-09-04 22:49:41

标签: javascript arrays

假设我有一个如下数组(每个小数组都是[x, y]):

var myPoints = [[25, 28], [26, 26], [70, 40], [50, 50], [300, 300], [285, 350], [1000, 1000]];

让我们说我需要将阵列缩小到4分。 (这是一个小例子,我的实际阵列有数千个点)我怎样才能根据密度对阵列进行细化,以便从点距离更近的区域中移除更多的点,从密度更低的区域移除更少的点?

在这种情况下(将上面的数组从8项减少到4项)我希望返回的数组看起来如下所示:

var thinnedPoints = [[25, 28], [70, 40], [300, 300], [1000, 1000]];

我对如何处理这个问题的想法是生成一个字典,将点映射到它与另一个点的最小距离(例如,靠近另一个点的点将具有较小的最小距离)然后对字典进行排序根据递增的最小距离,然后删除字典中的每个n&n tn项。

这种方法存在的问题是我不知道如何有效地为每个点生成到最近的其他点值的距离。

是否有一种有效的方法来生成这些值,或者是否有另一种方法来处理这种基于密度的细化问题?

谢谢!

3 个答案:

答案 0 :(得分:1)

您似乎想要解决P中心问题或P中位数问题。

来自Approximability Results for the p-Center Problem的Stefan Buettcher,

  

p - 中心问题,也称为Min-Max多中心问题   或设施位置问题,是一个着名的操作问题   研究。非正式地说,这是将消防局安置在一个地方的问题   城市,以便到达城市任何一点的最长时间   最小化。

来自J. Reese的Methods for Solving the p-Median Problem: An Annotated Bibliography

  

p - 中位数问题简单地表述为:给定图表或网络   G = (V, E),查找Vp ⊆ V |Vp| = p,其中p也可以   是可变的或固定的[...],以及最短距离的总和   从{V\Vp}中的顶点到Vp中最近的顶点是   最小化。

这两个问题一般都是NP完全的,因此没有(已知的)方法在多项式时间内解决它们。但是你可以尝试各种启发式方法。

答案 1 :(得分:1)

一个非常简单而有效的解决方案,在大型设备上运行得特别好,就是随机选择点。这隐含地从包含比其他地方更少的点的区域中移除更少的点 - 如果您只想线性地缩放密度,这似乎正是您想要的。它应该产生与您的方法相同的结果,而不需要计算任何距离。

如果没有以任何方式订购数据(即已经是随机的),您也可以每隔一秒或者只删除第一个或第二个。

如果你想非线性地调整密度分布,你可以把这个集合分成多个小的区域(例如正方形),使得每个区域的密度大致均匀,然后每隔n次下降一次。每个地区的积分。如果您选择适当的区域大小,这种方法也可能比较小的数据集上的纯随机方法提供更好(和更一致)的结果。

答案 2 :(得分:0)

您可以使用for..of循环,for循环,.map()Math.min().filter()

循环遍历数组的每个元素,将xy分配给单独的数组变量;减去xy数组中每个元素之间的差异;映射原始数组,首先删除匹配对的第一个或第二个元素,其中两个元素在数组中的任何其他数字之间具有最小的数值差异;也就是说,这两个数字之间用最少的数字分隔。随着数字之间的距离增加,继续删除元素,直到n,此处为3,元素从原始数组中删除。

例如,映射x可以返回

  [[25, 28], [70, 40], [300, 300], [1000, 1000]];

  [[26,26], [50,50], [285,350], [1000,1000]]

因为数字之间的范围在方向上相同

  [1, 1, 20, 20, 15, 15, 700]

var myPoints = [
  [25, 28],
  [26, 26],
  [70, 40],
  [50, 50],
  [300, 300],
  [285, 350],
  [1000, 1000]
];

var [x, y] = [
  [],
  []
];

var [xx, yy] = [
  [],
  []
 ];

for (let z of myPoints) {
  [x, y] = [
    [...x, z[0]],
    [...y, z[1]]
  ];
}

var stop = 3;

for (var i = 0; i < x.length; i++) {
  var prop = x[i];
  if (typeof xx[i] !== "object") {
    xx[i] = {
      index: i,
      diff: [],
      value: prop
    };
  }

  for (var len = 0; len < x.length; len++) {
    var key = x[len];
    xx[i].diff.push(
      prop > key 
      ? prop - key 
      : key > prop ? key - prop : Infinity
    )
  }
}

var range = xx.map(prop => Math.min.apply(Math, prop.diff));
var temp = range.slice(0);

for (var i = 0; i < stop; i++) {
  var curr = Math.min.apply(Math, temp);
  var index = temp.indexOf(curr);
  temp[index] = Infinity;
  var pair = Math.min.apply(Math, temp);
  var next = temp.indexOf(pair);
  temp[next] = Infinity;
  x[next] = void 0;
};

var res = myPoints.map((prop, index) => 
            x[index] === undefined ? null : prop).filter(Boolean);

console.log(res);

用作功能

var myPoints = [
  [25, 28],
  [26, 26],
  [70, 40],
  [50, 50],
  [300, 300],
  [285, 350],
  [1000, 1000]
];

var filter = (arr, xy, n) => {

  var [x, y] = [
    [],
    []
  ];

  var [xx, yy] = [
    [],
    []
  ];

  for (let z of arr) {
    [x, y] = [
      [...x, z[0]],
      [...y, z[1]]
    ];
  }

  var XY = {
    "x": [x, xx],
    "y": [y, yy]
  };

  var item = XY[xy];
  var stop = n;
  for (var i = 0; i < item[0].length; i++) {
    var prop = item[0][i];
    if (!item[1][i]) {
      item[1][i] = {
        index: i,
        diff: [],
        value: prop
      };
    }

    for (var len = 0; len < item[0].length; len++) {
      var key = item[0][len];
      item[1][i].diff.push(
        prop > key ? prop - key : key > prop ? key - prop : Infinity
      )
    }
  }
  
  var range = item[1].map(prop => Math.min.apply(Math, prop.diff));
  var temp = range.slice(0);

  for (var i = 0; i < stop; i++) {
    var curr = Math.min.apply(Math, temp);
    var index = temp.indexOf(curr);
    temp[index] = Infinity;
    var pair = Math.min.apply(Math, temp);
    var next = temp.indexOf(pair);
    temp[next] = Infinity;
    item[0][next] = void 0;
  };

  return arr.map((prop, index) => 
    item[0][index] === undefined ? null : prop).filter(Boolean);
}

console.log(filter(myPoints, "x", 3));