Группировка всего набора данных и агрегирование

У меня есть набор данных из 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)

Теперь вы можете либо splitn1 по недавно созданному групповому индексу или набору данных

  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
Другие вопросы по тегам