From 2a427e82d511a76808493da08b399973bd9aa399 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Thu, 17 Nov 2016 20:27:12 -0500 Subject: [PATCH] [GH75] Remove anomalies from data set * Modified the algorithm to exclude data points outside of the 5 times standard deviation range. * Excluding data points that took fewer than 5 minutes. * Made the longest and shortest more readble --- .../static/js/controllers/metricsCtrl.js | 15 +++++--- .../static/js/services/cycleTimeService.js | 29 ++++++++++----- lib/static/static/js/services/dateService.js | 36 +++++++++++++++---- lib/static/static/templates/metrics.html | 4 +-- 4 files changed, 64 insertions(+), 20 deletions(-) diff --git a/lib/static/static/js/controllers/metricsCtrl.js b/lib/static/static/js/controllers/metricsCtrl.js index 944145d..8d3d8a1 100644 --- a/lib/static/static/js/controllers/metricsCtrl.js +++ b/lib/static/static/js/controllers/metricsCtrl.js @@ -3,9 +3,9 @@ .module('huburn') .controller('metricsCtrl', metricsCtrl); - metricsCtrl.$inject = ['$routeParams', '$q', 'metricService', 'gitHubService', 'cycleTimeService']; + metricsCtrl.$inject = ['$routeParams', '$q', 'metricService', 'gitHubService', 'cycleTimeService', 'dateService']; - function metricsCtrl($routeParams, $q, metricService, gitHubService, cycleTimeService) { + function metricsCtrl($routeParams, $q, metricService, gitHubService, cycleTimeService, dateService) { var vm = this; vm.numberOfMilestones = 6; vm.currentMilestoneIssues = []; @@ -188,11 +188,18 @@ vm.showCycleTimes = function showCycleTimes() { vm.displayCycleTimes = 'flex'; vm.displayDistributions = 'none'; - } + }; vm.showDistributions = function showDistributions() { vm.displayCycleTimes = 'none'; vm.displayDistributions = 'flex'; - } + }; + + vm.getTimeInReadbleForm = function getTimeInReadbleForm(timeInDays) { + if (timeInDays < 0.25) + return dateService.daysToHours(timeInDays).toFixed(1) + " hours"; + + return timeInDays.toFixed(1) + " days"; + }; } }()); \ No newline at end of file diff --git a/lib/static/static/js/services/cycleTimeService.js b/lib/static/static/js/services/cycleTimeService.js index 512f5f5..c3def9d 100644 --- a/lib/static/static/js/services/cycleTimeService.js +++ b/lib/static/static/js/services/cycleTimeService.js @@ -117,7 +117,7 @@ var historicalInProgressCycles = getCycleTimesForColumn(issuesWithLabel, '2 - In Progress') .filter(hasValidCycleTime) .map(getCycleInDays) - .sort(sortCycles); + .sort(sortCycles); if (historicalInProgressCycles.length < 2) continue; @@ -127,16 +127,21 @@ .filter(hasValidCycleTime) .map(getCycleInDays); - var historicalInProgressCycleTimes = historicalInProgressCycles.map(getTimeFromCycle); - var mean = jStat.mean(historicalInProgressCycleTimes); - var standardDeviation = jStat.stdev(historicalInProgressCycleTimes); - maxValues.push(mean + (3 * standardDeviation)); + var mean = jStat.mean(historicalInProgressCycles.map(getTimeFromCycle)); + var standardDeviation = jStat.stdev(historicalInProgressCycles.map(getTimeFromCycle)); + var maxValue = mean + (3 * standardDeviation); + + historicalInProgressCycles = removeAnomalies(historicalInProgressCycles, standardDeviation, mean); + mean = jStat.mean(historicalInProgressCycles.map(getTimeFromCycle)); + standardDeviation = jStat.stdev(historicalInProgressCycles.map(getTimeFromCycle)); + maxValue = mean + (3 * standardDeviation); + maxValues.push(maxValue); statistics.push({ pointsLabel: pointsLabelsToRetrieve[i], - numberOfHistoricalItems: historicalInProgressCycleTimes.length, + numberOfHistoricalItems: historicalInProgressCycles.length, shortestDataPoint: historicalInProgressCycles[0], - longestDataPoint: historicalInProgressCycles[historicalInProgressCycleTimes.length - 1], + longestDataPoint: historicalInProgressCycles[historicalInProgressCycles.length - 1], dataPoints: currentInProgressTimes, mean: mean, standardDeviation: standardDeviation @@ -158,10 +163,18 @@ } function getCycleInDays(cycleTime) { - cycleTime.time = dateService.toDays(cycleTime.time); + cycleTime.time = dateService.toDaysNotRounded(cycleTime.time); return cycleTime; } + function removeAnomalies(cycles, standardDeviation, mean) { + return cycles.filter(function (cycle) { + return cycle.time > (mean - (5 * standardDeviation)) && + cycle.time < (mean + (5 * standardDeviation)) && + dateService.daysToMinutes(cycle.time) > 5; + }); + } + function sortCycles(cycleOne, cycleTwo) { return cycleOne.time - cycleTwo.time; } diff --git a/lib/static/static/js/services/dateService.js b/lib/static/static/js/services/dateService.js index a69d0d8..ca7cc7e 100644 --- a/lib/static/static/js/services/dateService.js +++ b/lib/static/static/js/services/dateService.js @@ -5,11 +5,18 @@ .factory('dateService', dateService); function dateService() { - + var hoursInADay = 24; + var minutesInAnHour = 60; + var secondsInAMinute = 60; + var millisecondsInASecond = 1000; + return { + daysToMinutes: daysToMinutes, + daysToHours: daysToHours, getTimeBetween: getTimeBetween, toHours: toHours, - toDays: toDays + toDays: toDays, + toDaysNotRounded: toDaysNotRounded }; function getTimeBetween(firstDate, secondDate) { @@ -17,13 +24,30 @@ } function toDays(timeInMilliseconds) { - var oneDay = 24*60*60*1000; // days*minutes*seconds*milliseconds - return round(timeInMilliseconds/oneDay); + var millisecondsInADay = hoursInADay * getMillisecondsInAnHour(); + return round(timeInMilliseconds / millisecondsInADay); + } + + function toDaysNotRounded(timeInMilliseconds) { + var millisecondsInADay = hoursInADay * getMillisecondsInAnHour(); + return timeInMilliseconds / millisecondsInADay; } function toHours(timeInMilliseconds) { - var oneHour = 60*60*1000; // hours*minutes*seconds*milliseconds - return round(timeInMilliseconds/oneHour); + var millisecondsInAnHour = minutesInAnHour * secondsInAMinute * millisecondsInASecond; + return round(timeInMilliseconds / millisecondsInAnHour); + } + + function daysToMinutes(timeInDays) { + return timeInDays * hoursInADay * minutesInAnHour; + } + + function daysToHours(timeInDays) { + return timeInDays * hoursInADay; + } + + function getMillisecondsInAnHour() { + return minutesInAnHour * secondsInAMinute * millisecondsInASecond; } function round(value) { diff --git a/lib/static/static/templates/metrics.html b/lib/static/static/templates/metrics.html index 2573669..5d536ab 100644 --- a/lib/static/static/templates/metrics.html +++ b/lib/static/static/templates/metrics.html @@ -103,8 +103,8 @@

{{ statistic.numberOfHistoricalItems }} historical issues, on average, spending {{ statistic.mean.toFixed(1) }} days in progress. - Longest: {{ statistic.longestDataPoint.issue.number }} - taking {{ statistic.longestDataPoint.time }} days, - Shortest: {{ statistic.shortestDataPoint.issue.number }} - taking {{ statistic.shortestDataPoint.time }} days + Longest: {{ statistic.longestDataPoint.issue.number }} - {{ vm.getTimeInReadbleForm(statistic.longestDataPoint.time) }}, + Shortest: {{ statistic.shortestDataPoint.issue.number }} - {{ vm.getTimeInReadbleForm(statistic.shortestDataPoint.time) }}