Среднее значение для каждой группы в файле data.frame

У меня есть data.frame и мне нужно рассчитать среднее значение для каждой группы (т. data.frame За Month , ниже).

 Name Month Rate1 Rate2 Aira 1 12 23 Aira 2 18 73 Aira 3 19 45 Ben 1 53 19 Ben 2 22 87 Ben 3 19 45 Cat 1 22 87 Cat 2 67 43 Cat 3 45 32 

Мой желаемый результат выглядит ниже, где значения для Rate1 и Rate2 являются групповыми. Пожалуйста, проигнорируйте значение, я сделал это для примера.

 Name Rate1 Rate2 Aira 23.21 12.2 Ben 45.23 43.9 Cat 33.22 32.2 

8 Solutions collect form web for “Среднее значение для каждой группы в файле data.frame”

Этот тип операции – именно то, для чего был создан aggregate :

 d < - read.table(text='Name Month Rate1 Rate2 Aira 1 12 23 Aira 2 18 73 Aira 3 19 45 Ben 1 53 19 Ben 2 22 87 Ben 3 19 45 Cat 1 22 87 Cat 2 67 43 Cat 3 45 32', header=TRUE) aggregate(d[, 3:4], list(d$Name), mean) Group.1 Rate1 Rate2 1 Aira 16.33333 47.00000 2 Ben 31.33333 50.33333 3 Cat 44.66667 54.00000 

Здесь мы объединяем столбцы 3 и 4 данных.frame d , группируем по d$Name и применяем mean функцию.


Или, используя интерфейс формулы:

 aggregate(. ~ Name, d[-2], mean) 

Или используйте group_by & summarise_at из пакета dplyr :

 library(dplyr) d %>% group_by(Name) %>% summarise_at(vars(-Month), funs(mean(., na.rm=TRUE))) # A tibble: 3 x 3 Name Rate1 Rate2    1 Aira 16.3 47.0 2 Ben 31.3 50.3 3 Cat 44.7 54.0 

См. « ?summarise_at для многих способов указания переменных, на которые нужно действовать. Здесь, vars(-Month) говорит все переменные, кроме Month .

Вы также можете использовать пакет plyr , который как-то более универсален:

 library(plyr) ddply(d, .(Name), summarize, Rate1=mean(Rate1), Rate2=mean(Rate2)) Name Rate1 Rate2 1 Aira 16.33333 47.00000 2 Ben 31.33333 50.33333 3 Cat 44.66667 54.00000 

Третьей большой альтернативой является использование пакета data.table , который также имеет class data.frame, но такие операции, как вы ищите, вычисляются намного быстрее.

 library(data.table) mydt < - structure(list(Name = c("Aira", "Aira", "Aira", "Ben", "Ben", "Ben", "Cat", "Cat", "Cat"), Month = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), Rate1 = c(15.6396600443877, 2.15649279424609, 6.24692918928743, 2.37658797276116, 34.7500663272292, 3.28750138697048, 29.3265553981065, 17.9821839334431, 10.8639802575958), Rate2 = c(17.1680489538369, 5.84231656330206, 8.54330866437461, 5.88415184986176, 3.02064294862551, 17.2053351400752, 16.9552950199166, 2.56058000170089, 15.7496228048122)), .Names = c("Name", "Month", "Rate1", "Rate2"), row.names = c(NA, -9L), class = c("data.table", "data.frame")) 

Теперь, чтобы принять среднее значение Rate1 и Rate2 за все 3 месяца, для каждого человека (Имя): сначала определите, в каких столбцах вы хотите взять среднее значение

 colstoavg < - names(mydt)[3:4] 

Теперь мы используем lapply, чтобы взять среднее значение по столбцам, которые мы хотим использовать (colstoavg)

 mydt.mean < - mydt[,lapply(.SD,mean,na.rm=TRUE),by=Name,.SDcols=colstoavg] mydt.mean Name Rate1 Rate2 1: Aira 8.014361 10.517891 2: Ben 13.471385 8.703377 3: Cat 19.390907 11.755166 

