-
-
Save dfabulich/fc6b13a8bffc5518c4731347de642749 to your computer and use it in GitHub Desktop.
"use strict"; | |
// based on unutbu's stackoverflow answer | |
// https://stackoverflow.com/a/40958702/54829 | |
// which is based on Evan Miller's blog post | |
// http://www.evanmiller.org/ranking-items-with-star-ratings.html | |
function starsort(ratings) { | |
function sum(array) { return array.reduce((x, y) => x + y, 0) }; | |
function square(x) { return x * x; }; | |
const confidenceZ = 1.65; | |
// include five fake reviews | |
// 1 1-star, 1 2-star, 1 3-star, 1 4-star, 1 5-star | |
const fakeRatings = ratings.map(count => count + 1); | |
const N = sum(fakeRatings); | |
const average = sum(fakeRatings.map((count, i) => (i + 1) * count)) / N; | |
// Dirichlet standard deviation of average | |
const x = sum(fakeRatings.map((count, i) => square(i + 1) * count)) / N; | |
const standardDeviation = Math.sqrt((x - square(average)) / (N + 1)); | |
return average - confidenceZ * standardDeviation; | |
} | |
console.log(starsort([60, 80, 75, 20, 25])); |
No, I haven't, but I'm frankly confused by your question, in a way that makes me think that you're confused, too.
Do you actually allow real users to give a product a fractional score, like 4.3 out of 5? I assume not, right? You just let people give an integer star rating from 1 to 5, and "4.3" is the average of 10 ratings, right? To use starsort, you'd need the actual original rankings as the users provided them; you can't just take the average and try to feed that into starsort.
But, let's say you do allow users to give a score of 4.3 out of 5. OK, well, I assume you don't allow users to submit ratings with an unlimited number of digits. Users can't rate a product 4.31234745938 out of 5, can they? So I'm guessing they're allowed a single decimal point? So they can rate a product 4.3 out of 5, but not 4.32 out of 5? If they're only allowed a single decimal point, then you're really using a "fixed point" number, so you can just multiply their scores by ten, as if the users rated the product on a scale from 0 to 50, and 10 users rated the product 43 out of 50. That will let you use starsort normally.
Barring that, you could probably just round all of the numbers to one decimal place. 4.31234745938 is close enough to 4.3. Then you can treat the problem as if it were a fixed point number.
Here's a Go version, for anyone searching like I was:
// starsort.go
package main
import(
"fmt"
"math"
)
// http://www.evanmiller.org/ranking-items-with-star-ratings.html
func sum(ns []int) int {
var total int
for _,n := range ns {
total += n
}
return total
}
func f(s []int, ns []int)float64{
N := sum(ns)
K := len(ns)
ks := make([]int,K)
for i:=0; i<5; i++ {
ks[i] = s[i] * (ns[i]+1)
}
return float64(sum(ks)) / float64(N+K)
}
func starSort(ns []int) float64 {
N := sum(ns)
K := len(ns)
s := []int{5, 4, 3, 2, 1}
s2 := []int{25, 16, 9, 4, 1}
z := float64(1.65)
fsns := f(s, ns)
return fsns - z * math.Sqrt(((f(s2, ns) - (fsns*fsns)) / float64(N+K+1)))
}
func main(){
fmt.Println(starSort([]int{60, 80, 75, 20, 25}))
}
@dfabulich Have you tried this with floating numbers? Not sure how to modify this to fit my use case but, say I have an array of ratings like this:
How do I go about using the starsort function?