Расчет ранга с учетом метки времени в сгруппированных данных - PullRequest
2 голосов
/ 03 апреля 2020

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

Пример данных, включая ожидаемый ранг:

da = data.frame(player = c(1,1,1,2,2,2,3,3,3), date_sec = c(1451665633,1451665693,1451665721,1451665627,1451665692,1451665738,1451665626,1451665684,1451665765), points = c(100,150,200,130,140,230,80,90,100), rank = c(2,1,1,1,1,1,1,3,3))

da
  player   date_sec points rank
1      1 1451665633    100    2
2      1 1451665693    150    1
3      1 1451665721    200    1
4      2 1451665627    130    1
5      2 1451665692    140    1
6      2 1451665738    230    1
7      3 1451665626     80    1
8      3 1451665684     90    3
9      3 1451665765    100    3

Например, игрок 2 имеет date_se c 1451665738 ранг 1, потому что на данный момент ни один другой игрок не имеет у меня было больше очков.

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

library(dplyr)

da2 = mutate(da, day = as.Date(as.POSIXct(date_sec, origin="1970-01-01"))) %>%
   group_by(player, day) %>%
   mutate(my_ranks = order(order(points, day, decreasing=TRUE)))

da2

A tibble: 9 x 6
# Groups:   player, day [3]
  player   date_sec points  rank day        my_ranks
   <dbl>      <dbl>  <dbl> <dbl> <date>        <int>
1      1 1451665633    100     2 2016-01-01        3
2      1 1451665693    150     1 2016-01-01        2
3      1 1451665721    200     1 2016-01-01        1
4      2 1451665627    130     1 2016-01-01        3
5      2 1451665692    140     2 2016-01-01        2
6      2 1451665738    230     2 2016-01-01        1
7      3 1451665626     80     3 2016-01-01        3
8      3 1451665684     90     3 2016-01-01        2
9      3 1451665765    100     3 2016-01-01        1

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

У кого-нибудь есть идея?

1 Ответ

1 голос
/ 04 апреля 2020

Во-первых, я бы использовал complete, чтобы у вас была строка для каждой комбинации player / date_sec. Это позволит упростить сравнение для каждого момента времени.

Далее я бы использовал fill, чтобы перенести самый последний счет каждого игрока. Баллы должны быть отсортированы / упорядочены до этого.

Затем, поскольку у вас есть оценка для каждой отметки времени, вы можете group_by(date_sec) и каждый раз заказывать игроков для ранжирования.

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

library(tidyverse)

da %>%
  complete(player, date_sec) %>%
  group_by(player) %>%
  arrange(date_sec) %>%
  fill(points) %>%
  group_by(date_sec) %>%
  mutate(my_ranks = order(order(points, decreasing = TRUE))) %>%
  right_join(da)

Вывод

Joining, by = c("player", "date_sec", "points", "rank")
# A tibble: 9 x 5
# Groups:   date_sec [9]
  player   date_sec points  rank my_ranks
   <dbl>      <dbl>  <dbl> <dbl>    <int>
1      1 1451665633    100     2        2
2      1 1451665693    150     1        1
3      1 1451665721    200     2        1
4      2 1451665627    130     1        1
5      2 1451665692    140     2        1
6      2 1451665738    230     1        1
7      3 1451665626     80     3        1
8      3 1451665684     90     3        3
9      3 1451665765    100     3        3
...