После того, как вы прочитали ваш вопрос несколько раз и проверили желаемый результат, похоже, что вам нужна адаптивная скользящая «уникальная» функция, выровненная по вправо (то есть предыдущим n дням ), с окном 3 дня.
Использование datatable должно быть возможным, и akrun предоставил неадаптивное решение с align = 'left'. Однако вы хотите выровнять = 'right' (по умолчанию).
library(data.table)
dt[, .(.(id)), day][
, frollapply(seq_len(.N), n = 3, FUN = function(i) uniqueN(unlist(V1[i])))
[1] NA NA 8 9 9
Обратите внимание, что
dt[, .(.(id)), day]
day V1
1: 1 1,6
2: 2 9, 6, 5,10
3: 3 5,7,6,2,9,3
4: 4 1, 4,10
5: 5 9, 7, 7,10, 7
К сожалению, data.table не предоставляет частичное (adaptive = TRUE) опция окна для функции frollapply
, в отличие от других (frollmean
и frollsum
).
Мы можем попробовать ...
nk <- function(x, k) c(seq.int(k), rep(k, x - k))
dt[, .(.(id)), day][
, frollapply(seq_len(.N), n = nk(.N, 3), FUN = function(i) uniqueN(unlist(V1[i])))
V1 V2 V3 V4 V5
1: 2 NA NA NA NA
2: 4 5 NA NA NA
3: 6 7 8 8 8
4: 3 9 9 9 9
5: 3 5 9 9 9
Но мы получаем data.table с 5 столбцами с ответами, скрывающимися в диагонали.
В итоге я использовал mapply
с пользовательской функцией N_unique
для подсчета уникальных значений в списке идентификаторов, возвращаемых скользящим окном. Мы все еще можем использовать частичную ширину окна с функцией nk
, определенной выше.
N_unique <- function(i, width, x){
uniqueN(unlist(x[(i - (width - 1)):i]))
}
dt2 <- dt[, .(.(id)), day][
, user_cnt := mapply(FUN = N_unique, i = seq_len(.N),
width = nk(.N, 3), MoreArgs = list(x = V1))][, V1:=NULL]
dt2
day user_cnt
1: 1 2
2: 2 5
3: 3 8
4: 4 9
5: 5 9
Данные :
dput(dt)
structure(list(day = c(1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L,
3L, 3L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L), id = c(1, 6, 9, 6, 5,
10, 5, 7, 6, 2, 9, 3, 1, 4, 10, 9, 7, 7, 10, 7)), row.names = c(NA,
-20L), class = c("data.table", "data.frame"), .internal.selfref = <pointer: 0x0bae2498>)
Примечание : Команда для создания dt
с использованием set.seed
привела к чему-то отличному от того, что предоставил OP.