Теория вероятностей в действии 2.0 (web приложение для корректировки прогнозов разработчиков)

—

от автора

Раз в несколько лет возвращаюсь к задаче создания алгоритма для наиболее вероятного прогноза на основании ошибок предыдущих прогнозов. В этот раз попробую обойтись минимумом текста (ссылка на демо в конце).

Ссылка на оригинал статьи с объяснением принципа Доказательного Планирования (в оригинале Evidence Based Scheduling) — советую ознакомиться, чтоб быть в контексте.

Версия 1.0: Первый блин в коме (2019)

Как я видел решение этой задачи 5 лет назад (здесь очевидная ошибка): Берем самый худший вариант из предыдущего опыта и проецируем на текущую задачу — это и будет мой прогноз для Продукт Менеджера 😠.

Версия 2.0: Кажется, это успех (2024)

К примеру, у разработчика (исполнителя) есть несколько решенных задач с параметрами:

  1. Дата начала выполнения задачи (start)

  2. Дата его оценки финиша (estimation)

  3. Дата реального финиша (finish)

Итак, добавлена новая задача, получен estimation от разраба. Теперь вопрос — насколько он ошибся?

Алгоритм расчета наиболее худшего сценария: Берем скорость самой неудачной задачи этого разработчика и вычисляем дату окончания текущей задачи.

💥 Алгоритм поиска наиболее вероятного сценария: Думаю, всем очевидно, что скорость «среднюю по больнице» брать — это неточно. Поэтому логика следующая: Человек работает, как правило, [плюс-минус] с одной скоростью — алгоритм должен ее «ощутить». Как именно: если среди возможных вариантов скоростей его работы встречаются два с минимальным отклонением — это повод искать ещё варианты с примерно таким же отклонением. В итоге, найденные варианты образуют «скопления», среднее значение которых можно учитывать как наиболее вероятное (поправьте в комментариях, если я неправ):

// NOTE: 1. Отсортированный список скоростей выполнения задач const sortedSpeeds: { v: number }[] = speeds.sort((e1, e2) => e1.v - e2.v)  // NOTE: 2. Список отклонений между этими скоростями const deltas: {   value: number | null;   delta: number | null;   prev: number | null;   next: number | null;   isSensed: boolean; // Это тот самый показатель "чувствительности" }[] = [] let minDelta = 1000000 let maxDelta = 0    for (let i = 0, max = sortedSpeeds.length; i < max; i++) {   const prevValue = !!sortedSpeeds[i - 1] ? sortedSpeeds[i - 1] : null   const nextValue = !!sortedSpeeds[i + 1] ? sortedSpeeds[i + 1] : null   const currentValue = sortedSpeeds[i]   const delta = typeof prevValue?.v === 'number'     ? currentValue.v - (prevValue.v)     : null   deltas.push({     value: sortedSpeeds[i].v,     delta, next: nextValue?.v || null,     prev: prevValue?.v || null,     isSensed: false, // by default   })    if (typeof delta === 'number') {     if (minDelta >= delta) minDelta = delta     if (maxDelta <= delta) maxDelta = delta   } }  // NOTE: 3. Оставим только скорости с минимальным отклонением друг от друга // Коэфф sensibility нужен для большего охвата задач, когда их немного (я беру 4) // По мере роста задач коэфф. sensibility можно уменьшать до значения 1-2 const sensed: {   counter: number;   speedValues: number[];   averageSpeed: number; } = {   counter: 0,   speedValues: [],   averageSpeed: 0, } for (let i = 0, max = deltas.length; i< max; i++) {   if ((deltas[i].delta as number) <= sensibility * minDelta) {     deltas[i].isSensed = true     if (typeof deltas[i].value === 'number') {       sensed.counter += 1       sensed.speedValues.push((deltas[i].value as number))     }   }   else     deltas[i].isSensed = false }  // NOTE: 4. Все! Теперь наиболее вероятная дата финиша // может быть расчитана в соответствии с наиболее вероятной скоростью: sensed.averageSpeed = getArithmeticalMean(sensed.speedValues)

Попробовать живьем


ссылка на оригинал статьи https://habr.com/ru/articles/874226/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *