【问题标题】:Find 'average' with equal upper and lower distance to values of a given set找到与给定集合的值具有相等上下距离的“平均值”
【发布时间】:2017-04-02 21:23:01
【问题描述】:

我最近遇到以下情况 问题:

给定一组高度为 yᵢ 的点,求线的高度,其上点的平均距离等于线下点的平均距离:

更抽象的定义:给定一组实值数据点 Y = {y1, ..., yn},求 ȳ 将 Y 分成两个集合 Y⁺ = {y ∊ Y : y > ȳ} 和 Y⁻ = {y ∊ Y : y

朴素解决方案:用 Y 的平均值初始化 ȳ,计算平均上下距离,并根据上下平均距离是否更大而迭代地向上或向下移动。

问题:这个问题很基础,所以可能有更好的解决方案(?)甚至是非迭代代数算法?

【问题讨论】:

  • y坐标等于的点呢?这些不包括在您的集合 Y⁺ 和 Y⁻ 中,因此 ȳ 似乎将 Y 分成 三个 集合,其中一个似乎被忽略了。如果它们都包含在两组中,它们会改变平均距离。
  • @RoryDaulton 好点,任何解决方案都可以。因此,只要算法快速/简单,要么包含它们一个,要么包含它们,要么不包含它们。
  • 如果你知道哪些点在线的上方和下方,因为有间隙,那么就很简单了。但如果你不这样做,那么如果一个点在线上会发生什么?
  • 解决方案始终存在并不是 100% 清楚的。当一个点从直线下方移动到直线上方时,就会出现不连续性,这是平均跳跃的分母。另一种看待问题的方法是,如果它位于两个连续的 y 之间(这是一个简单的线性方程),您可以代数求解该点必须是什么,但我看不到任何证明结果的方法点至少位于这 2 个 y 之间。
  • @le_m 我已经说服自己这是真的,并且有一个证明的草图,但需要使它更严格。这个想法是连续候选y_bar之间的距离小于相应连续y之间的距离,因此如果y_bar在一个阶段高于两个连续y之间的间隔,它不能跳到下一对连续y之间的间隔下方。因此,中间值定理的一种离散模拟成立。但是,正如我所说,它还不严谨,我可能忽略了一些东西。

标签: algorithm math distance


【解决方案1】:

正如评论中提到的,如果你知道线的上方和下方有哪些点,那么你可以这样解决:

a = 直线上方的点数

b = 线下的点数

sa = 线上所有 y 的总和

sb = 线下所有 y 的总和

现在我们可以创建以下等式:

(sa - a * y) / a = (b * y - sb) / b              | * a * b
sa * b - a * b * y = a * b * y - a * sb          | + a * b * y + a * sb
sa * b + a * sb = 2 * a * b * y                  | / (2 * a * b)
==> y = (a * sb + b * sa) / (2 * a * b)
      = sa / (2 * a) + sb / (2 * b)
      = (sa / a + sb / b) / 2

如果我们解释结果,那么我们可以说它是线上方和下方点的平均值之间的平均值。

【讨论】:

  • 将您的答案与良好的初始估计和迭代更新相结合,与简单的解决方案相比,算法略有改进。
【解决方案2】:

基于maraca's answer的迭代解决方案:

用给定值的平均值初始化

  1. 将给定的值拆分高于低于的值。
  2. 计算此拆分的新的最优 ȳ。

重复直到 ȳ 收敛

这比问题中概述的算法略快。

// Find mean with equal average distance to upper and lower values:
function findEqualAverageDistanceMean(values) {
  let mean = values.reduce((a, b) => a + b) / values.length,
      last = NaN;

  // Iteratively equalize average distances:
  while (last != mean) {
    let lower_total = 0,
        lower_n = 0,
        upper_total = 0,
        upper_n = 0;

    for (let value of values) {
      if (value > mean) {
        upper_total += value;
        ++upper_n;
      } else if (value < mean) {
        lower_total += value;
        ++lower_n;
      }
    }
    last = mean;
    mean = (upper_total / upper_n + lower_total / lower_n) / 2;
  }
  return mean;
}

// Example:
let canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    points = Array.from({length: 100}, () => Math.random() ** 4),
    mean = points.reduce((a, b) => a + b) / points.length,
    equalAverageDistanceMean = findEqualAverageDistanceMean(points);

function draw(points, mean, equalAverageDistanceMean) {
  for (let [i, point] of points.entries()) {
    ctx.fillStyle = (point < equalAverageDistanceMean) ? 'red' : 'green';
    ctx.fillRect(i * canvas.width / points.length, canvas.height * point, 3, 3);
  }
  ctx.fillStyle = 'black';
  ctx.fillRect(0, canvas.height * mean, canvas.width, .5);
  ctx.fillRect(0, canvas.height * equalAverageDistanceMean, canvas.width, 3);
}

draw(points, mean, equalAverageDistanceMean);
&lt;canvas id="canvas" width="400" height="200"&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-12
    • 1970-01-01
    • 1970-01-01
    • 2014-01-22
    • 2012-02-09
    • 1970-01-01
    • 1970-01-01
    • 2015-08-26
    相关资源
    最近更新 更多