views:

1129

answers:

3

My language is PHP, but the algorithm should be fairly universal.

I have an associative array of (let's say) ratings and number of times that rating has been given.

$ratings = array(
    1 => 1,
    2 => 3,
    3 => 6,
    4 => 3,
    5 => 3
);

This is the equivalent of: [1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5], but given the numbers I'm working with, it would be quite inefficient to convert from the first form to the second.

What would be the algorithm to calculate the mean of the above numbers?

+12  A: 

Try this:

$total = 0;
$count = 0;
foreach($ratings as $number=>$frequency) {
  $total += $number * $frequency;
  $count += $frequency;
}
return $total / $count;
Ray Hidayat
You might have to convert one of the numbers to double in the return line, I can't remember whether PHP does integer division.
Ray Hidayat
PHP's cool with all that!
nickf
If there was a "duel the accepted answer" button, I would click it here :)
Sparr
IMHO, this is not the "mean" calculation but the "average" calculation. As the answer is accepted, I guess nickf was looking for an "average" calculation
Ghislain Leveque
+8  A: 

Wouldn't this work?

$total = 0;
$sum = 0;
foreach ($ratings as $k => $v) {
  $total += $k * $v;
  $sum += $v;
}
echo $total / $sum;

EDIT: Well, I look silly, since someone beat me to it. Oh well.

Sasha
Sorry! Our code is pretty much exactly the same though!
Ray Hidayat
Yeah, I noticed that - that's pretty crazy.
Sasha
+1 for the effort. :)
andyk
+2  A: 

Doubt I can beat the accepted answer, but I find that built in looping functions run faster than scripted loops. Not sure how well the calls to $multiply are going to be optimized. If this is really slow then I expect someone will point it out in a comment.

function multiply( $k , $v ) { return $k * $v; }
return array_sum( array_map( 'multiply' , array_keys($ratings) , $ratings ) ) / array_sum( $ratings );
Sparr
+1 for the PHP implementation. As for performance though: With an array of 10000 'points' each with between 0 and 255 votes, averaged 100 times: Your function: 4.294s, Accepted solution: 3.45115s
nickf
So close! It's actually not quite that close when I benchmark it myself, but still in the running. I notice you edited out my incorrect lambda function syntax, if you have PHP 5.3 you should give it a try with an anonymous function defined inline in the array_map.
Sparr