Star Ratings

I’ve been awfully busy programming lately. My Django-based side project is coming along well and I hope to have it ready for use in a few weeks. Please don’t ask more about it, that’s really all I can say for now. Anyways, I came across an interesting little math problem today and was hoping some skilled programmers out there could come up with a more elegant solution than mine.

Problem: Star Ratings

People can rate cheeseburgers on my website with a star rating of 0-5 stars (whole stars only), 5 being mighty tasty and 0 being disgusting. I would like to show the average of everyone’s ratings of a particular cheeseburger to the nearest half star. I have already calculated the average rating as a float (star_sum) and the total number of people that rated the particular cheeseburger (num_raters). The result should be stored as a float in a variable named “stars.”

My Solution (in Python):

# round to one decimal place and
# separate into whole and fractional parts
parts = str(round(star_sum/num_raters, 1)).split('.')
whole = int(parts[0])
frac = int(parts[1])
if frac < 3:
___frac = 0
elif frac > 7:
___frac = 0
___whole += 1
else:
___frac = 5
# recombine for a star rating rounded to the half
stars = float(str(whole)+’.'+str(frac))

Mmmm… In-N-Out Burgers… Please leave a comment if you’ve got a better solution.

Update (hooray!)

I’ve updated my solution to:

stars = round(star_sum*2/num_raters)/2

I knew there was a way to do this mathematically, I just couldn’t remember how. I suppose the same trick would work for rounding to thirds, fourths, etc. Thanks so much to r, Christopher Finke, and Bob for the better approach.

9 Comments

  1. r

    Posted April 19, 2007 at 2:11 pm | Permalink

    might be misunderstanding what you’re trying to do, but

    formatting an average value to the nearest half (forgive the lack of python syntax):

    round(AvgValue * 2) / 2

    should work

  2. Posted April 19, 2007 at 2:58 pm | Permalink

    If you’re willing to change your boundaries to .75 and .25 (rather than .7 and .3), you could do this:

    stars = float(round(star_sum / num_raters * 2) / 2);

  3. J Taylor

    Posted April 19, 2007 at 5:55 pm | Permalink

    #I don’t program in Python and I’m not sure if this code has the correct syntax
    #Calculate rating out of 10
    rating = round(star_sum*2/num_raters, 1)
    #Calculate number of whole stars by integer division
    whole_stars = rating // 2
    #Calculate number of half stars by remainder
    half_stars = rating % 2
    #Combine into one number
    stars = whole_stars + (half_stars * 0.5)

  4. Posted April 19, 2007 at 6:02 pm | Permalink

    In general you should never have to convert a number to a string. If you needed to get the fractional and whole parts of a float there’s math.modf(someFloat) which returns (frac, whole). Anyway, I would probably just double the sum, round, then half it.

    stars = 0.5 * round((2.0 * star_sum) / num_raters)

  5. Posted April 20, 2007 at 12:13 am | Permalink

    I gave this to some of my co-workers (system administrators and software developers) as a challenge. Only 2 out of 7 could get it right (both software developers - one of them an apprentice).

    I immediately knew the solution when I finished reading the problem at hand, and I would have done it exactly like Bob did. I guess it’s just the experience in solving problems like this one that enables you to see this solution.

  6. Posted April 20, 2007 at 10:11 am | Permalink

    Here’s an idea:

    stars = float(str(round(float(star_sum)/num_raters,1)).split(’.')[0]) + {’0′:0, ‘1′:0, ‘2′:0, ‘3′:0.5, ‘4′:0.5, ‘5′:0.5, ‘6′:0.5, ‘7′:0.5, ‘8′:1.0,’9′:1.0}[str(round(float(star_sum)/num_raters,1)).split(’.')[1]]

    or more concisely,

    stars = round(float(star_sum+star_sum)/num_raters)/2

  7. Posted April 20, 2007 at 10:52 am | Permalink

    Alexander - seems to me like something people would remember if they had used it before. I’d never had to round like that before and I kept thinking that there was some way to do it mathematically, but I couldn’t remember how. I hope it’s not as important to know the best solution as it is to know a better solution exists.

    Richard and Christopher - I suppose I was being too generous with .7. I don’t mind the rounding difference and I doubt the cheeseburgers will either.

    Everybody - Thanks so much for the help! I suppose I could have looked around more for the solution but now I feel like my blog was actually useful.

  8. Posted April 21, 2007 at 1:48 pm | Permalink

    Hey Leah… Why Django over Ruby on Rails? I picked Django too, and we all have our reasons. Write a post about it!!!

  9. Tom

    Posted April 23, 2007 at 8:07 am | Permalink

    A perfect example of why everyone’s first course in programming should be Fortran.