Commit c0e84e2c by Jason Davies

### Optimise d3.mean.

```Originally we were using Welford’s algorithm, but this is primarily
useful when computing the variance in a numerically stable manner, since
Welford’s approach requires an incremental mean.

I’ve removed a test for the mean of more than one instance of
Number.MAX_VALUE as this is unlikely to occur in practice; most likely
this was the reason I used Welford’s algorithm in the first place.

There’s a paper [1] comparing various algorithms for computing the mean,
and Welford’s is actually slightly less accurate than the naïve
approach.  There are some more accurate approaches but I think it’s
overkill for d3.mean.

[1] Youngs, Edward A., and Elliot M. Cramer. "Some results relevant to
choice of sum and sum-of-product algorithms." Technometrics 13.3 (1971):
657-665.

Related: #1842.```
parent 624f21c9
 ... ... @@ -91,13 +91,13 @@ return x != null && !isNaN(x); } d3.mean = function(array, f) { var n = array.length, a, m = 0, i = -1, j = 0; var s = 0, n = array.length, a, i = -1, j = n; if (arguments.length === 1) { while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; while (++i < n) if (d3_number(a = array[i])) s += a; else --j; } else { while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; while (++i < n) if (d3_number(a = f.call(array, array[i], i))) s += a; else --j; } return j ? m : undefined; return j ? s / j : undefined; }; d3.quantile = function(values, p) { var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; ... ...
This diff is collapsed.
 import "../math/number"; d3.mean = function(array, f) { var n = array.length, var s = 0, n = array.length, a, m = 0, i = -1, j = 0; j = n; if (arguments.length === 1) { while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; while (++i < n) if (d3_number(a = array[i])) s += a; else --j; } else { while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; while (++i < n) if (d3_number(a = f.call(array, array[i], i))) s += a; else --j; } return j ? m : undefined; return j ? s / j : undefined; };
 ... ... @@ -18,10 +18,6 @@ suite.addBatch({ assert.equal(mean([1, 2, 3, 4, 5, NaN]), 3); assert.equal(mean([10, null, 3, undefined, 5, NaN]), 6); }, "can handle large numbers without overflowing": function(mean) { assert.equal(mean([Number.MAX_VALUE, Number.MAX_VALUE]), Number.MAX_VALUE); assert.equal(mean([-Number.MAX_VALUE, -Number.MAX_VALUE]), -Number.MAX_VALUE); }, "returns undefined for empty array": function(mean) { assert.isUndefined(mean([])); assert.isUndefined(mean([null])); ... ...
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment