【问题标题】:How to find a precent value that represents how much two arrays are different?如何找到表示两个数组不同的百分比值?
【发布时间】:2019-05-08 13:46:11
【问题描述】:

我有两个数组。

我想要一个百分比值来描述它们的值有多少不同。 我尝试使用 MSE 和 RMSE:

/**
* Mean Squared Error
*    MSE = (1/n) * Ʃ[(r - p)^2]}
*/
export function computeMse(a, b) {
  const size = a.length
  let error = 0
  for (let i = 0; i < size; i++) {
    error += Math.pow(b[i] - a[i], 2)
  }
  return (1 / size) * error
}

/**
* Root Mean Squared Error
*    RMSE = √MSE
*/
export function computeRmse(a, b) {
  return Math.sqrt(computeMse(a, b))
}

和:

const a = [2354493, 2615706, 1594281, 1570894, 1930709, 2086681]
const b = [2354493, 2224360.55, 1906806.9, 1408769.93, 1609053.96, 2200698.72]

const mse = computeMse(a, b)
const rmse = computeRmse(a, b)

结果是:

mse:  65594986451.87959
rmse:  256115.18200192583

我不认为这个结果是正确的。 首先,mse 和 rmse 不在 [0, 100] 范围内,然后即使两个数组相差不大,也是非常大的值。

我错了吗?


我也试试:

export function computeMape(actual, forecast) {
  const size = actual.length
  let error = 0
  for (let i = 0; i < size; i++) {
    error += Math.abs((actual[i] - forecast[i]) / actual[i])
  }
  return (100 * error) / size
}

与:

const a = [77, 50, 38, 30, 26, 18] 
const b = [77, 81.13, 92.77, 101.98, 119.76, 121.26]

我得到mape: 230.10116059379217...

另一个例子:

const a = [1.15, 1.09, 1.08, 0.78, 0.51, 0.44]
const b = [1.15, 1.61, 1.88, 2.13, 2.3, 2.47]

const mape = computeMape(a, b) // result: 184.53357461497413

假设你有这三个数据集:

红线表示真实数据,绿色虚线表示用户创建的预测数据(测试1),灰色虚线表示用户创建的预测数据(测试2)。事实上,用户可以尝试不同的时间来点击真实数据(就像游戏一样)。

现在我想向用户返回一个反馈,告诉用户他以百分比的形式猜测数据趋势有多么错误。

用户可以做出许多预测。我想要一个百分比数字来告诉我用户错了多少,以便比较每次尝试。

这样的可能吗?


同样在这种情况下,我得到 NaN 结果:

const a = [132.6, 114.1, 134.5, 124.5, 144.4, 162.4]
const b = [132.6, 134.15, 134.15, 134.15, 139.19]

为什么?

【问题讨论】:

  • 我上一条评论出了点问题,所以重复一遍:看看here: MAPE 可能超过 100,如果值显着不同。您也可以使用 SMAPE,这可能是您正在寻找的更多内容 - 请参阅 here
  • 另外,这不是真正的编码问题,因为您的代码很好。这更像是一个统计问题,您可能会发现最好在stats.stackexchange.com 上询问最适合使用的统计数据。

标签: javascript statistics mse


【解决方案1】:

我猜你正在寻找的度量实际上是 MPE 而不是 MSE。

function mpe(a, f) {
    let size = a.length, sum = 0;
    for (let i = 0; i < size; i++) {
        sum += (a[i] - f[i]) / a[i];
    }
    return 100 * sum / size;
}


// small demo

forecast = [10, 20, 30]
actual   = [10, 20, 30]

for(i = 0; i < 20; i++) {
    console.log(actual.join() + ' mpe ' + mpe(actual, forecast).toFixed(1) + '%')
    actual[i % 3] += 10;


}

【讨论】:

  • @beth:添加Math.abs 然后:en.wikipedia.org/wiki/Mean_absolute_percentage_error。还可以点击其中的链接,找出您所追求的确切测量值。
  • 我正在编辑我的主代码,你能帮帮我吗?我觉得有点傻
  • @beth:您的代码似乎是正确的。如果实际值大于预测 x 2,则 MAPE 可以大于 100%
  • 嗯好的。如何将其转换为百分比值?
  • @beth:假设你转换它并且它返回说 87%。你会如何解释? 87% 什么?
【解决方案2】:

嗯,这取决于100%的含义。如果 100%(在您的情况下)是与实际数据的最大可能偏差,那么您必须在输出中定义一些 限制

例如,试试:

function computeError(obj) {
  let size = obj.actual.length;
  let maxErr = obj.limits[1] - obj.limits[0];
  let error = 0;
  let i;
  
  for (i = 0; i < size; i++) {
    error += Math.abs((obj.actual[i] - obj.forecast[i]) / maxErr);
  }
  
  console.log( ((100 * error) / size).toFixed(3), '%' );
}

const testCases = [
  {
    actual: [2354493, 2615706, 1594281, 1570894, 1930709, 2086681],
    forecast: [2354493, 2224360.55, 1906806.9, 1408769.93, 1609053.96, 2200698.72],
    limits: [0, 5e6] // [0, 5000000]
  },
  {
    actual: [77, 50, 38, 30, 26, 18],
    forecast: [77, 81.13, 92.77, 101.98, 119.76, 121.26],
    limits: [0, 2e2] // [0, 200]
  },
  {
    actual: [1.15, 1.09, 1.08, 0.78, 0.51, 0.44],
    forecast: [1.15, 1.61, 1.88, 2.13, 2.3, 2.47],
    limits: [0, 3e0] // [0, 3]
  },
  
  // extra cases
  {
    actual: [0, 0, 0],
    forecast: [1, 1, 1],
    limits: [0, 1e0]
  },
  {
    actual: [1, 1, 1],
    forecast: [1, 1, 1],
    limits: [0, 1e9]
  }
]; 

testCases.forEach(computeError); // calls computeError function on each object

【讨论】:

    【解决方案3】:

    一种愚蠢但实用的方法是简单地考虑误差,根据您喜欢的样本和预测之间的距离计算 (norm1, norm2, 随便)

    然后通过您选择的函数将结果值映射到区间 [0;1](实现 f:[0; infty]->[0;1])

    例如:

    f(err) = e^(-x^2/a^2) with a of your choice
    

    在您的代码中,可能类似于

    var err = computeMse(a,b)
    function toPercent(err){
        const a = 1;
        return Math.exp(-x*x/a*a);
    }
    var percent = toPercent(err)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-23
      • 2019-08-18
      • 2020-12-15
      • 2023-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多