
Viele Websites benutzen Bewertungen, um die Wichtigkeit oder die Beliebtheit eines Artikels oder Produkts zu messen. Beliebte jQuery Plugins wie das 5 Star-Rating sind schnell und einfach integriert. Die Schwierigkeit liegt eher an der Ausgabe der Daten und dabei wollen wir helfen!
Bei unserem neusten Projekt Stokedcamps geht es darum, dass sich einerseits Surfcamps mit einem Profil präsentieren können und anderseits dass Besucher diese bewerten können. Wir haben ebenfalls das verbreitete 5 Star-Rating eingesetzt. Folgendes Problem ergibt sich:
Problem
Surfcamp 1 erhält 23 Bewertungen:
20 x 5
3 x 4
ergibt eine durchschnittliche Bewertung von 4.8
Surfcamp 2 erhält 1 Bewertung:
1 x 5
ergibt eine durchschnittle Bewertung von 5
Was läuft hier falsch?
Sortiert man nun die Surfcamps nach ihrer durchschnittlichen Bewertung wird das zweite Surfcamp besser gelistet als das erste. Rein mathematisch macht dies Sinn, allerdings ist das zweite Surfcamp aufgrund der vielen Besucher und der überdurchschnittlichen Bewertung natürlich als besser einzustufen.
Demo mit falscher Sortierung
Wir haben das ganze mal veranschaulicht mit einem Bewertungssystem für Superheroes, schaut es euch an, setzt Bewertungen und erkennt wie es sich verhält:
Wie kann das Problem gelöst werden?
Um das Problem zu lösen muss also eine Gewichtung geschaffen werden, möglichst eine organische welche sich an der Höhe der Gesamtbewertungen und der durchschnittlichen Bewertung orientiert. Wir haben gesucht und sind auf den Bayes’schen Durchschnitt gestossen. Der nach dem englischen Mathematiker Thomas Bayes benannte bayessche Wahrscheinlichkeitsbegriff interpretiert Wahrscheinlichkeit als Grad persönlicher Überzeugung. Genau das suchen wir!
Auf der Seite von The Broth haben wir folgende Formel dazu entdeckt:
bayesian = ( (avg_num_votes * avg_rating) + (this_num_votes * this_rating) ) / (avg_num_votes + this_num_votes)
Legende:
- avg_num_votes: Die durchschnittle Anzahl an Bewertungen von allen Objekten die mehr als 0 Bewertungen haben
- avg_rating: Die durchschnittliche Bewertung jedes Objekts (wieder alle mit mehr als 0 Bewertungen)
- this_num_votes: Anzahl der Bewertungen für dieses Objekt
- this_rating: Die Bewertung dieses Objekts
Wir haben also das ganze bei der Superhero-Bewertung eingebaut und Boom! Genau so wie es sein soll, die Bewertung wird aufgrund der Menge an Bewertungen und der durchschnittlichen Bewertung gemessen, wenn es viele Stimmen gibt können wir also darauf vertrauen, dass das die öffentliche Meinung vieler ist.
Demo mit Bayes’schen Bewertung
Vielen Entwicklern wird die oben erwähnte Formel reichen um das in ihre Projekte zu integrieren, wer noch eine Code-Beispiel benötigt helfen wir natürlich gerne.
PHP-Beispiel
<?php
// Config
$total_votes = 0; // Number of total votes
$total_rating = 0; // Number of total ratings
$number_of_superheroes = 0; // Number of Superheroes
// Create Superhero Array
$superheroes = array (
'dark_knight' => array ('id' => '1', 'name' => 'dark_knight', 'num_votes' => 5, 'avg_rating' => 4.8),
'green_lantern' => array ('id' => '2', 'name' => 'green_lantern', 'num_votes' => 1, 'avg_rating' => 5 ),
'robin' => array ('id' => '3', 'name' => 'robin', 'num_votes' => 1, 'avg_rating' => 5 ),
'superman' => array ('id' => '4', 'name' => 'superman', 'num_votes' => 1, 'avg_rating' => 5 ),
'flash' => array ('id' => '5', 'name' => 'flash', 'num_votes' => 1, 'avg_rating' => 5 ),
);
// Loop array and count data
foreach ($superheroes as $k => $v) {
$total_votes += $v['num_votes'];
$total_rating += $v['avg_rating'];
$number_of_superheroes += 1;
}
// Do the math
$avg_num_votes = $total_votes/$number_of_superheroes; // Average number of votes
$avg_rating = $total_rating/$total_votes; // Average rating for all superheroes
// Bayes it and write output
foreach ($superheroes as $k => $v) {
$karma = ( ($avg_num_votes * $avg_rating) + ($v['num_votes'] * $v['avg_rating']) ) / ($avg_num_votes + $v['num_votes']);
echo $v['name'] . ': ' . round(($karma*2*10)) . '<br/>';
}
?>
Wie verwendet ihr dieses Beispiel?
Kopiert euch dieses PHP-Script in ein Textfile, speichert es beispielsweise unter superheroes.php und kopiert es auf den Server eures Vertrauens. Ruft das PHP im Browser auf und ihr seht die Ausgabe der Berechnung. Nun könnt ihr Werte im Array anpassen und schauen wie sich dies auf das Karma auswirkt. Das Script ist bestimmt eine gute Grundlage um die Bayes’schen Bewertung zu verstehen und anzuwenden. Als Live-Beispiel könnt ihr euch auch die Bewertungen auf Stokedcamps.com anschauen.
Habt ihr diese Bewertung auf eurer Seite integriert oder habt ihr Fragen? Meldet euch in den Kommentaren.



