Возможный подход:
stringr::word(DT$string_col, end = DT$first_n_words)
#output
[1] "A BB" "DD EEE FFFF" "AB DFD EFGD" "ABC"
Вот сравнение скорости для этого небольшого набора данных:
library(microbenchmark)
denis <- function(x){
x[,line := .I]
x[, output_string_col := gsub(paste0("^((\\w+\\W+){", first_n_words - 1, "}\\w+).*$"),"\\1", string_col),
by = line]
x[,("line") := NULL]
}
Tim <- function(x){
x[, output_string_col := apply(x, 1, function(x) {
gsub(paste0("^((\\w+\\W+){", as.numeric(x[2]) - 1, "}\\w+).*$"), "\\1", x[1])
})]
}
miss <- function(x){
x[, output_string_col := stringr::word(string_col, end = first_n_words)]
}
microbenchmark(
Tim(DT),
miss(DT),
denis(DT)
)
Unit: milliseconds
expr min lq mean median uq max neval cld
Tim(DT) 1.875036 1.926662 2.174488 1.971941 2.181196 12.83158 100 a
miss(DT) 1.452720 1.484245 1.710604 1.510905 1.592787 15.27196 100 a
denis(DT) 2.780183 2.864604 3.255014 2.948813 3.126542 18.78252 100 b
для большего набора данных:
DT <- DT[sample(1:4, 100000, replace = TRUE),]
Unit: seconds
expr min lq mean median uq max neval cld
Tim(DT) 13.924312 14.628571 15.030614 14.810397 15.840749 15.949039 5 b
miss(DT) 3.571372 3.939229 4.150258 4.237873 4.492383 4.510435 5 a
denis(DT) 11.291374 11.728155 13.362248 12.738197 13.478435 17.575077 5 b
Как указывалось в комментариях Дж. Гротендика, микробенчмарк, возможно, не самый правильный способ измерения производительности таблицы данных, поскольку DT изменяется от одной итерации к следующей без сброса ее к начальному значению.
Итакв следующие несколько строк производительность будет измеряться только один раз после создания таблицы данных
DT <- data.table(string_col = c("A BB CCC",
"DD EEE FFFF GDG",
"AB DFD EFGD ABC DBC",
"ABC DEF"),
first_n_words = c(2, 3, 3, 1))
set.seed(1)
ind <- sample(1:4, 100000, replace = TRUE)
DT1 <- DT[ind,]
system.time(Tim(DT1))
#output
user system elapsed
14.06 0.02 15.01
DT2 <- DT[ind,]
system.time(miss(DT2))
#output
user system elapsed
2.82 0.00 2.87
DT3 <- DT[ind,]
system.time(denis(DT3))
#output
user system elapsed
11.56 0.03 11.98
all.equal(DT1, DT2)
all.equal(DT2, DT3)