-
-
Save pavelpower/4c22b470f1e78030802963d61ae6b8e1 to your computer and use it in GitHub Desktop.
Метод-Монте Карло для расчета вероятности срока решения проекта на основе пропускной способности по задачам и количеству задач в проекте. В модель добавлена возможное наступление рисков, которые могут добавить или убавить количество задач к проекту
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Данные по пропускной способности по итерациям времени | |
// итерация - минимальная единица времени в которой хотим считать | |
// длительность проекта | |
const historicalDataThroughput = [ | |
4, 1, 2, 1, 4, 3, 2, 3, 2, 3, 6, | |
3, 2, 1, 6, 13, 3, 1, 6, 1, 2, | |
4, 4, 6, 3, 1, 3, 3, 6, 6, 2, | |
6, 2, 1 | |
]; | |
// количество задач в проекте | |
const countTaskInProject = 40; | |
// Риски которые могут случится с какой-то вероятностью | |
// И добавить новых задач к проекту | |
// Предполагаем что риск может сработать один раз | |
const risks = [ | |
// С вероятностью "probability" наступления риска, к проекту добавится от "min" до "max" задач | |
{ probability: 2, countTask: { min: 10, max: 15 } }, | |
{ probability: 12, countTask: { min: 2, max: 20 } }, | |
{ probability: 5, countTask: { min: 5, max: 12 } }, | |
{ probability: 4, countTask: { min: -8, max: -2 } }, | |
] | |
// Выполнить функцию Монте-Карло и получить результат | |
const result = MonteCarloForProject( | |
historicalDataThroughput, | |
countTaskInProject, | |
risks, | |
10000 | |
); | |
// Показать результат в консоли | |
console.table(result); | |
/** | |
* Получить распределение вероятности завершения проекта | |
* на основе количества решаемых задач за итерацию | |
* | |
* @param {Array<Number>} historicalDataThroughput Набор испторических данных по пропускной способности | |
* @param {Number} countTaskInProject Количество задач в проекте | |
* @param {Array<{probability: Number, countNewTasks: Number}>} risks Риски | |
* @param {Number} numberOfExperiments Количество проводимх эксперимантов | |
* @returns {Array<Number, Number>} key - количество фич в итерации, value - частота | |
*/ | |
function MonteCarloForProject( | |
historicalDataThroughput, | |
countTaskInProject, | |
risks, | |
numberOfExperiments | |
) { | |
const result = new Map(); | |
const len = historicalDataThroughput.length | |
let experiment = 1; | |
for (; experiment <= numberOfExperiments; experiment++) { | |
let prjTasks = countTaskInProject; | |
// Перебираем все риски | |
risks.forEach(r => { | |
let randomForRisk = getRandomBetween(1, 100); | |
// Если сгенерированное число меньше чем указанный процент вероятности, | |
// считаем что риск случился | |
if (r.probability > randomForRisk) { | |
// Выбираем случайное количество задач между min и max указанное в риске | |
let countTasks = getRandomBetween(r.min, r.max); | |
// Добавялем их к проекту | |
prjTasks += countTasks; | |
} | |
}); | |
let IndexIteration = 0; | |
while (prjTasks > 0) { | |
// Выбираем случайное число из набора Throughput | |
let randomIndex = Math.floor(Math.random() * len); | |
// Получаем какое количество задач нужно отнять в эту неделю | |
let countTasks = historicalDataThroughput[randomIndex]; | |
// Отнимаем это количество задач | |
prjTasks = prjTasks - countTasks; | |
// Переходим к следующей итерации | |
IndexIteration += 1; | |
} | |
// Фиксируем какая итерация получилась | |
let i = result.get(IndexIteration); | |
result.set(IndexIteration, i ? i + 1 : 1); | |
} | |
let sum = 0; | |
// Готовим данные к показу результата | |
return Array.from(result, ([name, value]) => ({ iteration: name, count: value })) | |
.sort((a, b) => a.iteration - b.iteration) | |
.map((i) => { | |
sum += i.count; | |
return { | |
...i, | |
probability: sum / numberOfExperiments | |
} | |
}) | |
} | |
function getRandomBetween(min, max) { | |
return Math.floor(Math.random() * (max - min + 1)) + min; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment