Алгоритм составления Top10 чего угодно

В каждом сборнике советов о том как сделать блог более популярным есть "Напишите Top10 чего-то". Вот я решил написать Top10. Но как истинный программист, вместо 10 бессмысленных фактов написал алгоритм как правильно выбирать Top10 чего-то.

Допустим, у вас есть сайт со статьями и вы хотите сделать Top10 статей, учитывая количество их просмотров. Не торопитесь, подумайте сначала, зачем вы хотите это сделать. Наверное, чтобы показать людям статьи, которые могут быть им наиболее интересны. Но показывая одни и те же Top10, вы искусственно увеличиваете количество просмотров статей, которые находятся в топе и они, возможно, случайно туда попав, уже никогда не исчезнут. В то же время посещаемость надо учитывать, потому что всё же корреляция посещаемость-интересность есть.

В моём алгоритме, чем больше рейтинг, тем выше будет вероятность появления записи в топе и вероятность более высокого положения там. Записи с нулевым рейтингом появляются только тогда, когда показаны записи с ненулевым рейтингом и выбираются случайно.

Используется функция примерно так

PHP:
  1. function test() {
  2.     $a = array(
  3.         'Item with rating 10' => 10,
  4.         'Item with rating 8' => 8,
  5.         'Item with rating 5' => 5,
  6.         'Item with rating 3' => 3,
  7.         'Item with rating 1' => 1,
  8.         'Item with rating 0 #1' => 0,
  9.         'Item with rating 0 #2' => 0,
  10.         'Item with rating 0 #3' => 0,
  11.         'Item with rating 0 #4' => 0,
  12.         'Item with rating 0 #5' => 0,
  13.         'Item with rating 0 #6' => 0,
  14.         'Item with rating 0 #7' => 0,
  15.         'Item with rating 0 #8' => 0,
  16.         'Item with rating 0 #9' => 0,
  17.     );
  18.  
  19.     echo('<pre>');
  20.     print_r(getRandomTop($a));
  21.     print_r('----------------');
  22.     print_r(getRandomTop($a));
  23.     print_r('----------------');
  24.     print_r(getRandomTop($a));
  25.     echo('</pre>');
  26.  
  27.     exit;
  28. }

Вот пример того, что выводится:

PHP:
  1. (
  2.     [0] => Item with rating 8
  3.     [1] => Item with rating 10
  4.     [2] => Item with rating 5
  5.     [3] => Item with rating 1
  6.     [4] => Item with rating 3
  7.     [5] => Item with rating 0 #2
  8.     [6] => Item with rating 0 #1
  9.     [7] => Item with rating 0 #2
  10.     [8] => Item with rating 0 #8
  11.     [9] => Item with rating 0 #4
  12. )
  13.  
  14. ----------------
  15.  
  16. (
  17.     [0] => Item with rating 10
  18.     [1] => Item with rating 5
  19.     [2] => Item with rating 8
  20.     [3] => Item with rating 1
  21.     [4] => Item with rating 3
  22.     [5] => Item with rating 0 #3
  23.     [6] => Item with rating 0 #9
  24.     [7] => Item with rating 0 #9
  25.     [8] => Item with rating 0 #3
  26.     [9] => Item with rating 0 #1
  27. )
  28.  
  29. ----------------
  30.  
  31. (
  32.     [0] => Item with rating 10
  33.     [1] => Item with rating 8
  34.     [2] => Item with rating 3
  35.     [3] => Item with rating 5
  36.     [4] => Item with rating 1
  37.     [5] => Item with rating 0 #7
  38.     [6] => Item with rating 0 #1
  39.     [7] => Item with rating 0 #8
  40.     [8] => Item with rating 0 #7
  41.     [9] => Item with rating 0 #5
  42. )

Естественно, лучше применять хитрые оценки для выставления рейтингов, например,
(1000 - кол-во дней с опубликования)+(100 * кол-во комментариев)+(кол-во просмотров)
Ну и можно применять это к "лучшим" пользователям, комментариям, товарам,...

Вот сама функция:

