Как умножить каждую строку одной матрицы на другую матрицу в R? - PullRequest
1 голос
/ 19 февраля 2020

Для следующих двух матриц:

yy=matrix(c(1:40), nrow = 10, ncol = 8)
tt=diag(1:4)

Я хотел бы создать новую матрицу yy_new=matrix(NA, nrow = 10, ncol=ncol(tt)), умножив каждую строку и сначала 4 column из yy на tt. Например, для первой строки yy_new=yy[1,1:4]%*%tt, вторая строка - yy_new=yy[2,1:4]%*%tt. Наконец, я хочу получить среднее значение yy_new в каждом столбце как yy_new=apply(yy_new,2,mean). Следующий l oop работает хорошо, но для большого набора данных это занимает много времени.

 yy_new=matrix(NA, nrow = 10, ncol=ncol(tt))         
 for ( it in 1:10){
      for ( tim in 1:4){
        yy_new[it, tim]=yy[it,tim]*tt[tim,tim]
      }
    }
yy_new=apply(yy_new,2,mean)

аналогично, я хочу другую матрицу yy_new1, учитывая последние четыре столбца yy

 yy_new1=matrix(NA, nrow = 10, ncol=ncol(tt))

Как я могу сделать это эффективно, используя любую встроенную функцию или настраиваемую функцию? Любая помощь приветствуется.

1 Ответ

1 голос
/ 19 февраля 2020

Вот более короткая (и более быстрая) версия для yy_new

yy_new <- rowMeans(apply(yy[, 1:4], 1, function(row) row %*% tt))

Аналогично для последних 4 столбцов yy

yy_new1 <- rowMeans(apply(yy[, (ncol(yy)-3):ncol(yy)], 1, function(row) row %*% tt))

Обратите внимание, что rowMeans и colMeans обычно быстрее, чем apply(..., 1, mean) и apply(..., 2, mean).


Вот результаты microbenchmark сравнения

library(microbenchmark)
res <- microbenchmark(
    rowMeans_apply = {
        yy_new = rowMeans(apply(yy[, 1:4], 1, function(row) row %*% tt))
    },
    for_loop = {
        yy_new=matrix(NA, nrow = 10, ncol=ncol(tt))
         for ( it in 1:10){
              for ( tim in 1:4){
                yy_new[it, tim]=yy[it,tim]*tt[tim,tim]
              }
            }
    }
)
res
#Unit: microseconds
#           expr      min       lq      mean   median       uq       max neval
# rowMeans_apply   73.148   82.097  116.8959  101.329  123.863  1348.141   100
#       for_loop 3985.521 4141.633 5017.9808 4421.285 5020.425 18574.364   100

Обновление

В ответ на ваш комментарий вы можете сделать что-то вроде этого:

f <- function(x) rowMeans(apply(x, 1, function(row) row %*% tt))
sapply(split.default(as.data.frame(yy), rep(1:2, each = 4)), f)
#         1     2
#[1,]   5.5   5.5
#[2,]  31.0  31.0
#[3,]  76.5  76.5
#[4,] 142.0 142.0

Объяснение: split.default здесь разбивает data.frame на первые 4 и последние 4 столбца и сохраняет их как два data.frame s в list; затем мы используем от sapply до l oop через элементы list и вычисляем требуемое количество по запросу. Результирующий выходной объект является matrix.

...