I need to calculate 5-star ratings like the one on Amazon website. I have done enough search to find what is the best algorithm, but I am not able to get a proper answer. For ex
If you are start calculation of overall rating from beginning then this formula will help you.
Formula
((Overall Rating * Total Rating) + new Rating) / (Total Rating + 1)
Example
suppose you have no ratings till now then formula is like, overall rating is "0" till now. total rating "0" and given rating is "4"
((0*0)+4)/1 = 4
If overall rating is "4.11" Total rating is "478" And new rating giving by one user is "2"
then formula is like
((4.11 * 478)+ 2)/479 // 479 is increment of new rating from 478
Super helpful reply by Blindy, here's the PHP code that's based on it. Some may find useful. The results will be 4.11 as per OP's example:
$ratings = array(
5 => 252,
4 => 124,
3 => 40,
2 => 29,
1 => 33
);
function calcAverageRating($ratings) {
$totalWeight = 0;
$totalReviews = 0;
foreach ($ratings as $weight => $numberofReviews) {
$WeightMultipliedByNumber = $weight * $numberofReviews;
$totalWeight += $WeightMultipliedByNumber;
$totalReviews += $numberofReviews;
}
//divide the total weight by total number of reviews
$averageRating = $totalWeight / $totalReviews;
return $averageRating;
}
How to build the above $ratings array
Example pseudo code, but which should work that explains how to build the $ratings array when info is stored in DB assuming you have a table called "ratings" and a column called "rating". In this case it's 1 join, you would need to do 4 joins to get all ratings, but this should get you started:
SELECT count(c1.rating) as one_star, count(c2.rating) as two_star
FROM ratings c1
LEFT OUTER JOIN
ratings c2
ON
c1.id = c2.id
WHERE
c1.rating = 1
AND
c2.rating = 2
another approach suggested in comments
SELECT SUM(rating = 1) AS one_s ,SUM(rating = 2) AS two_s ,SUM(rating = 3) as three_s FROM reviews where product_id = 9