From 75d7d1f0bfb072b7df3e2e8b6e510d9b3e10401a Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Thu, 2 Jun 2016 13:00:01 -0400 Subject: [PATCH 1/2] [ci] add npm test command --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index fd238ec..7ecaf01 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "author": "Angus Gibbs (http://angusgibbs.com)", "homepage": "http://github.com/angusgibbs/statsjs", "keywords": ["math", "stats", "statistics", "average", "mean", "min", "max", "standard", "deviation", "regression", "quartile", "median", "outliers", "factorial", "probability", "permutation", "combination", "binomial", "geometric", "normal", "z-test"], + "scripts": { + "test": "mocha test/*.js" + }, "repository": { "type": "git", "url": "git://github.com/angusgibbs/statsjs.git" @@ -23,4 +26,4 @@ "mocha": "1.4.x", "expect.js": "git://github.com/angusgibbs/expect.js.git" } -} \ No newline at end of file +} From 2f6ba831875fa6d1711d0557e6cd2c88e50bd6a8 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Thu, 2 Jun 2016 13:12:24 -0400 Subject: [PATCH 2/2] [stats] add support for returning arbitrary quantiles --- lib/stats.js | 34 ++++++++++++++++++++++++---------- test/test.js | 10 ++++++++++ 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/lib/stats.js b/lib/stats.js index c875a34..8207a9a 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -169,26 +169,40 @@ } }, - // Finds the first quartile of the numbers. + // Finds a quantile with the given ratio // - // Returns the first quartile. - q1: function() { + // Returns that quantile. + quantile: function(ratio) { // Sort the numbers var nums = this.clone().sort(); + var arr = nums.arr; + + // 0 and 1 are bounds; clamp to them + if (ratio <= 0.0) return arr[0]; + if (ratio >= 1.0) return arr[arr.length - 1]; + + // Determine which index represents the quantile, + // averaging if it falls on a boundary + var idx = (ratio * arr.length) - 1; + if (idx === Math.floor(idx)) { + return 0.5 * (arr[idx] + arr[idx + 1]); + } else { + return arr[Math.ceil(idx)]; + } + }, - // The first quartile is the median of the lower half of the numbers - return nums.slice(0, Math.floor(nums.size() / 2)).median(); + // Finds the first quartile of the numbers. + // + // Returns the first quartile. + q1: function() { + return this.quantile(0.25); }, // Finds the third quartile of the numbers. // // Returns the third quartile. q3: function() { - // Sort the numbers - var nums = this.clone().sort(); - - // The third quartile is the median of the upper half of the numbers - return nums.slice(Math.ceil(nums.size() / 2)).median(); + return this.quantile(0.75); }, // Finds the interquartile range of the data set. diff --git a/test/test.js b/test/test.js index 03baea9..df0d73e 100644 --- a/test/test.js +++ b/test/test.js @@ -30,6 +30,16 @@ describe('#median()', function() { }); }); +describe('#quantile()', function () { + it('should return the proper median and quantiles', function() { + expect(stats([3, 4, 4, 5, 6, 8, 9]).quantile(0)).to.equal(3); + expect(stats([3, 4, 4, 5, 6, 8, 9]).quantile(0.25)).to.equal(4); + expect(stats([3, 4, 4, 5, 6, 8, 9]).quantile(0.50)).to.equal(5); + expect(stats([3, 4, 4, 5, 6, 8, 9]).quantile(0.75)).to.equal(8); + expect(stats([3, 4, 4, 5, 6, 8, 9]).quantile(1)).to.equal(9); + }); +}); + describe('#q1()', function() { it('should return the first quartile of an odd length array', function() { expect(stats([12, 19, 4, 1, 2, 5, 8]).q1()).to.equal(2);