Я описываю два способа сделать это: один основан на data.table, а другой на основе пакета reshape2 . У метода data.table уже есть ответ, но я попытался сделать его более чистым и более подробным.

Данные выглядят так:

  d < - structure(list(Name = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), .Label = c("Aira", "Ben", "Cat"), class = "factor"), Month = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), Rate1 = c(12L, 18L, 19L, 53L, 22L, 19L, 22L, 67L, 45L), Rate2 = c(23L, 73L, 45L, 19L, 87L, 45L, 87L, 43L, 32L)), .Names = c("Name", "Month", "Rate1", "Rate2"), class = "data.frame", row.names = c(NA, -9L )) head(d) Name Month Rate1 Rate2 1 Aira 1 12 23 2 Aira 2 18 73 3 Aira 3 19 45 4 Ben 1 53 19 5 Ben 2 22 87 6 Ben 3 19 45 library("reshape2") mym <- melt(d, id = c("Name")) res <- dcast(mym, Name ~ variable, mean) res #Name Month Rate1 Rate2 #1 Aira 2 16.33333 47.00000 #2 Ben 2 31.33333 50.33333 #3 Cat 2 44.66667 54.00000 

Использование data.table:

 # At first, I convert the data.frame to data.table and then I group it setDT(d) d[, .(Rate1 = mean(Rate1), Rate2 = mean(Rate2)), by = .(Name)] # Name Rate1 Rate2 #1: Aira 16.33333 47.00000 #2: Ben 31.33333 50.33333 #3: Cat 44.66667 54.00000 

Существует еще один способ сделать это, избегая писать много аргументов для j в data.table с использованием .SD

 d[, lapply(.SD, mean), by = .(Name)] # Name Month Rate1 Rate2 #1: Aira 2 16.33333 47.00000 #2: Ben 2 31.33333 50.33333 #3: Cat 2 44.66667 54.00000 

если мы хотим только Rate1 и Rate2, тогда мы можем использовать .SDcols следующим образом:

 d[, lapply(.SD, mean), by = .(Name), .SDcols = 3:4] # Name Rate1 Rate2 #1: Aira 16.33333 47.00000 #2: Ben 31.33333 50.33333 #3: Cat 44.66667 54.00000 

Вот несколько способов сделать это в базе R включая альтернативный aggregate подход. Приведенные ниже примеры возвращают средства в месяц, и я думаю, это то, что вы просили. Хотя, такой же подход можно было бы использовать для возврата средств на одного человека:

Использование ave :

 my.data < - read.table(text = ' Name Month Rate1 Rate2 Aira 1 12 23 Aira 2 18 73 Aira 3 19 45 Ben 1 53 19 Ben 2 22 87 Ben 3 19 45 Cat 1 22 87 Cat 2 67 43 Cat 3 45 32 ', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA') Rate1.mean <- with(my.data, ave(Rate1, Month, FUN = function(x) mean(x, na.rm = TRUE))) Rate2.mean <- with(my.data, ave(Rate2, Month, FUN = function(x) mean(x, na.rm = TRUE))) my.data <- data.frame(my.data, Rate1.mean, Rate2.mean) my.data 

Использование:

 my.data < - read.table(text = ' Name Month Rate1 Rate2 Aira 1 12 23 Aira 2 18 73 Aira 3 19 45 Ben 1 53 19 Ben 2 22 87 Ben 3 19 45 Cat 1 22 87 Cat 2 67 43 Cat 3 45 32 ', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA') by.month <- as.data.frame(do.call("rbind", by(my.data, my.data$Month, FUN = function(x) colMeans(x[,3:4])))) colnames(by.month) <- c('Rate1.mean', 'Rate2.mean') by.month <- cbind(Month = rownames(by.month), by.month) my.data <- merge(my.data, by.month, by = 'Month') my.data 

Использование lapply и split :

 my.data < - read.table(text = ' Name Month Rate1 Rate2 Aira 1 12 23 Aira 2 18 73 Aira 3 19 45 Ben 1 53 19 Ben 2 22 87 Ben 3 19 45 Cat 1 22 87 Cat 2 67 43 Cat 3 45 32 ', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA') ly.mean <- lapply(split(my.data, my.data$Month), function(x) c(Mean = colMeans(x[,3:4]))) ly.mean <- as.data.frame(do.call("rbind", ly.mean)) ly.mean <- cbind(Month = rownames(ly.mean), ly.mean) my.data <- merge(my.data, ly.mean, by = 'Month') my.data 

Использование sapply и split :

 my.data < - read.table(text = ' Name Month Rate1 Rate2 Aira 1 12 23 Aira 2 18 73 Aira 3 19 45 Ben 1 53 19 Ben 2 22 87 Ben 3 19 45 Cat 1 22 87 Cat 2 67 43 Cat 3 45 32 ', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA') my.data sy.mean <- t(sapply(split(my.data, my.data$Month), function(x) colMeans(x[,3:4]))) colnames(sy.mean) <- c('Rate1.mean', 'Rate2.mean') sy.mean <- data.frame(Month = rownames(sy.mean), sy.mean, stringsAsFactors = FALSE) my.data <- merge(my.data, sy.mean, by = 'Month') my.data 

Использование aggregate :

 my.data < - read.table(text = ' Name Month Rate1 Rate2 Aira 1 12 23 Aira 2 18 73 Aira 3 19 45 Ben 1 53 19 Ben 2 22 87 Ben 3 19 45 Cat 1 22 87 Cat 2 67 43 Cat 3 45 32 ', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA') my.summary <- with(my.data, aggregate(list(Rate1, Rate2), by = list(Month), FUN = function(x) { mon.mean = mean(x, na.rm = TRUE) } )) my.summary <- do.call(data.frame, my.summary) colnames(my.summary) <- c('Month', 'Rate1.mean', 'Rate2.mean') my.summary my.data <- merge(my.data, my.summary, by = 'Month') my.data 

Вы также можете использовать общие функции cbind() и lm() без перехвата:

 cbind(lm(d$Rate1~-1+d$Name)$coef,lm(d$Rate2~-1+d$Name)$coef) > [,1] [,2] >d$NameAira 16.33333 47.00000 >d$NameBen 31.33333 50.33333 >d$NameCat 44.66667 54.00000 

Вы также можете выполнить это с sqldf пакета sqldf , как показано ниже:

 library(sqldf) x < - read.table(text='Name Month Rate1 Rate2 Aira 1 12 23 Aira 2 18 73 Aira 3 19 45 Ben 1 53 19 Ben 2 22 87 Ben 3 19 45 Cat 1 22 87 Cat 2 67 43 Cat 3 45 32', header=TRUE) sqldf(" select Name ,avg(Rate1) as Rate1_float ,avg(Rate2) as Rate2_float ,avg(Rate1) as Rate1 ,avg(Rate2) as Rate2 from x group by Name ") # Name Rate1_float Rate2_float Rate1 Rate2 #1 Aira 16.33333 47.00000 16 47 #2 Ben 31.33333 50.33333 31 50 #3 Cat 44.66667 54.00000 44 54 

Я недавно конвертирую в dplyr как показано в других ответах, но sqldf хорош, поскольку большинство аналитиков данных / ученых-разработчиков / разработчиков имеют хотя бы некоторое свободное владение SQL. Таким образом, я думаю, что он имеет тенденцию делать более универсально читаемый код, чем dplyr или другие решения, представленные выше.

ОБНОВЛЕНИЕ: отвечая на комментарий ниже, я попытался обновить код, как показано выше. Однако поведение было не таким, каким я ожидал. Похоже, что определение столбца (т. int vs float ) выполняется только тогда, когда псевдоним столбца совпадает с именем исходного столбца. Когда вы указываете новое имя, агрегатный столбец возвращается без округления.

Interesting Posts
Давайте будем гением компьютера.