PHP:
  1. /**
  2. * Get random top $count items depending of $list values
  3. *
  4. * @param array $list Hash - $item=>$value. The greater is value the more chances it has to get to top
  5. * @param integer $count Max count of result. If count($list)<=$count then count($result)==count($list)
  6. * @return array Top $count items
  7. */
  8. function getRandomTop($list, $count = 10) {
  9.     $result = array();
  10.     arsort($list); // sort $list by values descending
  11.  
  12.     // select random items among ones with values>0
  13.     $total = array_sum($list); // sum of $list values (not keys)
  14.     while ($total!=0 && count($result)<$count) {
  15.         $sum = 0;
  16.         foreach ($list as $key=>$value) {
  17.             $rand = mt_rand(1, $total);
  18.             $sum += $value;
  19.  
  20.             if ($rand <= $sum) {
  21.                 $result[] = $key;
  22.                 unset($list[$key]);
  23.                 break;
  24.             }
  25.         }
  26.  
  27.         $total = array_sum($list);
  28.     };
  29.  
  30.     // select random items with value==0
  31.     while (count($result)<$count && !empty($list)) {
  32.         $item = array_rand($list);
  33.         $result[] = $item;
  34.         unset($list[$item]);
  35.     }
  36.  
  37.     return $result;
  38. }


Понравилось?

  1. Подпишись через RSS
  2. Расскажи о http://php.southpark.com.ua друзьям.
    Все способы хороши: ICQ, E-mail, свой блог, комментарий в чужом блоге или сообщение на форуме
  3. Добавь статью на news2.ru, Хабрахабр или в закладки

Огромное спасибо!

И не стесняйтесь комментировать - у меня стоит плагин, который убирает rel="nofollow" у людей, которые написали больше 5 комментариев.

RSS feed | Trackback URI

11 комментариев »

Comment by FX Poster Subscribed to comments via email
2007-12-08 20:15:44

pr($this->getRandomTop($a));
pr('----------------');
pr($this->getRandomTop($a));
pr('----------------');
pr($this->getRandomTop($a));

$this убери...

 
2007-12-08 20:55:57

Спасибо, убрал и сделал так, чтобы работало без CakePHP.
Скопировал со своего кода, а у меня функции редко вне классов находятся :)

 
2007-12-09 10:38:22

почему нельзя сделать одним SQL запросом ?
Рейтинг - это просто атрибут у статьи.

 
2007-12-09 11:31:55

Прочитай ещё раз абзац о вероятности попадания в топ. Специально же жирным выделил :)
SQL-запросом будут выводиться одни и те же записи и это будет увеличивать их рейтинг.
"Богатые станут ещё богаче, бедные - ещё беднее"
getRandomTop пытается с этим как-то бороться, но при этом рейтинг всё же учитывать.

 
Comment by larin Subscribed to comments via email
2007-12-09 16:19:24

Владимир, замечательная идея! У меня нечто похожее есть на одном сайте, там по похожему принципу строится облако тегов. Я это делал для того чтоб облако не было статичным уже через месяц существования проекта.

 
2007-12-09 21:27:59

Анатолий, аналогичная практика :-)

 
Comment by Антон Subscribed to comments via email
2007-12-18 09:07:37

Владимир, немного не по теме поста хочу сказать. Сейчас копировал некоторые ваши тексты в Вики -- написал парсер, который циферки подчищает. Попробуйте скопировать свой код из блоков. Цифры разметки слева копируются вместе с ним. Может стоит убрать ?
(win, ff)

 
2007-12-18 18:14:59

Я тоже не люблю, когда копируются цифры или когда во вставленном коде пробелы вместо табов.
Поэтому поставил специальный плагин в котором справа сверху есть надпись "plain text".

Если нажать "plain text", то уберётся разметка и цифры.

 
2007-12-18 18:43:27

Ну вот, похоже русскому программисту легче парсер написать, чем кнопку найти :-) Спасибо.

 
Comment by Дмитрий Subscribed to comments via email
2008-01-16 12:02:39

Здраствуйте
Очень интересненькая задачка и решение

Хочу поделиться одним решением, возможно будет полезным - когда делал у себя что-то похожее, для отсеивания тех, кто заинтересовался объектом, увидев его в топе и соответсвенно щелкал по ссылке на этот объект -> статистика не учитывала переход к объекту в случае если referer - страница с рейтингом

 
2008-01-17 11:01:21

@Дмитрий:
действительно хорошая идея. хотя я бы просто делал бы просто вес такого визита меньше - например, 1% от обычного захода.

 
Имя (required)
E-mail (required - never shown publicly)
URL
Текст комментария
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> in your comment.