Reputation: 3815
I have a vector of weight
and a list of the same length as weight
. I want to calculate
the weighted average of each element of the list using the weight
as shown below:
wt <- c(0.3, 0.5, 0.2)
temp_ls <- list(x = c(1, 2, 3, 4), y = c(5, 6, 7, 8), z = c(9, 10, 11, 12))
result_vec <- rep(length(temp_ls$x))
for(i in seq_along(temp_ls$x)){
temp_vec <- rep(NA, length(temp_ls))
for(j in seq_along(temp_ls)){
temp_vec[j] <- temp_ls[[j]][i]
}
result_vec[i] <- weighted.mean(temp_vec, wt)
}
result_vec
# 4.6 5.6 6.6 7.6
This approach seems way too complicated and long and wondered if any shorter method is there
using lapply
family.
Upvotes: 2
Views: 235
Reputation: 887971
An option is to transpose
the list
, loop over the list
and apply the weighted.mean
library(dplyr)
library(purrr)
temp_ls %>%
transpose %>%
map_dbl(~ weighted.mean(flatten_dbl(.x), w = wt))
#[1] 4.6 5.6 6.6 7.6
Or another approach would be to enframe
the list
to a two column tibble, then unnest
the list
element and do a group by weighted.mean
library(tibble)
library(tidyr)
library(data.table)
enframe(temp_ls) %>%
mutate(wt = wt) %>%
unnest(c(value)) %>%
group_by(grp = rowid(name)) %>%
summarise(out = weighted.mean(value, w = wt), .groups = 'drop') %>%
pull(out)
#[1] 4.6 5.6 6.6 7.6
Or using aggregate
after stack
ing into two column data.frame in base R
aggregate(values ~ grp, transform(stack(temp_ls),
grp = ave(seq_along(ind), ind, FUN = seq_along)),
FUN = weighted.mean, w = wt)
# grp values
#1 1 4.6
#2 2 5.6
#3 3 6.6
#4 4 7.6
Or using mapply
do.call(mapply, c(FUN = function(...) weighted.mean(c(...), w = wt),
unname(temp_ls)))
#[1] 4.6 5.6 6.6 7.6
Or with Map
unlist(do.call(Map, c(f = function(...) weighted.mean(c(...),
w = wt), unname(temp_ls))))
Or more compactly
apply(do.call(cbind, temp_ls), 1, weighted.mean, w = wt)
#[1] 4.6 5.6 6.6 7.6
Upvotes: 4