Вы можете использовать apply
подход. Должно занять около 20 секунд для 1e6 строк.
dt$mean.column <- apply(dt[2:3], 1, function(x)
mean(dt$value[seq(x[1], x[2])]))
# value start finish mean.column
# 1 1 1 3 2.0
# 2 2 4 7 5.5
# 3 3 5 8 6.5
# 4 4 8 9 8.5
# 5 5 6 10 8.0
# 6 6 3 10 6.5
# 7 7 2 4 3.0
# 8 8 1 10 5.5
# 9 9 9 10 9.5
# 10 10 4 8 6.0
Это примерно на 30% быстрее, хотя , если мы Vectorize
функция seq
, как это :
FUNV <- Vectorize(function(x, y) seq(x, y))
dt$mean.column2 <- with(dt, sapply(FUNV(start, finish), function(x) mean(value[x])))
stopifnot(all.equal(dt$mean.column, dt$mean.column2))
Редактировать: FUNV()
на самом деле может быть улучшен с использованием чего-то более быстрого, чем seq()
, например seq.int
или :
.
FUNV2 <- Vectorize(function(x, y) seq.int(x, y))
FUNV3 <- Vectorize(function(x, y) x:y)
А вот и микробенчмарка :
microbenchmark::microbenchmark(
apply=apply(df.L[2:3], 1, function(x) mean(df.L$value[seq(x[1], x[2])])),
FUNV=with(df.L, sapply(FUNV(start, finish), function(x) mean(value[x]))),
FUNV2=with(df.L, sapply(FUNV2(start, finish), function(x) mean(value[x]))),
FUNV3=with(df.L, sapply(FUNV3(start, finish), function(x) mean(value[x]))),
data.table={ ## see Cole's answer
dt.L[, id := .I]
dt.L[dt.L, on=.(id >= start, id <= finish), .(i.id, i.value, mean_col=mean(x.value)),
by=.EACHI, allow.cartesian=T]},
times=3L)
# Unit: seconds
# expr min lq mean median uq max neval cld
# apply 26.736665 26.740363 28.701785 26.744062 29.68435 32.624629 3 c
# FUNV 24.983665 26.513645 28.007959 28.043625 29.52011 30.996587 3 c
# FUNV2 15.371551 16.031383 16.848238 16.691215 17.58658 18.481949 3 b
# FUNV3 14.156043 14.266123 14.436663 14.376203 14.57697 14.777744 3 b
# data.table 2.138956 2.323735 2.426432 2.508515 2.57017 2.631825 3 a
Проверено на:
library(data.table)
dt <- data.table(value=c(10, 1:9), start=c(1, 4, 5, 8, 6, 3, 2, 1, 9, 4),
finish=c(3, 7, 8, 9, 10, 10, 4, 10, 10, 8))
df <- as.data.frame(df)
set.seed(42)
df.L <- df[sample(1:nrow(df), 1e6, replace=TRUE), ]
dt.L <- dt[sample(1:nrow(dt), 1e6, replace=TRUE), ]