Вот способ сделать это, используя sapply
.
Первое, что я делаю, это создаю список поиска: для каждого элемента я создаю список индекса, который я должен использовать для max:
> # First make it an iteratable
> search_list = sapply(df$Width, function(x){1:x})
> search_list[1:2]
[[1]]
[1] 1 2
[[2]]
[1] 1 2
> # Then add i
> search_list = sapply(1:length(search_list), function(i){search_list[[i]] + i})
> search_list[1:2]
[[1]]
[1] 2 3
[[2]]
[1] 3 4
Теперь, когда я знаю, по какому элементу искать, я применяю max:
> result <- sapply(search_list, function(elt){max(df$z[elt], na.rm = TRUE)})
Warning message:
In max(df$z[elt], na.rm = TRUE) :
no non-missing arguments to max; returning -Inf
> result[1:3]
[1] 86.0 66.2 66.2
Чтобы избежать предупреждения, можно добавить проверку для контроля того, что max не будет выполняться для NULL, но это немного замедлит код.
Например, вы можете создать свою собственную функцию max:
my_max <- function(x){ if (any(!is.na(x))){max(x, na.rm = TRUE)} else{NA}}
Сравнение эффективности:
Вот некоторый код, который делает это циклично, да еще и просто в функции:
sapply_way <- function(df){
search_list = sapply(df$Width, function(x){0:(x - 1)})
search_list = sapply(1:length(search_list), function(i){search_list[[i]] + i})
return(sapply(search_list, function(elt){max(df$z[elt], na.rm = TRUE)}))
}
loop_way <- function(df){
res <- list()
for (i in 1:nrow(df)){
res <- c(res, max(df$z[i:(i+df$Width[i] - 1)], na.rm = TRUE))
}
return(res)
}
С @symbolrush было предложено только одно хранилище:
one_sapply_way <- function(df){
sapply(1:nrow(df), function(i) {max(df$z[(i + 1):min((i+df$Width[i]), nrow(df))])})
}
С dplyr, предложенным @ Len
dplyr_way <- function(df){
df %>%
mutate(newmaxvar = rollapply(lead(df$z,1), df$Width, FUN = max, na.rm = T, align = "left", partial = T))
}
Используя библиотеку микробенчмарков, я сравниваю их:
> microbenchmark(
+ sapply_way(df),
+ loop_way(df),
+ one_sapply_way(df),
+ dplyr_way(df)
+ )
Unit: milliseconds
expr min lq mean median uq max neval
sapply_way(df) 1.874739 2.029868 2.826689 2.126493 2.284847 13.071267 100
loop_way(df) 2.965918 3.222217 3.917204 3.331158 3.522210 9.327948 100
one_sapply_way(df) 4.002259 4.537584 5.318989 4.672185 4.968806 21.825913 100
dplyr_way(df) 4.770276 5.418942 7.573212 5.693570 5.968198 104.622040 100
Как видите, sapply
быстрее. И если ваш df
станет больше, это будет еще интереснее.