Как рассчитать процентильный ранг для точечных итогов за разные промежутки времени? - PullRequest
3 голосов
/ 17 июня 2009

На веб-сайте, основанном на PHP и CodeIgniter, пользователи могут зарабатывать репутацию за различные действия, в отличие от переполнения стека. Каждый раз, когда присуждается репутация, в таблице MySQL создается новая запись с user_id, поощряемым действием и значением этого набора баллов (например, 10 репутации). Одновременно обновляется поле в таблице users, reputation_total.

Поскольку все это бессмысленно без системы отсчета, я хочу показать пользователям их процентильный ранг среди всех пользователей. Для полной репутации это кажется достаточно простым. Допустим, мой user_id - 1138. Просто подсчитайте количество пользователей в таблице users с на 1009 * меньше, чем у меня, подсчитайте общее количество пользователей и разделите, чтобы найти процент пользователей с более низкой репутацией, чем у меня. Это будет процентиль ранга пользователя 1138, верно? Легко!

Но я также показываю итоги репутации за разные промежутки времени - например, заработанные за последние семь дней, что включает в себя запрос к таблице репутации и суммирование всех моих очков, заработанных с данной даты. Я также хотел бы показать процентильный ранг для разных промежутков времени - например, я могу быть 11-м процентилем в целом, но 50-м процентилем в этом месяце и 97-м процентилем сегодня.

Кажется, мне пришлось бы пройтись и найти итоги репутации всех пользователей за данный промежуток времени, а затем посмотреть, куда я попадаю в эту группу, не так ли? Разве это не ужасно громоздко? Какой лучший способ сделать это?

Большое спасибо.

Ответы [ 2 ]

1 голос
/ 17 июня 2009

Я могу придумать несколько вариантов на макушке здесь:

  1. Как вы упомянули, суммируйте очки репутации, заработанные за указанный промежуток времени, и рассчитайте процентильные ранги на основе этого.

  2. Отслеживание обновлений для reputation_total на ежедневной основе - поэтому у вас есть таблица с user_id, date, reputation_total.

  3. Добавьте несколько новых столбцов в пользовательскую таблицу (reputation_total, reputation_total_today, reputation_total_last30days и т. Д.) Для каждого временного диапазона. Вы также можете нормализовать это в отдельной таблице (reputation_totals), чтобы избежать необходимости добавлять новый столбец для каждого промежутка времени, который вы хотите отслеживать.

Вариант № 1 является самым простым, но, вероятно, он будет медленным, если в вашей таблице транзакций репутации будет много строк - он не будет хорошо масштабироваться, особенно если вам нужно рассчитать их в реальном времени.

Вариант № 2 будет требовать больше памяти с течением времени (одна строка на пользователя в день), но, вероятно, будет значительно быстрее, чем непосредственный запрос таблицы транзакций.

Вариант № 3 менее гибок, но, вероятно, будет самым быстрым вариантом.

Оба варианта 2 и 3, вероятно, потребуют пакетной обработки для вычисления итогов на ежедневной основе, так что это тоже необходимо учитывать.

Я не думаю, что какой-либо вариант обязательно является лучшим - все они связаны с различными компромиссами скорости / места для хранения / сложности / гибкости. То, что вы будете делать, в конечном итоге будет зависеть от требований, предъявляемых к вашему заявлению.

1 голос
/ 17 июня 2009

Я не понимаю, почему это было бы слишком сложно. Как правило, все, что вам нужно, это добавить в предложение WHERE запрос, ограничивающий результаты, например:

WHERE DatePosted between @StartOfRange and @EndOfRange
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...