| 323 | # Calculate statistics. |
| 324 | |
| 325 | def statistics(data): |
| 326 | # NOTE(V8:10269): imports moved here to mitigate the outage. |
| 327 | import scipy |
| 328 | import scipy.stats |
| 329 | |
| 330 | N = len(data) |
| 331 | average = numpy.average(data) |
| 332 | median = numpy.median(data) |
| 333 | low = numpy.min(data) |
| 334 | high= numpy.max(data) |
| 335 | if N > 1: |
| 336 | # evaluate sample variance by setting delta degrees of freedom (ddof) to |
| 337 | # 1. The degree used in calculations is N - ddof |
| 338 | stddev = numpy.std(data, ddof=1) |
| 339 | # Get the endpoints of the range that contains 95% of the distribution |
| 340 | t_bounds = scipy.stats.t.interval(0.95, N-1) |
| 341 | #assert abs(t_bounds[0] + t_bounds[1]) < 1e-6 |
| 342 | # sum mean to the confidence interval |
| 343 | ci = { |
| 344 | 'abs': t_bounds[1] * stddev / sqrt(N), |
| 345 | 'low': average + t_bounds[0] * stddev / sqrt(N), |
| 346 | 'high': average + t_bounds[1] * stddev / sqrt(N) |
| 347 | } |
| 348 | else: |
| 349 | stddev = 0 |
| 350 | ci = { 'abs': 0, 'low': average, 'high': average } |
| 351 | if abs(stddev) > 0.0001 and abs(average) > 0.0001: |
| 352 | ci['perc'] = t_bounds[1] * stddev / sqrt(N) / average * 100 |
| 353 | else: |
| 354 | ci['perc'] = 0 |
| 355 | return { 'samples': N, 'average': average, 'median': median, |
| 356 | 'stddev': stddev, 'min': low, 'max': high, 'ci': ci } |
| 357 | |
| 358 | |
| 359 | def add_category_total(entries, groups, category_prefix): |