R - Добавить столбец в data.table из расчета по относительному подмножеству - PullRequest
0 голосов
/ 26 апреля 2018

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

DT <- data.table("userId" = c("user1", "user1", "user1", "user1", "user2", "user2", "user2", "user2", "user2"),
                 "topicId" = "topic1",
                 "attempt" = c(1, 2, 3, 4, 1, 2, 3, 4, 5),
                 "score" = c(50, 0, 50, 20, 20, 100, 100, 100, 100))

   userId topicId attempt score
1:  user1  topic1       1    50
2:  user1  topic1       2     0
3:  user1  topic1       3    50
4:  user1  topic1       4    20
5:  user2  topic1       1    20
6:  user2  topic1       2   100
7:  user2  topic1       3   100
8:  user2  topic1       4   100
9:  user2  topic1       5   100

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

   userId topicId attempt score scoreDiffFromFirst scoreDiffFromPrev
1:  user1  topic1       1    50                 NA                NA
2:  user1  topic1       2     0                -50               -50
3:  user1  topic1       3    50                  0                50
4:  user1  topic1       4    20                -30               -30
5:  user2  topic1       1    20                 NA                NA
6:  user2  topic1       2   100                 80                80
7:  user2  topic1       3   100                 80                 0
8:  user2  topic1       4   100                 80                 0
9:  user2  topic1       5   100                 80                 0

Я пробовал следующее:

for(i in 2:max(DT$attempt)) {
  DT[attempt == i, scoreDiffFromFirst := score - DT[attempt == 1 & userId == userId & topicId == topicId, score]]
  DT[attempt == i, scoreDiffFromPrev := score - DT[attempt == i - 1 & userId == userId & topicId == topicId, score]]
}

, который работает, пока не достигнет номера попытки, который представлен не в каждой группе пользователей / тем. Это означает, что последняя строка неверна, как показано ниже, потому что у user1 нет 5-й попытки:

   userId topicId attempt score scoreDiffFromFirst scoreDiffFromPrev
1:  user1  topic1       1    50                 NA                NA
2:  user1  topic1       2     0                -50               -50
3:  user1  topic1       3    50                  0                50
4:  user1  topic1       4    20                -30               -30
5:  user2  topic1       1    20                 NA                NA
6:  user2  topic1       2   100                 80                80
7:  user2  topic1       3   100                 80                 0
8:  user2  topic1       4   100                 80                 0
9:  user2  topic1       5   100                 50**              80**

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

Заранее спасибо.


Ответы [ 3 ]

0 голосов
/ 26 апреля 2018

dplyr делает это легко. first и lag легко получают значения показателя в относительных позициях, тогда как group_by группирует строки по userId и topicId, а затем применяет анализ по группам, а не по таблице в целом.

DT <- DT %>%
    group_by(userId, topicId) %>%
    mutate(scoreDiffFromFirst = score - first(score),
           scoreDIffFromPrev = score - lag(score))

DT
# A tibble: 9 x 6
# Groups:   userId, topicId [2]
  userId topicId attempt score scoreDiffFromFirst scoreDIffFromPrev
  <fct>  <fct>     <dbl> <dbl>              <dbl>             <dbl>
1 user1  topic1       1.   50.                 0.               NA 
2 user1  topic1       2.    0.               -50.              -50.
3 user1  topic1       3.   50.                 0.               50.
4 user1  topic1       4.   20.               -30.              -30.
5 user2  topic1       1.   20.                 0.               NA 
6 user2  topic1       2.  100.                80.               80.
7 user2  topic1       3.  100.                80.                0.
8 user2  topic1       4.  100.                80.                0.
9 user2  topic1       5.  100.                80.                0.

Единственное отличие состоит в том, что scoreDiffFromFirst равно 0, а не NA в строках первой попытки. Если это не то, что вы хотите, вы можете просто заменить их:

DT[DT$attempt == 1, "scoreDiffFromFirst"] <- NA
0 голосов
/ 26 апреля 2018

Вы также можете использовать ifelse подход.

DT[, `:=`(
  scoreDiffFromFirst = ifelse(rowid(topicId) == 1, NA, score - first(score)), 
  scoreDiffFromPrev = c(NA, diff(score))), by = userId]
0 голосов
/ 26 апреля 2018

Вы можете использовать by=

DT[order(attempt), c("scoreDiffFromFirst", "scoreDiffFromPrev") := 
  .(replace(score, 1, NA) - first(score), score - shift(score))
, by=.(userId,topicId)]

# or
DT[order(attempt), `:=`(
  scoreDiffFromFirst = replace(score, 1, NA) - first(score), 
  scoreDiffFromPrev = score - shift(score)
), by=.(userId,topicId)]

, что дает

   userId topicId attempt score scoreDiffFromFirst scoreDiffFromPrev
1:  user1  topic1       1    50                 NA                NA
2:  user1  topic1       2     0                -50               -50
3:  user1  topic1       3    50                  0                50
4:  user1  topic1       4    20                -30               -30
5:  user2  topic1       1    20                 NA                NA
6:  user2  topic1       2   100                 80                80
7:  user2  topic1       3   100                 80                 0
8:  user2  topic1       4   100                 80                 0
9:  user2  topic1       5   100                 80                 0

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

library(data.table)

data.table 1.10.4.3

Самый быстрый способ изучения (авторы data.table): https://www.datacamp.com/courses/data-analysis-the-data-table-way

Документация: ?data.table, example(data.table) и browseVignettes("data.table")

Примечания к выпуску, видео и слайды: http://r -datatable.com

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