суббота, 4 июля 2015 г.

Метод оценки временных затрат на выполнение набора задач по историческим данным

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

Примеры, когда это может пригодиться:

- Задачи оценены в story point-ах, а требуется оценить сколько это будет в часах

- Есть оценки в задач часах, но предыдущие данные показывают, что такие оценки расходятся с реально потраченным временем и хотелось бы получить более точную оценку


Теперь сам метод. Итак, пусть у нас есть:

1) Исторические данные по задачам, где для каждой задачи есть:

     hei - её оценка
     hti - реально затраченное время

     Оценка и затраченное время могут быть как в разных единицах (например story point-ы и часы), так и в одинаковых (часы)

2) Некоторое множество задач, каждая из которых оценена в тех же единицах, что и в предыдущем пункте.


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

Шаг 1. Вначале сгруппируем и упорядочим исторические данные по значению оценки. Т.е получится несколько групп задач:

задачи с оценкой he1,
задачи с оценкой he2,
...
задачи с оценкой heK

hei < hei+1, 1 <= i < K

Шаг 2. Если есть группы, в которых меньше двух задач, объединим их со следующими в списке группами.

В результате получится такая структура групп задач:

G1 - задачи у которых оценка лежит в пределах от a1 до b1
G2 - задачи у которых оценка лежит в пределах от a1 до b2
...
GM - задачи у которых оценка лежит в пределах от aM до bM

bi < ai+1, 1 <= i < M

Шаг 3. Для каждой группы по множеству значений реально потраченного времени посчитаем 3 показателя:

Количество: mi
Среднее: Xi
Несмещенную выборочную дисперсию (экселевская функция VAR.S): Si2


Пример группировки, чтобы было понятно о чем я. Пусть есть таблица оценок задач и реальных значений времени выполнения:

ОценкаРеальное значение
22.5
33.5
21.5
56
88
65
43
67
32.5
1014
23.5


Группируем  строки по значению оценки:

ОценкаКоличествоРеальные значения
232.5, 1.5, 3.5
323.5, 2.5
413
516
625, 7
818
10114


Есть 4 строки, в которых количество значений меньше 2 (строки с оценкой 4, 5, 8 и 10). Начиная с начала таблицы, объединим такие строки со следующими в списке, чтобы это исправить:

ОценкаКоличествоРеальные значения
232.5, 1.5, 3.5
323.5, 2.5
4-523, 6
625, 7
8-1028, 14


Теперь посчитаем среднее и несмещенную дисперсию:

ОценкаКоличествоСреднееНесмещенная дисперсия
23(2.5+1.5+3.5)/3 = 2.5((2.5-2.5)2+(1.5-2.5)2+(3.5-2.5)2)/(3-1) = 1
32(3.5+2.5)/2 = 3((3.5-3)2+(2.5-3)2)/(2-1) = 0.5
4-52(3+6)/2 = 4.5((3-4.5)2+(6-4.5)2)/(2-1) = 4.5
62(5+7)/2 = 6((5-6)2+(7-6)2)/(2-1) = 2
8-102(8+14)/2 = 11((8-11)2+(14-11)2)/(2-1) = 18


Вернемся к теоретической части.

Шаг 4. Сгруппируем оценки новых задач по значению самой оценки. Т.е. получим данные такого типа:

k1 задач с оценкой e1
k2 задач с оценкой e2
...
kL задач с оценкой eL

ei < ei+1, 1 <= i < K

Шаг 5. Чтобы получить итоговую оценку соотнесем оценки новых задач с историческими данными. Для каждой группы новых задач из предыдущего шага находим группу из исторических данных (из шага 2), в которую попадает ее оценка. Если такой группы нет, то берем самую первую группу, у которой оценка больше (лучше переоценить задачу, чем недооценить). Если оценка выше, чем самая высокая оценка в таблице, отнесем ее к последней группе. В примере выше задачу с оценкой 3 отнесем ко второй группе, задачу с оценкой 3.5 - к третьей, задачу с оценкой 13 - к последней.

