Другой возможный подход:
dupes <- c()
dt[, New := {
x <- !Letter %chin% dupes
dupes <- c(dupes, unique(Letter[x]))
x
}, by=.(Year, Month)]
Некоторые временные характеристики для справки ниже:
, если Letter является целым числом:
library(microbenchmark)
microbenchmark(mtd0=dt0[, New := !(Letter %in% dt0$Letter[dt0$Month<Month]), by=Month],
mtd1={
dt1[, v := FALSE]
dt1[unique(dt1, by="Letter"), on=.(Letter, Year, Month), v := TRUE]
},
mtd2={
dupes <- c()
dt2[, New := {
x <- !Letter %in% dupes
dupes <- c(dupes, unique(Letter[x]))
x
}, by=.(Year, Month)]
},
times=3L)
целочисленный выходной сигнал синхронизации:
Unit: milliseconds
expr min lq mean median uq max neval
mtd0 1293.3100 1318.775 1331.7129 1344.2398 1350.9143 1357.589 3
mtd1 377.1534 391.178 402.4423 405.2026 415.0868 424.971 3
mtd2 2015.2115 2020.926 2023.7209 2026.6400 2027.9756 2029.311 3
если буква является символом:
microbenchmark(mtd0=dt0[, New := !(Letter %chin% dt0$Letter[dt0$Month<Month]), by=Month],
mtd1={
dt1[, v := FALSE]
dt1[unique(dt1, by="Letter"), on=.(Letter, Year, Month), v := TRUE]
},
mtd2={
dupes <- c()
dt2[, New := {
x <- !Letter %chin% dupes
dupes <- c(dupes, unique(Letter[x]))
x
}, by=.(Year, Month)]
},
times=3L)
вывод времени:
Unit: milliseconds
expr min lq mean median uq max neval
mtd0 1658.5806 1689.8941 1765.9329 1721.2076 1819.6090 1918.0105 3
mtd1 849.2361 851.1807 852.8632 853.1253 854.6768 856.2283 3
mtd2 420.1013 426.0941 433.9202 432.0869 440.8296 449.5723 3
проверка:
> identical(dt2$New, dt1$v)
[1] TRUE
> identical(dt0$New, dt1$v)
[1] FALSE
данные:
set.seed(0L)
nr <- 1e7
dt <- unique(data.table(Letter=sample(nr/1e2, nr, replace=TRUE),
Year=sample(2014:2018, nr, replace=TRUE),
Month=sample(1:12, nr, replace=TRUE)))
setorder(dt, Year, Month)#[, Letter := as.character(Letter)]
dt0 <- copy(dt)
dt1 <- copy(dt)
dt2 <- copy(dt)
#for seed=0L, dt has about 4.8mio rows