Было несколько ошибок.
Решение
Вот что я тестировал и что работает:
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
будет функцией ограничения скорости и иногда может быть невероятно медленной.