Как найти процентное значение, представляющее, насколько два массива различны? - PullRequest
8 голосов
/ 08 мая 2019

У меня есть два массива.

Я хочу процентное значение, которое описывает, насколько их значения различны.Я пытаюсь использовать 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

Предположим, у вас есть три набора данных:

enter image description here

Красная линия представляет реальные данные, пунктирная зеленая линия представляетданные прогноза, созданные пользователем (тест 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]

Почему?

Ответы [ 3 ]

1 голос
/ 13 мая 2019

Ну, это зависит от , означающего , равного 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
1 голос
/ 13 мая 2019

Глупый, но практический подход заключается в том, чтобы просто учитывать погрешность, вычисляемую любым расстоянием, которое вам нравится между вашей выборкой и вашим прогнозом. (норма1, норма2, что угодно)

затем сопоставьте полученное значение с интервалом [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)
1 голос
/ 08 мая 2019

Я думаю, что мера, которую вы ищете, на самом деле 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;


}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...