9 Kommentare
Denis says:
Dez 20, 2011
Hallo,
das Script ist klasse. Was ich jetzt nur vermisse, ist, wie ich die einzelnen Votes abspeicher. Verwende ich da eine Tabelle, wo ich die ID des zu bewertenden Objektes speicher mit der entsprechenden Berwertung?
ID | Produkt | Voting
Und dann gebe ich für jedes Produkt den durchschnitt aus. Pro Produkt, alle Bewertungen durch die Anzahl aller abgegebenen Stimmen?
Grüße
derDenis
Webdesignlovers says:
Dez 20, 2011
Hallo Denis. Wir haben eine Tabelle für alle Produkte und eine Tabelle für alle Votes. Bsp:
Produkt-Tabelle
===============
id, karma, total votes, description
Rating-Tabelle
==============
id, user_id, rating, timestamp
Nach jeder Bewertung wird die Rating-Tabelle gefüllt. Die Berechnung von Karma und Total Ratings (Bayes’sche Berechnung) rufen wir über einen Cronjob auf. Je nachdem wie viele Produkte und Bewertungen du hast, frisst das ganze ziemlich Performance und das wollen wir dem User nicht zumuten.
Der Vorteil dieser Lösung ist zudem, dass du nicht bei jedem Produkte-Aufruf oder bei Sortierungen die Berechnung durchführen musst sondern lediglich die zwei Werte (Karma, Total Ratings) auslesen kannst. Nachteil ist, dass die Werte nicht immer Real-Time nachgeführt werden. Vielleicht hilft dir das als Lösungsansatz, schreib uns wie du es letztendlich gelöst hast.
Denis says:
Dez 23, 2011
Hi, ich habe es mal mit dieser Lösung von http://www.thebroth.com/blog/118/bayesian-rating versucht, heißt ich erstelle direkt 2 View Tabellen auf meinem SQL Server:
SELECT
ITEM_PK,
(select count(ITEM_PK) from ITEM_rating) / (select count(distinct ITEM_PK) from ITEM_rating) as avg_num_votes,
(select avg(rating / (((to_days(now()) – to_days(createDate)) / 90) + 1)) from ITEM_rating) as avg_rating,
count(ITEM_PK) as this_num_votes,
avg(rating / (((to_days(now()) – to_days(createDate)) / 90) + 1)) as this_rating
FROM
ITEM_rating
group by ITEM_PK
select ITEM_PK, ((avg_num_votes * avg_rating) + (this_num_votes * this_rating)) / (avg_num_votes + this_num_votes) as real_rating from YOUR_VIEW oder by real_rating
Das scheint auch zu funktioniren. Problem ist nur, wenn ich für 1 Venue 1 Stimme mit 10 abgebe und für eine 2 Venue 10 Stimmen a 9 gewinnt immer die 1 Venue, solange bis ich zur 1 Venue eine zweite Stimme von 5 abgebe.
Da stimmt doch etwas nicht :-(
Denis says:
Dez 23, 2011
ich glaube es muß in der ersten view tabelle:
” SUM “(ITEM_PK) as this_num_votes,
heißen, dann scheint es zu klappen.
Alexander says:
Jul 18, 2012
Ein sehr schöner Beitrag zu dem Thema:-)
Das ist genau das, was ich gesucht habe. THX
Webdesignlovers says:
Jul 26, 2012
Perfekt, das freut uns!
Denis says:
Sep 10, 2012
Hallo,
ich hatte das Projekt mal eine zeitlang auf seite gelegt. Und nun finde ich den Anfang nicht mehr :-)
Wie würde den dieser Cronjob aussehen? Das würde mich interessieren, da diese realtime Abfrage doch erheblich ist.
Beste Grüße,
Denis
Denis says:
Sep 10, 2012
Halli Hallo,
also irgendwie bekomme ich das nicht hin. Wenn ich genau 1 Bewertung mit der höchsten Bewertung eingebe, dann hat diese immer das höchste KARMA.
Was mache ich denn falsch?
http://www.bierbild.com/rating1.php
Sobald ich eine zweite Bewertung hinzufüge klappt es.
Ich denke mal das $v['avg_rating'] der knackpunkt ist.
Wer kann helfen?
Denis says:
Sep 10, 2012
Fehler gefunden!
Sorry für das zumüllen :-)
Ich hatte immer den Durchschnitt der einzelnen Bewertung genommen, iritiert durch das “avg_rating”. Jetzt nehme ich die Summe und es scheint zu klappen.
Grüße,
derDenis