Skip to content

Commit

Permalink
sumOfSq and std (standard deviation) - adding files
Browse files Browse the repository at this point in the history
  • Loading branch information
esjewett committed Sep 17, 2014
1 parent a22f474 commit 699b995
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 0 deletions.
37 changes: 37 additions & 0 deletions src/std.js
@@ -0,0 +1,37 @@
var reductio_std = {
add: function (prior) {
return function (p, v) {
if(prior) prior(p, v);
if(p.count > 0) {
p.std = 0.0;
var n = p.sumOfSq - p.sum*p.sum/p.count;
if (n>0.0) p.std = Math.sqrt(n/(p.count-1));
} else {
p.std = 0.0;
}
return p;
};
},
remove: function (prior) {
return function (p, v) {
if(prior) prior(p, v);
if(p.count > 0) {
p.std = 0.0;
var n = p.sumOfSq - p.sum*p.sum/p.count;
if (n>0.0) p.std = Math.sqrt(n/(p.count-1));
} else {
p.std = 0;
}
return p;
};
},
initial: function (prior) {
return function (p) {
p = prior(p);
p.std = 0;
return p;
};
}
};

module.exports = reductio_std;
25 changes: 25 additions & 0 deletions src/sum-of-squares.js
@@ -0,0 +1,25 @@
var reductio_sum_of_sq = {
add: function (a, prior) {
return function (p, v) {
if(prior) prior(p, v);
p.sumOfSq = p.sumOfSq + a(v)*a(v);
return p;
};
},
remove: function (a, prior) {
return function (p, v) {
if(prior) prior(p, v);
p.sumOfSq = p.sumOfSq - a(v)*a(v);
return p;
};
},
initial: function (prior) {
return function (p) {
p = prior(p);
p.sumOfSq = 0;
return p;
};
}
};

module.exports = reductio_sum_of_sq;
91 changes: 91 additions & 0 deletions test/std.spec.js
@@ -0,0 +1,91 @@
// Counting tests
describe('Reductio std', function () {

var std, noSumOfSq, accStd;

beforeEach(function () {
var data = crossfilter([
{ foo: 'one', bar: 1 },
{ foo: 'two', bar: 2 },
{ foo: 'three', bar: 3 },
{ foo: 'one', bar: 4 },
{ foo: 'one', bar: 5 },
{ foo: 'two', bar: 6 },
]);

var dim = data.dimension(function(d) { return d.foo; });
var group = dim.group();
var groupNoSumOfSq = dim.group();
var groupAccStd = dim.group();

var reducer = reductio()
.std(true)
.count(true);

// This doesn't work because no .sumOfSq(accessor) has been defined.
// The resulting group only tracks counts.
reducer(groupNoSumOfSq);

reducer.count(false).sumOfSq(false);
reducer.std(function(d) { return d.bar; });

reducer(groupAccStd);

reducer.sumOfSq(false);
reducer.std(false);

reducer.sumOfSq(function(d) { return d.bar; })
.std(true);

// Now it should track count, sumOfSq, and std.
reducer(group);

std = group;
noSumOfSq = groupNoSumOfSq;
accStd = groupAccStd;
});

it('has three groups', function (topic) {
expect(std.top(Infinity).length).toEqual(3);
});

it('grouping have the right averages', function (topic) {
var values = {};
std.top(Infinity).forEach(function (d) {
values[d.key] = d.value;
});

expect(Math.round(values['one'].std)).toEqual(Math.round(2.08167));
expect(Math.round(values['two'].std)).toEqual(Math.round(2.82843));
expect(Math.round(values['three'].std)).toEqual(Math.round(0));
});

it('grouping with .std() but no .sumOfSq() doesn\'t work', function (topic) {
var values = {};
noSumOfSq.top(Infinity).forEach(function (d) {
values[d.key] = d.value;
});

// It has a count, as defined.
expect(values['one'].count).toEqual(3);

// But no sumOfSq.
expect(values['one'].sumOfSq).toBeUndefined();

// And no std.
expect(values['one'].std).toBeUndefined();

// Also throws an error on the console, but that's more difficult to test.
});

it('grouping with .std(accessor) works', function (topic) {
var values = {};
accStd.top(Infinity).forEach(function (d) {
values[d.key] = d.value;
});

expect(Math.round(values['one'].std)).toEqual(Math.round(2.08167));
expect(Math.round(values['two'].std)).toEqual(Math.round(2.82843));
expect(Math.round(values['three'].std)).toEqual(Math.round(0));
});
});
50 changes: 50 additions & 0 deletions test/sum-of-squares.spec.js
@@ -0,0 +1,50 @@
// Counting tests
describe('Reductio sumOfSq', function () {
var group;

beforeEach(function () {
var data = crossfilter([
{ foo: 'one', bar: 1 },
{ foo: 'two', bar: 2 },
{ foo: 'three', bar: 3 },
{ foo: 'one', bar: 4 },
{ foo: 'one', bar: 5 },
{ foo: 'two', bar: 6 },
]);

var dim = data.dimension(function(d) { return d.foo; });
group = dim.group();

var reducer = reductio()
.count(true)
.sumOfSq(function(d) { return d.bar; });

reducer(group);
});

it('has three groups', function () {
expect(group.top(Infinity).length).toEqual(3);
});

it('grouping have the right sum of squares', function () {
var values = {};
group.top(Infinity).forEach(function (d) {
values[d.key] = d.value;
});

expect(values['one'].sumOfSq).toEqual(42);
expect(values['two'].sumOfSq).toEqual(40);
expect(values['three'].sumOfSq).toEqual(9);
});

it('grouping plays nicely with count', function () {
var values = {};
group.top(Infinity).forEach(function (d) {
values[d.key] = d.value;
});

expect(values['one'].count).toEqual(3);
expect(values['two'].count).toEqual(2);
expect(values['three'].count).toEqual(1);
});
});

1 comment on commit 699b995

@esjewett
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should address #2

Please sign in to comment.