Перекрестное соединение для вычисления новой переменной - PullRequest
1 голос
/ 02 апреля 2020

У меня есть набор игровых данных, и я наблюдаю количество очков одного игрока.

da = data.frame(points = c(144,186,220,410,433))

da                
  points
1    144
2    186
3    220
4    410
5    433  

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

ranges = data.frame(level = c(1,2,3,4,5), points_from = c(0,100,200,300,430), points_to = c(100,170,300,430,550))

ranges
  level points_from points_to
1     1           0       100
2     2         100       170
3     3         200       300
4     4         300       430
5     5         430       550  

Теперь я хочу вычислить новую переменную, которая указывает, насколько далеко игрок был от следующего уровня. Он рассчитывается по $ $ точкам / диапазонам $ points_to этого заданного уровня c.

Например, если у игрока 144 очка, а следующий уровень достигается при достижении 170 очков, прогресс на уровне 144 /170.

Таким образом, набор данных, который я хочу получить, выглядит следующим образом:

da_new = data.frame(points = c(144,186,220,410,433), points_to = c(170,300,300,430,550), level_progress = c(144/170,186/300,220/300,410/430,433/550))

da_new
  points points_to level_progress
1    144       170         0.8471
2    186       300         0.6200
3    220       300         0.7333
4    410       430         0.9535
5    433       550         0.7873

Как теперь я могу вычислить эту переменную?

Ответы [ 3 ]

3 голосов
/ 02 апреля 2020

Основная идея заключается в использовании merge(da, ranges, all = T) для выполнения "перекрестного соединения" между данными. Затем мы фильтруем, где points находится между points_from и points_to (что означает, что 186 отсутствует в окончательных данных).

library(dplyr)
merge(da, ranges, all = T) %>%
    # keep only where points fall between points_from and points_to
    filter(points >= points_from & points <= points_to) %>%
    mutate(level_progress = points / points_to)

  points level points_from points_to level_progress
1    144     2         100       170      0.8470588
2    220     3         200       300      0.7333333
3    410     4         300       430      0.9534884
4    433     5         430       550      0.7872727

Другой вариант - отфильтровать, где points <= point_to, и найти где points ближе всего к points_to (этот метод сохраняет 186):

merge(da, ranges, all = T) %>%
    filter(points <= points_to) %>%
    group_by(points) %>%
    slice(which.min(abs(points - points_to))) %>%
    mutate(level_progress = points / points_to)

  points level points_from points_to level_progress
   <dbl> <dbl>       <dbl>     <dbl>          <dbl>
1    144     2         100       170          0.847
2    186     3         200       300          0.62 
3    220     3         200       300          0.733
4    410     4         300       430          0.953
5    433     5         430       550          0.787
3 голосов
/ 02 апреля 2020

Вот базовое решение R с использованием findInterval

da_new <- da
da_new$points_to <- ranges$points_to[findInterval(da_new$points,c(0,ranges$points_to))]
da_new$level_progress <- da_new$points/da_new$points_to

, такое что

> da_new
  points points_to level_progress
1    144       170      0.8470588
2    186       300      0.6200000
3    220       300      0.7333333
4    410       430      0.9534884
5    433       550      0.7872727
0 голосов
/ 02 апреля 2020

с помощью dplyr,

df <- cbind(da,ranges)
da_new <- mutate(df, level_progress = points/points_to)[,c(1,4,5)]
...