В результате этой процедуры получим N групп задач, которые нам нужно оценить, соотнесенное с историческими данными:

n1 задач, относящихся к группе из m1 исторических задач, в которой среднее X1 и дисперсия S12
n2 задач, относящихся к группе из m2 исторических задач, в которой среднее X2 и дисперсия S22
...
nN задач, относящихся к группе из mN исторических задач, в которой среднее XN и дисперсия SN2

тогда распределение суммарного времени E для этих задач будет приближенно описываться таким законом:


(1)


Ti(mi-1) - независимые случайные величины, имеющие распределение Стьюдента с mi-1 степенями свободы.

Недостаток этой формулы в том, что сложно дать интервальную оценку времени (т.е оценку типа "с вероятностью 90% на эти задачи уйдет от 100 до 130 часов"). Нужны некоторые навыки программирования, чтобы смоделировать это распределение. Формула может быть полезна программистам, разрабатывающим софт для управления проектами, но для быстрого практического применения ее придется упростить.

Здесь нам помогут 2 фактора:

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

Поэтому для приближения заменим каждое из распределений Стьюдента в формуле (X) на нормальное распределение с той же дисперсией. В итоге получим, что распределение оценки приближается нормальным распределением с математическим ожиданием:


(2)


и дисперсией:


(3)


где

S2n, i - выборочная дисперсия (экселевская функция VAR.P) i-ой соответствующей группы исторических данных. Т.е в упрощенной формуле на шаге 3 будет считаться именно выборочная дисперсия.

Здесь стоит заметить, что распределение Стьюдента с n степенями свободы имеет дисперсию только при n >= 3. Поэтому для работы приближенной формулы необходимо, чтобы количество элементов в каждой группе исторических данных было не менее 4. В этом случае шаг 2 меняется следующим образом:

Если группа содержит меньше 4 элементов, объединяем ее с последующей. Если последняя группа содержит меньше 4 элементов, обїединяем ее с предпоследней. Повторяем до тех пор, пока каждая группа не будет содержать не менее 4 элементов. Очевидно, что эта процедура может быть выполнена, если в исторических данных есть не менее 4 оценок.


Небольшое дополнение, позволяющее автоматизировать расчеты. Если исторические данные хранятся в SQL-базе данных, то группировку можно осуществлять SQL-запросом.

Если например они находятся в таблице HistoricalData со столбцами с именами Estimate и Time,
то предварительные данные для расчета среднего и дисперсии можно получить таким запросом:



SELECT [Estimate]COUNT(1) AS [Count],
SUM([Time]) AS [Sum],
SUM([Time][Time]) AS [SumOfSquares]
FROM [HistoricalData]
GROUP BY [Estimate] ORDER BY [Estimate]
(4)


При объединении групп (шаг 2) суммируются количества (столбец Count) и суммы (Sum и SumOfSquares).

После этого среднее и дисперсии в i-ой строке таблицы считаются по таким формулам:



Xi = Sumi/Counti (5)



Sn,i2 = (SumOfSquaresi - Sumi2)/Counti (6)



Si2 = (SumOfSquaresi - Sumi2)/(Counti-1) (7)


Пример расчета оценки с пошаговым разбором

Пусть есть такой набор исторических данных (левая таблица) и набор оценок задач (список справа):

