Reputation: 83
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;
};
Upvotes: 3
Views: 5256
Reputation: 265
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
.)Upvotes: 0
Reputation: 9
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.
Upvotes: 0
Reputation: 782107
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));
Upvotes: 2