Skip to content

Instantly share code, notes, and snippets.

@unki2aut
Created October 21, 2020 14:19
Show Gist options
  • Save unki2aut/05e2308c2fead6a5e714c44f9eab13de to your computer and use it in GitHub Desktop.
Save unki2aut/05e2308c2fead6a5e714c44f9eab13de to your computer and use it in GitHub Desktop.
median of a continuous frequency distribution
const amount = 10000; // the smaller the amount, the more the bucket median is off
const data = generateValues(amount, 300);
console.log({
amount,
normalMedian: normalMedian(data.values),
bucketMedian: bucketMedian(data.buckets),
});
function normalMedian(arr) {
const arr2 = arr.slice(0).sort((a, b) => a - b);
const idx = Math.floor(arr2.length / 2);
// for even numbers (https://www.gstatic.com/education/formulas/images_long_sheet/en/median_formula.svg)
if (arr2.length % 2 === 0) {
return (arr2[idx - 1] + arr2[idx]) / 2;
} else {
return arr2[idx];
}
}
// ref: https://www.mathstips.com/median-for-discrete-and-continuous-frequency-type/
function bucketMedian(buckets) {
const cumulative = [];
const totalFrequency = buckets.reduce((sum, f, idx) => {
cumulative[idx] = sum + f;
return cumulative[idx];
}, 0);
const medianBucketIdx = cumulative.findIndex(cf => cf > totalFrequency / 2);
return Math.round(
(medianBucketIdx + (totalFrequency / 2 - cumulative[medianBucketIdx - 1]) / buckets[medianBucketIdx]) * 10,
);
}
function generateValues(amount, range) {
const values = new Array(amount);
const buckets = [];
for (let a = 0; a < amount; a++) {
const value = Math.floor(Math.random() * range);
values[a] = value;
const idx = Math.floor(value / 10);
buckets[idx] = (buckets[idx] || 0) + 1;
}
return { values, buckets };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment