summary
Advanced tools
Comparing version 1.0.0 to 2.0.0
{ | ||
"name": "summary", | ||
"description": "Takes an array of numbers and calculates some descriptive statistics", | ||
"version": "1.0.0", | ||
"version": "2.0.0", | ||
"author": "Andreas Madsen <amwebdk@gmail.com>", | ||
@@ -26,5 +26,5 @@ "main": "./summary.js", | ||
"devDependencies": { | ||
"tap": "0.6.x" | ||
"tap": "~14.0.0" | ||
}, | ||
"license": "MIT" | ||
} |
@@ -0,6 +1,6 @@ | ||
'use strict'; | ||
var array_types = [ | ||
Array, Int8Array, Uint8Array, Int16Array, Uint16Array, | ||
Int32Array, Uint32Array, Float32Array, Float64Array | ||
]; | ||
function isArray(x) { | ||
return Array.isArray(x) || ArrayBuffer.isView(x) && !(x instanceof DataView); | ||
} | ||
@@ -10,3 +10,3 @@ function Summary(data, sorted) { | ||
if (array_types.indexOf(data.constructor) === -1) { | ||
if (!isArray(data)) { | ||
throw TypeError('data must be an array'); | ||
@@ -54,4 +54,4 @@ } | ||
if (this._cache_sum === null) { | ||
var sum = 0; | ||
for (var i = 0; i < this._length; i++) sum += this._data[i]; | ||
let sum = 0; | ||
for (let i = 0; i < this._length; i++) sum += this._data[i]; | ||
this._cache_sum = sum; | ||
@@ -65,11 +65,11 @@ } | ||
if (this._cache_mode === null) { | ||
var data = this.sort(); | ||
const data = this.sort(); | ||
var modeValue = NaN; | ||
var modeCount = 0; | ||
var currValue = data[0]; | ||
var currCount = 1; | ||
let modeValue = NaN; | ||
let modeCount = 0; | ||
let currValue = data[0]; | ||
let currCount = 1; | ||
// Count the amount of repeat and update mode variables | ||
for (var i = 1; i < this._length; i++) { | ||
for (let i = 1; i < this._length; i++) { | ||
if (data[i] === currValue) { | ||
@@ -102,3 +102,8 @@ currCount += 1; | ||
if (this._cache_mean === null) { | ||
this._cache_mean = this.sum() / this._length; | ||
// Numerically stable mean algorithm | ||
let mean = 0; | ||
for (let i = 0; i < this._length; i++) { | ||
mean += (this._data[i] - mean) / (i+1); | ||
} | ||
this._cache_mean = mean; | ||
} | ||
@@ -111,5 +116,5 @@ | ||
if (!this._cache_quartiles.hasOwnProperty(prob)) { | ||
var data = this.sort(); | ||
var product = prob * this.size(); | ||
var ceil = Math.ceil(product); | ||
const data = this.sort(); | ||
const product = prob * this.size(); | ||
const ceil = Math.ceil(product); | ||
@@ -138,9 +143,13 @@ if (ceil === product) { | ||
if (this._cache_variance === null) { | ||
var mean = this.mean(); | ||
var sqsum = 0; | ||
for (var i = 0; i < this._length; i++) { | ||
sqsum += (this._data[i] - mean) * (this._data[i] - mean); | ||
// Numerically stable variance algorithm | ||
const mean = this.mean(); | ||
let biasedVariance = 0; | ||
for (let i = 0; i < this._length; i++) { | ||
const diff = this._data[i] - mean; | ||
biasedVariance += (diff * diff - biasedVariance) / (i+1); | ||
} | ||
this._cache_variance = sqsum / (this._length - 1); | ||
// Debias the variance | ||
const debiasTerm = ((this._length) / (this._length - 1)); | ||
this._cache_variance = biasedVariance * debiasTerm; | ||
} | ||
@@ -147,0 +156,0 @@ |
99
test.js
@@ -15,3 +15,3 @@ | ||
test('testing sort method', function (t) { | ||
const data = [2, 3, 7, -2, 0, 1, 1] | ||
const data = [2, 3, 7, -2, 0, 1, 1]; | ||
@@ -39,2 +39,11 @@ t.deepEqual( | ||
test('testing sort method when cached', function (t) { | ||
const s = summary([2, 3, 7, -2, 0, 1, 1]); | ||
t.deepEqual(s.sort(), [-2, 0, 1, 1, 2, 3, 7]); | ||
t.deepEqual(s.sort(), [-2, 0, 1, 1, 2, 3, 7]); | ||
t.end(); | ||
}); | ||
test('testing size method', function (t) { | ||
@@ -58,2 +67,9 @@ t.equal( | ||
test('testing sum method when cached', function (t) { | ||
const s = summary([1, 10]); | ||
t.equal(s.sum(), 11); | ||
t.equal(s.sum(), 11); | ||
t.end(); | ||
}); | ||
test('testing mode method', function (t) { | ||
@@ -71,2 +87,17 @@ t.equal( | ||
t.equal( | ||
summary([1, 2, 2, 3, 3, 3, 4]).mode(), | ||
3 | ||
); | ||
t.equal( | ||
summary([1, 2, 2, 3, 3, 4]).mode(), | ||
3 | ||
); | ||
t.equal( | ||
summary([1, 2, 2, 2, 3, 3, 4]).mode(), | ||
2 | ||
); | ||
t.equal( | ||
summary([1, 2, 3]).mode(), | ||
@@ -79,2 +110,9 @@ 3 | ||
test('testing mode method when cached', function (t) { | ||
const s = summary([1, 2, 3]); | ||
t.equal(s.mode(), 3); | ||
t.equal(s.mode(), 3); | ||
t.end(); | ||
}); | ||
test('testing mean method', function (t) { | ||
@@ -89,2 +127,9 @@ t.equal( | ||
test('testing mean method when cached', function (t) { | ||
const s = summary([2, 4]); | ||
t.equal(s.mean(), 3); | ||
t.equal(s.mean(), 3); | ||
t.end(); | ||
}); | ||
test('testing quartile method', function (t) { | ||
@@ -107,2 +152,13 @@ var data = summary([ | ||
// when cached | ||
t.equal(data.quartile(0.00), 2.00); | ||
t.equal(data.quartile(0.13), 3.00); | ||
t.equal(data.quartile(0.26), 7.00); | ||
t.equal(data.quartile(0.39), 14.0); | ||
t.equal(data.quartile(0.52), 18.0); | ||
t.equal(data.quartile(0.65), 21.0); | ||
t.equal(data.quartile(0.78), 25.0); | ||
t.equal(data.quartile(0.91), 28.0); | ||
t.equal(data.quartile(1.00), 29.0); | ||
t.end(); | ||
@@ -119,2 +175,4 @@ }); | ||
t.equal(data.median(), 18); | ||
// when cached | ||
t.equal(data.median(), 18); | ||
@@ -124,2 +182,3 @@ t.end(); | ||
test('testing variance method', function (t) { | ||
@@ -131,2 +190,10 @@ t.equal(summary([-2, -1, 0, 1, 2]).variance(), 2.5); | ||
test('testing variance method when cached', function (t) { | ||
const s = summary([-2, -1, 0, 1, 2]); | ||
t.equal(s.variance(), 2.5); | ||
t.equal(s.variance(), 2.5); | ||
t.end(); | ||
}); | ||
test('testing sd method', function (t) { | ||
@@ -138,2 +205,10 @@ t.equal(summary([-2, -1, 0, 1, 2]).sd(), Math.sqrt(2.5)); | ||
test('testing sd method when cached', function (t) { | ||
const s = summary([-2, -1, 0, 1, 2]); | ||
t.equal(s.sd(), Math.sqrt(2.5)); | ||
t.equal(s.sd(), Math.sqrt(2.5)); | ||
t.end(); | ||
}); | ||
test('testing max method', function (t) { | ||
@@ -145,2 +220,10 @@ t.equal(summary([6, 10, 2, 5]).max(), 10); | ||
test('testing max method when cached', function (t) { | ||
const s = summary([6, 10, 2, 5]); | ||
t.equal(s.max(), 10); | ||
t.equal(s.max(), 10); | ||
t.end(); | ||
}); | ||
test('testing min method', function (t) { | ||
@@ -152,2 +235,10 @@ t.equal(summary([6, 10, 2, 5]).min(), 2); | ||
test('testing min method when cached', function (t) { | ||
const s = summary([6, 10, 2, 5]); | ||
t.equal(s.min(), 2); | ||
t.equal(s.min(), 2); | ||
t.end(); | ||
}); | ||
test('typed array', function (t) { | ||
@@ -158,1 +249,7 @@ t.equal(summary(new Int8Array([2, 4])).mean(), 3); | ||
}); | ||
test('not array', function (t) { | ||
t.throws(() => summary({ length: 0 }), TypeError); | ||
t.end(); | ||
}); |
13045
329
5