Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Logarithmic Scale - Ranking in PHP

I am currently building a system that requires ranking based on an internal actions/score. The score itself can range from anywhere within 0 to 20000.

I need the function I create to rank users to return a value between 1-100. If this is impossible it would be fine to return any result sets over 100 as just 100. I am currently having difficulties ensuring creating a logarithmic algorithm for determining scores.

I have tried the following function:

echo 1 + sqrt(500 + 2000 * $score) / 50;

However the results this return do not vary enough for lower values and increase exponentially for higher ones.

Example input scores at low/average end of the scale are:

  • 0.15
  • 1
  • 7
  • 12

Example input at high end of the scale

  • 236.4
  • 1211
  • 17899.70

Any help would be greatly appreciated. Been stuck on this for a few days now. The above function is the best attempt I have so far however as advised there is not enough disparity between the low/medium results and too much between higher ones.

Thanks,

Daniel

like image 532
Daniel Benzie Avatar asked Dec 23 '15 13:12

Daniel Benzie


3 Answers

This is an open-ended question and there is no clear answer with different tradeoffs.. I'm not a PHP programmer, but something like the following should work.

# THESE PARAMETERS CONTROL THE RANKING ALGORITHM.
$rescale = 0;
$spread = 1;

function rescore ($n) {
    return log($n) + $rescale;
}

function rank ($scores) {
    return 100 / (1 + exp(- $spread * array_sum(array_map("rescore", $scores))));
}

You should choose $rescale so that the average score rescores to something close to 0. And play around with $spread until you're happy with how much your scores spread out.

The idea is that log turns a wide range of scores into numbers in a comparable range that can be positive or negative. Add a bunch of rescored scores together and you get an arbitrary real number. Then throw that into a logistic function (see https://en.wikipedia.org/wiki/Logistic_function for details) to turn that into a number in your desired range.

like image 162
btilly Avatar answered Nov 12 '22 00:11

btilly


Attempting to closely follow a definition in Wikepedia where "each mark on the [logarithmic] scale is the previous mark multiplied by a value," we set value^100 = 20000 and arrive at value = 1.104104805. Could this logarithmic scale then be implemented with a function akin to the following?

function rank($score){
  return log($score,1.104104805);
}

Output:

$scores = [0.15,1,7,12,236.4,1211,17899.70];

foreach ($scores as $score){
  echo "Score: " . $score . ", Rank: " . rank($score) . "\n";
}

/*
Score: 0.15, Rank: -19.156079885479
Score: 1, Rank: 0
Score: 7, Rank: 19.648736275112
Score: 12, Rank: 25.091228109202
Score: 236.4, Rank: 55.187884698844
Score: 1211, Rank: 71.683855953272
Score: 17899.7, Rank: 98.879704658993
*/
like image 2
גלעד ברקן Avatar answered Nov 12 '22 00:11

גלעד ברקן


thanks for the help. Here is what I ended up with (thanks to the help of Jake L Price)

The score varied slightly after the initial question (with 120,000 being the top end of the scale) however the logic for the algorithm needed to remain the same. As you can see below we used log * 10 to get a comprehensible low number. We then multiply this again by a number which ensures 120,000 has the top level of 100.

    echo $this->rank($score);

    public function rank($score)
        {
            //-- log reg time
            // 7.143963378055477 being the numberic multiplier to ensure 120,000 has the score of 100.
            $res = 7.143963378055477 * log($score * 10);
            return $res;
        }

This is now returning

$scores = [0.15,1,7,12,236.4,1211,17899.70, 120000];

    foreach ($scores as $score){
        echo "Score: " . $score . ", Rank: " . $this->rank($score) . "</br>";
    }

Output:

Score: 0.15, Rank: 2.896627883404
Score: 1, Rank: 16.449583579206
Score: 7, Rank: 30.351094421044
Score: 12, Rank: 34.201665683178
Score: 236.4, Rank: 55.495096060882
Score: 1211, Rank: 67.166020848577
Score: 17899.7, Rank: 86.407125230156
Score: 120000, Rank: 100
like image 2
Daniel Benzie Avatar answered Nov 12 '22 02:11

Daniel Benzie