Skip to content

Instantly share code, notes, and snippets.

@dtinth
Last active April 28, 2016 14:43
Show Gist options
  • Save dtinth/340fc1e7714ec338237115a9f37312c3 to your computer and use it in GitHub Desktop.
Save dtinth/340fc1e7714ec338237115a9f37312c3 to your computer and use it in GitHub Desktop.

Sort by (predicted) satisfaction

Based on an article: How Not To Sort By Average Rating

This code snippet sorts the restaurant listing in Foodpanda.co.th by using the equation from the above article.

Assumptions: Since the article is for binary rating (+/−), I’m going to make an assumption that the stars represent the proportion of delighted customers. For example, if a restaurant gets 4.5 stars and has 2,000 reviews, it is assumed that there are 1,800 delighted customers out of 2,000.

Usage:

  1. Go to a restaurant listing page.

  2. Scroll all the way to the bottom to make sure all pages are loaded.

  3. Copy the script and paste in the JavaScript console.

// Arigatou: http://www.evanmiller.org/how-not-to-sort-by-average-rating.html
function getSatisfactionRate (averageRating, numReviews) {
if (numReviews == 0) return 0
var positive = Math.round(averageRating / 5 * numReviews)
var negative = numReviews - positive
return ((positive + 1.9208) / (positive + negative) -
1.96 * Math.sqrt((positive * negative) / (positive + negative) + 0.9604) /
(positive + negative)) / (1 + 3.8416 / (positive + negative))
}
var data = [].map.call(document.querySelectorAll('.vendor'), (el, i) => {
var rv = +(x => x && x.getAttribute('content') || 0)(el.querySelector('[itemprop="ratingValue"]'))
var rc = +(m => m && m[0] || '0')(
(x => x && x.textContent || '0')(el.querySelector('.review')).match(/\d+/)
)
return [getSatisfactionRate(rv, rc), el, rv, rc, i + 1]
})
function getElement (el) {
var z = el.querySelector('.gtx')
if (z) return z
var c = document.createElement('div')
c.className ='gtx'
el.appendChild(c)
return c
}
data.sort((a, b) => b[0] - a[0])
data.forEach((row, i) => {
row[1].parentNode.appendChild(row[1])
var details = getElement(row[1])
details.innerHTML = `
<div style="text-align:right;position:absolute;top:1em;right:70px;font-size:1.2em">
<strong>${(100 * row[0]).toFixed(2)}%</strong> satisfaction
</div>
<div style="text-align:right;position:absolute;bottom:1em;right:70px;opacity:0.4">
(#${i + 1} from xbar=${row[2]}, n=${row[3]}, i=${row[4]})
</div>
`
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment