Нахождение кумулятивной суммы и затем усреднение значений в R - PullRequest
0 голосов
/ 02 ноября 2018

Я хочу вычислить совокупную сумму для первого (n-1) columns (если у нас есть n матрица столбцов) и затем усреднить значения. Я создал образец матрицы для выполнения этой задачи. У меня есть следующая матрица

ma = matrix(c(1:10), nrow = 2, ncol = 5)
ma
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    3    5    7    9
[2,]    2    4    6    8   10

Я хотел найти следующее

ans = matrix(c(1,2,2,3,3,4,4,5), nrow = 2, ncol = 4)
ans
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    2    3    4    5

Ниже приведены мои r функции.

ColCumSumsAve <- function(y){
  for(i in seq_len(dim(y)[2]-1)) {
    y[,i] <- cumsum(y[,i])/i
  }
}
ColCumSumsAve(ma)

Однако, когда я запускаю вышеупомянутую функцию, она не производит никакого вывода. Есть ли ошибки в коде?

Спасибо.

Ответы [ 4 ]

0 голосов
/ 02 ноября 2018

Все, что вам нужно, это rowMeans:

nc <- 4
cbind(ma[,1],sapply(2:nc,function(x) rowMeans(ma[,1:x])))
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    2    3    4    5
0 голосов
/ 02 ноября 2018
k <- t(apply(ma,1,cumsum))[,-ncol(k)]
for (i in 1:ncol(k)){
  k[,i] <- k[,i]/i
}
k

Это должно работать.

0 голосов
/ 02 ноября 2018

Было несколько ошибок.

Решение

Вот что я тестировал и что работает:

colCumSumAve <- function(m) {
  csum <- t(apply(X=m, MARGIN=1, FUN=cumsum))
  res <- t(Reduce(`/`, list(t(csum), 1:ncol(m))))
  res[, 1:(ncol(m)-1)]
}

Проверьте это с помощью:

> colCumSumAve(ma)
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    2    3    4    5

что правильно.

Пояснение:

colCumSumAve <- function(m) {
  csum <- t(apply(X=m, MARGIN=1, FUN=cumsum)) # calculate row-wise colsum
  res <- t(Reduce(`/`, list(t(csum), 1:ncol(m))))
  # This is the trickiest part.
  # Because `csum` is a matrix, the matrix will be treated like a vector 
  # when `Reduce`-ing using `/` with a vector `1:ncol(m)`.
  # To get quasi-row-wise treatment, I change orientation
  # of the matrix by `t()`. 
  # However, the output, the output will be in this transformed
  # orientation as a consequence. So I re-transform by applying `t()`
  # on the entire result at the end - to get again the original
  # input matrix orientation.
  # `Reduce` using `/` here by sequencial list of the `t(csum)` and
  # `1:ncol(m)` finally, has as effect `/`-ing `csum` values by their
  # corresponding column position.
  res[, 1:(ncol(m)-1)] # removes last column for the answer.
  # this, of course could be done right at the beginning,
  # saving calculation of values in the last column,
  # but this calculation actually is not the speed-limiting or speed-down-slowing step
  # of these calculations (since this is sth vectorized)
  # rather the `apply` and `Reduce` will be rather speed-limiting.
}

Ну, ладно, тогда я мог бы сделать:

colCumSumAve <- function(m) {
  csum <- t(apply(X=m[, 1:(ncol(m)-1)], MARGIN=1, FUN=cumsum))
  t(Reduce(`/`, list(t(csum), 1:ncol(m))))
}

или

colCumSumAve <- function(m) {
  m <- m[, 1:(ncol(m)-1)] # remove last column
  csum <- t(apply(X=m, MARGIN=1, FUN=cumsum))
  t(Reduce(`/`, list(t(csum), 1:ncol(m))))
}

Тогда это действительно более оптимизированное решение.

Исходная функция

Ваша исходная функция делает только назначения в for -петле и ничего не возвращает. Поэтому я сначала скопировал ваш ввод в res, обработал его с помощью for -loop, а затем возвратил res.

ColCumSumsAve <- function(y){
  res <- y
  for(i in seq_len(dim(y)[2]-1)) {
    res[,i] <- cumsum(y[,i])/i
  }
  res
}

Однако это дает:

> ColCumSumsAve(ma)
     [,1] [,2]     [,3] [,4] [,5]
[1,]    1  1.5 1.666667 1.75    9
[2,]    3  3.5 3.666667 3.75   10

Проблема в том, что cumsum в матрицах вычисляется в направлении столбцов, а не по строкам, поскольку он обрабатывает матрицу как вектор (который проходит по матрице по столбцам).

Исправленная функция оригинала

После некоторого дерьма я понял, что правильное решение:

ColCumSumsAve <- function(y){
  res <- matrix(NA, nrow(y), ncol(y)-1) 
  # create empty matrix with the dimensions of y minus last column
  for (i in 1:(nrow(y))) {           # go through rows
    for (j in 1:(ncol(y)-1)) {       # go through columns
      res[i, j] <- sum(y[i, 1:j])/j  # for each position do this
    }
  }
  res   # return `res`ult by calling it at the end!
}

с тестированием:

> ColCumSumsAve(ma)
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    2    3    4    5

Примечание: dim(y)[2] равно ncol(y) - и dim(y)[1] равно nrow(y) - и вместо этого seq_len(), 1: короче, и я думаю, даже немного быстрее.

Примечание. Мое решение, представленное первым, будет быстрее, поскольку оно использует apply, векторизацию cumsum и Reduce. - for -циклы в R медленнее.

Позднее примечание: не уверен, что первое решение быстрее. Начиная с R-3.x кажется, что циклы for быстрее. Reduce будет функцией ограничения скорости и иногда может быть невероятно медленной.

0 голосов
/ 02 ноября 2018

Вот как я это сделал

> t(apply(ma, 1, function(x) cumsum(x) / 1:length(x)))[,-NCOL(ma)]
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    2    3    4    5

Это применяет функцию cumsum по строкам к матрице ma, а затем делит ее на правильную длину, чтобы получить среднее значение (cumsum(x) и 1:length(x) будут иметь одинаковую длину). Затем просто транспонируйте с помощью t и удалите последний столбец с помощью [,-NCOL(ma)].

Причина, по которой ваша функция не выводится, состоит в том, что вы ничего не возвращаете. Вы должны завершить функцию с return(y) или просто y, как предложил Мариус. В любом случае, похоже, что ваша функция не дает правильного ответа.

...