Published
Edited
Mar 11, 2021
7 stars
Insert cell
Insert cell
Insert cell
A = [1, 1, 2, 3, 5]
Insert cell
d3.gmdn(A)
Insert cell
Insert cell
d3.gmean(A)
Insert cell
Insert cell
d3.agmean(A)
Insert cell
Insert cell
d3.mean(A)
Insert cell
d3.median(A)
Insert cell
Insert cell
B = Float64Array.from({ length: 1e6 }, Math.random)
Insert cell
d3.gmdn(B)
Insert cell
d3.gmean(B)
Insert cell
d3.gmean([-1, -4]) // geometric mean of negative numbers, why not. But the numbers should all be of the same sign for this to have any kind of meaning
Insert cell
Insert cell
d3 = {
const d3 = await require("d3-array@2");

d3.gmean = function(data, value = d => d) {
const r = 64;
const K = 2 ** r;
const K1 = 2 ** -r;
let p = 1; // product
let n = 0; // count
let s = 1; // sign
let k = 0; // track exponent to prevent under/overflows
for (let i = 0; i < data.length; i++) {
const v = value(data[i]);
if (+v === +v) {
n++;
s = Math.sign(v);
if (s === 0) return 0;
p *= Math.abs(v);
while (p > K) (p *= K1), ++k;
while (p < K1) (p *= K), --k;
}
}
return n ? s * 2 ** ((Math.log2(p) + k * r) / n) : NaN;
};

d3.agmean = function(data, value = d => d) {
const step = a => [d3.mean(a), d3.gmean(a)];
let a = step(Array.from(data, value).filter(d => +d === +d));
while (Math.abs(a[1] - a[0]) > 1e-16) a = step(a);
return a[0];
};

d3.gmdn = function(data, value = d => d) {
const step = a => [d3.mean(a), d3.gmean(a), d3.median(a)];
let a = step(Array.from(data, value).filter(d => +d === +d));
while (Math.abs(a[1] - a[0]) > 1e-16) a = step(a);
return a[0];
};

return d3;
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more