ОценкаРеальное значение
1628
11
33
11
84
811
105
22
614
30.5
14
11
55
55
1212
54
10.5
810
20.5
813
1622
46
12.5
11.5
47
412
88.5
66
1212
44
1211
11
63.5
56
87
1211
536
813.5
12
1212
20.5
36.5
64
35.5
11
43.5
33
35
31
1024.5
39
33
15
34
32
89.5
12.5
45.5
55
25
88
48.5
11
15
22
31
51.5
11
24
22
11
45
26
41
44
11
1214
1212
22
1616
33
34.5
55
67
64
45
86
1211
33
65
32
53
44
22
31
213
63
820.5
60.5
44
66
44
129.5
511
44
62
88.5
22
66.5
88
66
22
43
626.5
1027
82
45.5
88
88
316
32
32.5
11
22
22
68
55
22
56.5
513.5
1619
1818
66
826
815
66
611
33
1617
1016
1320
22
12
72
1117.5
411
42
88
1312
41
20.5
34
824
88
1313
22
33
44
86
64
34
11
33
4, 4, 3, 5, 4, 5, 15, 5, 12, 3, 4, 2, 3, 1, 4, 4, 8, 4, 3, 1, 2, 3, 8, 8, 3, 8, 8, 4, 8, 1, 1, 16, 5, 3, 5, 6, 2


Дадим интервальную оценку времени, которое будет затрачено на выполнение задач справа

Шаг 1. Группируем исторические данные, считая количество сумму и сумму квадратов реальных значений (я здесь воспользовался SQL-запросом (4))

ОценкаКоличествоСуммаСумма квадратов
12036100
21953.5294.75
32594.5596.25
421104672
513106.51829.75
6191291453
7124
822232.53229.25
10472.51610.25
11117.5306.25
129104.51225.25
13345713
1651022174
18118324


Шаг 2. Идем по таблице сверху вниз и объединяем каждую строку, в которой количество меньше 4 со следующей, при этом суммируя значения в столбцах Количество, Сумма и Сумма квадратов.

ОценкаКоличествоСуммаСумма квадратов
12036100
21953.5294.75
32594.5596.25
421104672
513106.51829.75
6191291453
7124
822232.53229.25
10472.51610.25
11117.5306.25
129104.51225.25
13345713
1651022174
18118324

Строку с оценкой 7 объединим со строкой с оценкой 8

ОценкаКоличествоСуммаСумма квадратов
12036100
21953.5294.75
32594.5596.25
421104672
513106.51829.75
6191291453
7 - 823234.53233.25
10472.51610.25
11117.5306.25
129104.51225.25
13345713
1651022174
18118324

Строку с оценкой 11 объединим со строкой с оценкой 12

ОценкаКоличествоСуммаСумма квадратов
12036100
21953.5294.75
32594.5596.25
421104672
513106.51829.75
6191291453
7 - 823234.53233.25
10472.51610.25
11 - 12101221531.5
13345713
1651022174
18118324

Строку с оценкой 13 объединим со строкой с оценкой 16

ОценкаКоличествоСуммаСумма квадратов
12036100
21953.5294.75
32594.5596.25
421104672
513106.51829.75
6191291453
7 - 823234.53233.25
10472.51610.25
11 - 12101221531.5
13 - 1681472887
18118324

В последней строке с оценкой 18 количество тоже меньше 4, но поскольку для нее нет следующей строки, объединим ее с предыдущей:

ОценкаКоличествоСуммаСумма квадратов
12036100
21953.5294.75
32594.5596.25
421104672
513106.51829.75
6191291453
7 - 823234.53233.25
10472.51610.25
11 - 12101221531.5
13 - 1891653211


Шаг 3. Считаем среднее и выборочную дисперсию в каждой группе:

ОценкаКоличествоСуммаСумма квадратовСреднее Выборочная дисперсия
1203610036/20 = 1.8100/20 - 1.82 = 1.76
21953.5294.7553.5/19 = 2.815789474294.75/19 - 2.8157894742 = 7.584487535
32594.5596.2594.5/25 = 3.78596.25/25 - 3.782 = 9.5616
421104672104/21 = 4.952380952672/21 - 4.9523809522 = 7.473922902
513106.51829.75106.5/13 = 8.1923076921829.75/13 - 8.1923076922 = 73.63609467
6191291453129/19 = 6.7894736841453/19 - 6.7894736842 = 30.3767313
7 - 823234.53233.25234.5/23 = 10.195652173233.25/23 - 10.195652172 = 36.62476371
10472.51610.2572.5/4 = 18.1251610.25/4 - 18.1252 = 74.046875
11 - 12101221531.5122/10 = 12.21531.5/10 - 12.22 = 4.31
13 - 1891653211165/9 = 18.333333333211/9 - 18.333333332 = 20.66666667


Шаг 4. Группируем оценки новых задач. Напомню список:

4, 4, 3, 5, 4, 5, 15, 5, 12, 3, 4, 2, 3, 1, 4, 4, 8, 4, 3, 1, 2, 3, 8, 8,  3, 8, 8, 4, 8, 1, 1, 16, 5, 3, 5, 6, 2

Если сгруппировать, получится такая таблица:

ОценкаКоличество
14
23
37
48
55
61
86
121
131
161


Шаг 5. Сопоставляем группы исторических данных (слева) и новых задач (справа):

ОценкаКоличествоСреднее Выборочная дисперсия
1201.81.76
2192.8157894747.584487535
3253.789.5616
4214.9523809527.473922902
5138.19230769273.63609467
6196.78947368430.3767313
7 - 82310.1956521736.62476371
10418.12574.046875
11 - 121012.24.31
13 - 18918.3333333320.66666667
ОценкаКоличество
14
23
37
48
55
61
86
121
131
161

Соответствующие группы выделены одинаковыми цветами

Теперь объединяем соответствующие строки 2 таблиц, группируя строки правой, если нужно (например последние две):

ОценкаКоличество (mi)Среднее (Xi) Выборочная дисперсия (S2n, i)Количество (ni)
1201.81.764
2192.8157894747.5844875353
3253.789.56167
4214.9523809527.4739229028
5138.19230769273.636094675
6196.78947368430.37673131
7 - 82310.1956521736.624763716
11 - 121012.24.311
13 - 18918.3333333320.666666672

Далее, по формулам (2) и (3) получаем:

M[E] = 239.5180079

σ2 = 1336.791715

т.е

σ = 36.56216233

Чтобы получить интервальную оценку, используем таблицу квантилей нормального распределения. С 90% вероятностью значение нормально распределенной случайной величины E лежит в пределах M[E]±1,645σ

Таким образом с вероятностью 90% можно утверждать, что время потраченное на планируемые задачи лежит в пределах от  239.5180079-1,645*36.56216233 ≈ 179.37 до 239.5180079+1,645*36.56216233 ≈ 299.66 часов.


Практические выводы из расчетов:

Вывод 1. Формула (3) подтверждает практический совет: при планировании задач ставить буфер в конце цикла, а не локально в каждую задачу/требование.

Вывод 2. Исторические данные естественно лучше обновлять по мере работы над проектом. А именно, сделанные задачи пополняют множество исторических данных. И вот тут полезно использовать таблицу, полученную после первичной группировки на шаге 1. Сделанные задачи обновляют строки этой таблицы (увеличивая количество, сумму или сумму квадратов) или вставляют новые. Таким образом исторические данные могут считаются "кумулятивно", что позволяет не выполнять полную обработку всей истории каждый раз, когда нужно оценить новый набор задач. Достаточно один раз получить небольшую таблицу и обновлять ее по мере накопления исторических данных.

Вывод 3. Задачи с большими оценками вносят значительный вклад в погрешность общей оценки. Из формулы (3) видны 2 причины этого:
  1. Большое значение S2n, i. Это понятно, так как при оценке больших задач и погрешность оценки больше. 
  2. Небольшое количество таких задач mi в исторических данных

Поэтому при оценках больших задач лучше разбивать их на задачи поменьше. Сама процедура разбиения помогает понять, что же нужно сделать в задаче и уточнить оценку просто за счет того, что уменьшается вероятность упустить какую-то часть задачи, на которую не обратили внимание при более поверхностной оценке.



Комментариев нет: