用于计算五星评级的算法

我需要计算像亚马逊网站上的五星评级。我已经做了足够的搜索来找到最好的算法,但是我不能得到一个正确的答案。例如,如果这些是收视率

5 star - 252
4 star - 124
3 star - 40
2 star - 29
1 star - 33

总共478条评论

亚马逊的计算结果是“五星中的4.1星”。谁能告诉我这个数字是怎么算出来的?我不能仅仅通过做平均分就得到这个。

107036 次浏览

Yes, you can average them out:

(5 * 252 + 4 * 124 + 3 * 40 + 2 * 29 + 1 * 33) / 478 = 4.11

That's a weighted average, where you weigh each rating with the number of votes it got:

(5*252 + 4*124 + 3*40 + 2*29 + 1*33) / (252+124+40+29+33) = 4.11 and change

This rating system is based on a weighted average or weighted mean. That is, they used the weight in terms of stars to compute a decimal value which rounds to 4.1. For example:

Sum of (weight * number of reviews at that weight) / total number of reviews
(5*252 + 4*124 + 3*40 + 2*29 + 1*33) / 478 = 4.1

Weighted average, sum the number of stars times its weight, and then divide it through by the total number of reviews.

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

a better way to do this,

rating = (sum_of_rating * 5)/sum_of_max_rating_of_user_count

example:

total users rated: 6
sum_of_max_rating_of_user_count: 6 x 5 = 30
sum_of_rating: 25


rating = (25 * 5) / 30

Done!

in Javascript

function calcAverageRating(ratings) {


let totalWeight = 0;
let totalReviews = 0;


ratings.forEach((rating) => {


const weightMultipliedByNumber = rating.weight * rating.count;
totalWeight += weightMultipliedByNumber;
totalReviews += rating.count;
});


const averageRating = totalWeight / totalReviews;


return averageRating.toFixed(2);
}




const ratings = [
{
weight: 5,
count: 252
},
{
weight: 4,
count: 124
},
{
weight: 3,
count: 40
},
{
weight: 2,
count: 29
},
{
weight: 1,
count: 33
}
];


console.log(calcAverageRating(ratings));

(Total nunber of star / total number of persons who review * 5 ) * 5

= Answer

Fixed decimals in js to 1.

answer.toFixed(1);

Example the total reviews of 5 person is 20 star.

(20/5*5)*5 = 4.0

According to your question your solution will be like this.

Sum of (Rate*TotalRatingOfThatRate)/ TotalNumberOfReviews


((5*252)+(4*124)+(3*40)+(2*29)+(1*33)) / (252+124+40+29+33)

output will be 4.1

In addition, I am just trying to make practical and full code for all.

My Json Object Array

var yourRatingData =[{
review_id:1,
customer_id:5,
customer_name:"Faysal",
rating:5,
review_content:"I like this product it's cool and best in quality"
},
{
review_id:2,
customer_id:6,
customer_name:"Adams",
rating:4,
review_content:"It's quality product though price a bit high"
},
{
review_id:3,
customer_id:8,
customer_name:"Jane",
rating:3,
review_content:"I like but should improve quality"
},
{
review_id:4,
customer_id:9,
customer_name:"Julia",
rating:1,
review_content:"It's not good"
}];

Rating Calculation

let _5star = yourRatingData.filter(r=>r.rating==5).length;
let _4star = yourRatingData.filter(r=>r.rating==4).length;
let _3star = yourRatingData.filter(r=>r.rating==3).length;
let _2star = yourRatingData.filter(r=>r.rating==2).length;
let _1star = yourRatingData.filter(r=>r.rating==1).length;


//Sum of individual star.
let sumOfRating = parseInt( _5star + _4star + _3star + _2star + _1star );


//Total number of rating
let overallRating = parseInt( 5*_5star + 4*_4star + 3*_3star + 2*_2star +1*_1star );


//Average of all rating
let averageRating = parseFloat(overallRating/sumOfRating);


//Percentage of each star rating
let _5starPercentage = parseInt((_5star/totalRating)*100);
let _4starPercentage = parseInt((_4star/totalRating)*100);
let _3starPercentage = parseInt((_3star/totalRating)*100);
let _2starPercentage = parseInt((_2star/totalRating)*100);
let _1starPercentage = parseInt((_1star/totalRating)*100);

I think it's helpful.

This is an example method using flutter,

double starRating = 5.0;
getRating() {
// ! Check Already Accepted by others or Not -----------------------------------
//
int totalof5s = 0;
int totalof4s = 0;
int totalof3s = 0;
int totalof2s = 0;
int totalof1s = 0;
//
FirebaseFirestore.instance
.collection('usersRating')
.where("passengerUid", isEqualTo: "GNblJJJsjicaA2vkXJNJ6XCAiwa2")
.snapshots()
.forEach((querySnapshot) {
if (querySnapshot.size > 0) {
querySnapshot.docs.forEach((element) async {
if (element["rating"] == 5) {
totalof5s++;
} else if (element["rating"] == 4) {
totalof4s++;
} else if (element["rating"] == 3) {
totalof3s++;
} else if (element["rating"] == 2) {
totalof2s++;
} else if (element["rating"] == 1) {
totalof1s++;
}
//
if (this.mounted) {
setState(() {
starRating = (5 * totalof5s +
4 * totalof4s +
3 * totalof3s +
2 * totalof2s +
1 * totalof1s) /
(totalof5s + totalof4s + totalof3s + totalof2s + totalof1s);
});
}
});
        

} else {
// This is default one in any case these user doesn't have any rating document exists
if (this.mounted) {
setState(() {
starRating = 5.0;
});
}
}
});
}