Рассчитать стандартное отклонение (σ) от предыдущего и нового элемента (накопительное / инкрементальное SD) - PullRequest
2 голосов
/ 22 июня 2019

Текущий процесс проверяется, где следующие числа вычисляются «кумулятивно» (из предыдущих значений + новый элемент):

  • Минимальная продолжительность
  • Максимальная продолжительность
  • Средняя продолжительность

Стандартное отклонение (σ) продолжительности также должно рассчитываться, поскольку оно указывает на статистическая дисперсия .

В зависимости от приложения неудобно хранить каждый элемент / число, поэтому необходимо рассчитать его относительно предыдущего значения и нового элемента.

Пример:

NewElement  Min  Max  Avg  StdDev           // AllElements (which are NOT meant to be stored)
1           1    1    1    -                   [1]
2           1    2    1.5  0.5                 [1,2]
3           1    3    2    0.8164965809277     [1,2,3]
4           1    4    2.5  1.1180339887499     [1,2,3,4]
0           0    4    2    1.4142135623731     [1,2,3,4,0]

это онлайн калькулятор SD для справочных значений)

Упрощенная версия цели будет выглядеть так:

const calculateNewStats = (stats, newElement) => {
  const newStats = {};
  newStats.count = stats.count + 1;
  newStats.min = Math.min(stats.min, newElement);
  newStats.max = Math.max(stats.max, newElement);
  newStats.avg = (stats.avg * stats.count + newElement) / newStats.count;

  // newStats.sd = ??? that's the problem

  return newStats;
};

// initial values
let stats = {
  count: 0,
  min: 0,
  max: 0,
  avg: 0,
  // initial SD is theoretically controversial (N/A), but that's not the point
  sd: 0,
};

// loopStart goes here ... an infinite one

    // many things goes here ... eventually, we have a `newElement`

    stats = calculateNewStats(stats, newElement);

// loopEnd goes here

В течение некоторого времени проводился поиск, некоторые математические уравнения (например, this ) были найдены и тщательно применены, но полученные числа были неверными.

1 Ответ

2 голосов
/ 22 июня 2019

Алгоритм на странице, на которую вы ссылаетесь , работает, вот рабочая реализация:

const calculateNewStats = (stats, newElement) => {
  const newStats = {};

  newStats.count = stats.count + 1;
  newStats.min = Math.min(stats.min, newElement);
  newStats.max = Math.max(stats.max, newElement);
  newStats.avg = (stats.avg * stats.count + newElement) / newStats.count;

  newStats.sd = Math.sqrt(
    (
      (newStats.count - 1) * stats.sd * stats.sd +
      (newElement - newStats.avg) * (newElement - stats.avg)
    ) / (newStats.count)
  );

  return newStats;
};

// initial values
let stats = {
  count: 0,
  min: 0,
  max: 0,
  avg: 0,
  sd: 0
};

let newElements = [1, 2, 3, 4, 0];

for (let newElement of newElements) {
  stats = calculateNewStats(stats, newElement);
  console.log(stats);
}

Результат на JSBin

Может быть, вы пропустили последнее предложение?

Если вы хотите, чтобы популяционная дисперсия или стандартное отклонение заменили N-1 на N и N-2 на N-1.


Примечание: будет небольшая потеря точности, которая будет увеличиваться по мере добавления элементов. Я бы посоветовал:

  • сохранить дисперсию в stats вместе с sd; сейчас я вычисляю квадратный корень из дисперсии, чтобы получить SD, затем возводя в квадрат SD, чтобы получить дисперсию в следующей итерации
  • хранить общее значение в stats, вместо того, чтобы пересчитывать его с stats.avg * stats.count на каждой итерации

Вы храните еще 2 числа в stats, но вы должны получить более точные цифры.

Это лучшая реализация:

const calculateNewStats = (stats, newElement) => {
  const newStats = {};
  newStats.count = stats.count + 1;
  newStats.total = stats.total + newElement;
  newStats.min = Math.min(stats.min, newElement);
  newStats.max = Math.max(stats.max, newElement);
  newStats.avg = (stats.total + newElement) / newStats.count;

  newStats.variance = (
    (newStats.count - 1) * stats.variance +
    (newElement - newStats.avg) * (newElement - stats.avg)
  ) / (newStats.count);

  newStats.sd = Math.sqrt(newStats.variance);

  return newStats;
};

// initial values
let stats = {
  count: 0,
  total: 0,
  min: 0,
  max: 0,
  avg: 0,
  sd: 0,
  variance: 0
};

let newElements = [1, 2, 3, 4, 0];

for (let newElement of newElements) {
  stats = calculateNewStats(stats, newElement);
  console.log(stats);
}

JSBin

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