У меня есть такой фрейм данных:
V1 = paste0("AB", seq(1:48))
V2 = seq(1:48)
test = data.frame(name = V1, value = V2)
Я хочу рассчитать средние значения столбца значений и конкретных строк.
Схема рядов довольно сложная:
Rows of MeanA1: 1, 5, 9
Rows of MeanA2: 2, 6, 10
Rows of MeanA3: 3, 7, 11
Rows of MeanA4: 4, 8, 12
Rows of MeanB1: 13, 17, 21
Rows of MeanB2: 14, 18, 22
Rows of MeanB3: 15, 19, 23
Rows of MeanB4: 16, 20, 24
Rows of MeanC1: 25, 29, 33
Rows of MeanC2: 26, 30, 34
Rows of MeanC3: 27, 31, 35
Rows of MeanC4: 28, 32, 36
Rows of MeanD1: 37, 41, 45
Rows of MeanD2: 38, 42, 46
Rows of MeanD3: 39, 43, 47
Rows of MeanD4: 40, 44, 48
Как вы видите, он начинается с 4 разных точек (1, 13, 25, 37), затем всегда +4, а для следующих 4 означает, что он просто переходит еще на 1 строку вниз.
Я хотел бы иметь вывод всех этих средств в один список.
Есть идеи? ПРИМЕЧАНИЕ. В этом примере среднее значение, конечно, всегда является средним числом, но мой реальный df отличается.
Не совсем уверен в требуемом формате вывода, но следующие коды могут вычислить то, что вы хотите, в любом случае.
calc_mean1 <- function(x) mean(test$value[seq(x, by = 4, length.out = 3)])
calc_mean2 <- function(x){sapply(x:(x+3), calc_mean1)}
output <- lapply(seq(1, 37, 12), calc_mean2)
names(output) <- paste0('Mean', LETTERS[seq_along(output)]) # remove this line if more than 26 groups.
output
## $MeanA
## [1] 5 6 7 8
## $MeanB
## [1] 17 18 19 20
## $MeanC
## [1] 29 30 31 32
## $MeanD
## [1] 41 42 43 44
@ Сотос, ты прав. В вопросе приводится пример с «MeanA1», «MeanD1»,..., в котором не упоминается, что делать, если можно просто удалить более 26 групп или четвертую строку кодов.
Комментирование, как вы сделали рядом с функцией, вероятно, лучший вариант.
Идея с помощью базы R состоит в том, чтобы создать группирующую переменную для каждых 4 строк, разделить данные каждые 12 строк (nrow(test) / 4
) и агрегировать, чтобы найти среднее значение, т.е.
test$new = rep(1:4, nrow(test)%/%4)
lapply(split(test, rep(1:4, each = nrow(test) %/% 4)), function(i)
aggregate(value ~ new, i, mean))
# $`1`
# new value
# 1 1 5
# 2 2 6
# 3 3 7
# 4 4 8
# $`2`
# new value
# 1 1 17
# 2 2 18
# 3 3 19
# 4 4 20
# $`3`
# new value
# 1 1 29
# 2 2 30
# 3 3 31
# 4 4 32
# $`4`
# new value
# 1 1 41
# 2 2 42
# 3 3 43
# 4 4 44
И еще способ.
fun <- function(DF, col, step = 4){
run <- nrow(DF)/step^2
res <- lapply(seq_len(step), function(inc){
inx <- seq_len(run*step) + (inc - 1)*run*step
dftmp <- DF[inx, ]
tapply(dftmp[[col]], rep(seq_len(step), run), mean, na.rm = TRUE)
})
names(res) <- sprintf("Mean%s", LETTERS[seq_len(step)])
res
}
fun(test, 2, 4)
#$MeanA
#1 2 3 4
#5 6 7 8
#
#$MeanB
# 1 2 3 4
#17 18 19 20
#
#$MeanC
# 1 2 3 4
#29 30 31 32
#
#$MeanD
# 1 2 3 4
#41 42 43 44
Спасибо за помощь! Еще одно отличное решение!
Поскольку вы сказали, что вам нужен длинный список средств, я предположил, что это также может быть вектор, в котором у вас просто есть все эти значения. Вы получите это так:
V1 = paste0("AB", seq(1:48))
V2 = seq(1:48)
test = data.frame(name = V1, value = V2)
meanVector <- NULL
for (i in 1:(nrow(test)-8)) {
x <- c(test$value[i], test$value[i+4], test$value[i+8])
m <- mean(x)
meanVector <- c(meanVector, m)
}
Это немного слишком подходит к вопросу. Например, если у OP более 26 групп, у вас закончатся
LETTERS
...