Векторизация взвешенных арифметических операций по матрице

Мне было интересно, есть ли способ векторизовать взвешенную арифметику по матрицам. например для вычисления средневзвешенного значения values ниже заданного weights:

set.seed(12321)
values = matrix(sample(10:40, 6, replace = TRUE), ncol = 2)
weights = matrix(sample(1:5, 6, replace = TRUE), ncol = 2)

Мы можем:

w.mean = numeric()

for (i in 1:dim(values)[1]){
  w.mean[i] = stats::weighted.mean(x=values[i,], w =  weights[i,])
}

Но это не быстро для больших матриц. Мне было интересно, есть ли полностью векторизованный способ с использованием семейства apply или aggregate или подобного.


person aljabadi    schedule 04.02.2019    source источник
comment
Чтобы преобразовать ваш код из for в sapply, вы можете сделать sapply(1:nrow(values), function(i) weighted.mean(values[i, ], weights[i, ])), но я не уверен, что это эффективнее, чем цикл for.   -  person Ronak Shah    schedule 04.02.2019
comment
Цикл for, вероятно, настолько быстр, насколько это возможно. Вы можете попробовать matrixstats::weightedMean, который будет быстрее. Что представляет собой «большая» матрица (т. е. много столбцов, много строк, и то, и другое)?   -  person Hugh    schedule 04.02.2019
comment
может быть apply(abind::abind(values, weights, along = 3), 1, function(x) weighted.mean(x[,1], x[,2]))   -  person alistaire    schedule 04.02.2019


Ответы (2)


вы можете попробовать сгруппировать свои значения и веса в одном data.frame

value_weight <- data.frame(group = rep(1:2, each = 3), 
                           value = sample(10:40, 6, replace = TRUE), 
                           weight = sample(1:5, 6, replace = TRUE))

а затем с помощью библиотеки plyr

ddply(value_weight, .(group), # split the data frame according to group
      function(x) data.frame(wret = weighted.mean(x$value, x$weight)))

больше информации здесь

person Victor Maxwell    schedule 04.02.2019

Всем спасибо. Действительно содержательные ответы. Я протестировал их и sapply оказался быстрым, а после этого abind. Однако в моем исходном наборе данных у меня были группы, которые я суммировал по группам, используя dcast. Однако после того, как я увидел предложение для ddply, я вернулся к нему. Я понял, что использование data.table::data.table делает его на несколько порядков быстрее:

n = 1000
DT = data.table(id = sample(LETTERS[1:10], size = n, replace = TRUE),
                value = sample(seq(20,30), size = n, replace = TRUE),
                weight = sample(seq(1,5), size = n, replace = TRUE))

wtd_var = DT[,lapply(.SD,function(x)(weightedVar(as.numeric(x),w=weight))),by=id,.SDcols='value']
wtd_var

data.table действительно крут!

person aljabadi    schedule 05.02.2019