Группировка всего набора данных и агрегирование
У меня есть набор данных из 20 переменных V1,V2,V3......V20
с 1200 рядами.
Я хочу усреднить каждые четыре строки в моем фрейме данных, т.е. мой выходной набор данных должен иметь 20 столбцов, содержащих V1,V2,V3…V20
и 300 строк, содержащих среднее значение данных в группе из 4 человек.
Я не могу использовать tapply
Что касается этого, я должен ввести 1 переменную за раз; Я хочу усреднить все 20 переменных одновременно.
Есть ли эффективный способ сделать это? Я хочу использовать функции из семейства apply и хотел бы избежать зацикливания.
1 ответ
С помощью lapply
с colMeans
set.seed(42)
dat <- as.data.frame(matrix(sample(1:20, 20*1200, replace=TRUE), ncol=20))
n <- seq_len(nrow(dat))
res <- do.call(rbind,lapply(split(dat, (n-1)%/%4 +1),colMeans, na.rm=TRUE))
dim(res)
#[1] 300 20
объяснение
Здесь идея заключается в создании группирующей переменной, которая разбивает наборы данных на подмножества наборов данных в списке с условием, что 1:4
строки входят в первое подмножество, 5:8
до 2-го подмножества, и..., последнее подмножество будет иметь 297:300
, Для простоты понимания, используя подмножество строк. Предположим, что ваш набор данных имеет 10 строк:
n1 <- seq_len(10)
n1
#[1] 1 2 3 4 5 6 7 8 9 10
(n1-1) %/%4 #created a numeric index to split by group
# [1] 0 0 0 0 1 1 1 1 2 2
я добавил 1
к вышесказанному, чтобы начать с 1
вместо 0
(n1-1) %/%4 +1
#[1] 1 1 1 1 2 2 2 2 3 3
Вы также можете использовать gl
то есть.
gl(10, 4, 10)
Для набора данных это должно быть
gl(1200, 4, 1200)
Теперь вы можете либо split
n1
по недавно созданному групповому индексу или набору данных
split(n1,(n1-1) %/%4 +1) # you can check the result of this
Для подмножества из 10 строк dataset
split(dat[1:10,], (n1-1) %/%4 +1)
а затем использовать lapply
вместе с colMeans
чтобы получить значения столбцов каждого элемента списка и связать их, используя do.call(rbind,..)
Или же
summarise_each
от dplyr
library(dplyr)
res2 <- dat %>%
mutate(N= (row_number()-1)%/%4+1) %>%
group_by(N) %>%
summarise_each(funs(mean=mean(., na.rm=TRUE))) %>%
select(-N)
dim(res2)
#[1] 300 20
all.equal(as.data.frame(res), as.data.frame(res2), check.attributes=FALSE)
#[1] TRUE
Или же
С помощью data.table
library(data.table)
DT1 <- setDT(dat)[, N:=(seq_len(.N)-1)%/%4 +1][,
lapply(.SD, mean, na.rm=TRUE), by=N][,N:=NULL]
dim(DT1)
#[1] 300 20