Given an array of numbers, I am looking to find the percentile of a given value.
I found this code here that seems to do what I need, but I was hoping I could get someone to explain this code to me step by step:
const percentile = (arr, val) =>
(100 *
arr.reduce(
(acc, v) => acc + (v < val ? 1 : 0) + (v === val ? 0.5 : 0),
0
)) /
arr.length;
// example
// percentile([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 6); // 55
Update
Thanks everyone for your help. I found a Percentile formula that further helps me understand what the code is doing.
Formula:
Percentile = [L + ( 0.5 x S ) / N] * 100
Based on my new understanding of the function, I find this a bit easier to read:
/**
* **Percentile = ((L + ( 0.5 x S )) / N) * 100**
* - L = Number of values **lower** than `value`
* - S = Number of same rank
* - N = Total numbers
*/
const percentile = (arr, value) => {
const currentIndex = 0;
const totalCount = arr.reduce((count, currentValue) => {
if (currentValue < value) {
return count + 1; // add 1 to `count`
} else if (currentValue === value) {
return count + 0.5; // add 0.5 to `count`
}
return count + 0;
}, currentIndex);
return (totalCount * 100) / arr.length;
};
The function is equivalent to ths simpler version.
count contains the number of elements that val is higher than, plus 0.5 for each element it's equal to. Dividing this total by the number of elements is the percentile.
const percentile = (arr, val) => {
let count = 0;
arr.forEach(v => {
if (v < val) {
count++;
} else if (v == val) {
count += 0.5;
}
});
return 100 * count / arr.length;
}
console.log(percentile([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 6));
Even if the vector is not sorted the result is correct. The vector can contain duplicated values.
reduce scan a vector and produce a result accumulating partial results inside the acc
acc is initialized to 0 (line 5)
(v < val ? 1 : 0) result in 1 or 0 depending if v < val. The conditional ternary operator ? : is not needed because true is interpreted as 1 and false as 0, so you can write only + (v < val)
(v === val ? 0.5 : 0) add .5 only for values equal to the val.
Lines 2 and 7 transform the frequency of lower (and equal) values into a percentile.
arr (aka it sets each element in arr as v). On each iteration...v to val. If v is less than val, then acc is increased by 1. If v is equal to val, then acc is increased by 0.5. (In layperson's terms, this means that as the function iterates through each element in arr, the value of acc is counting how many elements are less than or equal to val.)acc is divided by the number of elements in arr. (In other words, since acc is the number of elements that are less than val, dividing acc/arr gives us a decimal representing the proportion of the array that's less than val.)