Средний ряд по разным уровням факторов
У меня есть следующий фрейм данных:
df = data.frame(id=c("A","A","A","A","B","B","B","B","C","C","C","C","D","D","D","D"),
sub=rep(c(1:4),4),
acc1=runif(16,0,3),
acc2=runif(16,0,3),
acc3=runif(16,0,3),
acc4=runif(16,0,3))
Я хочу получить средние строки для каждого идентификатора, то есть я хочу получить среднее значение acc1, acc2, acc3 и acc4 для каждого уровня A, B, C и D путем усреднения значений для каждого подпункта (4 уровня). для каждого идентификатора), что в конечном итоге дало бы что-то вроде этого (с заменой NA на средства, которые я хочу, конечно):
dfavg = data.frame(id=c("A","B","C","D"),meanacc1=NA,meanacc2=NA,meanacc3=NA,meanacc4=NA)
Заранее спасибо!
4 ответа
Пытаться:
Вы можете использовать любой из специализированных пакетов dplyr
или же data.table
или используя base R
, Потому что у вас есть много столбцов, которые начинаются с acc
чтобы получить среднее значение, я выбираю dplyr
, Здесь идея состоит в том, чтобы сначала group
переменная по id
а затем использовать summarise_each
чтобы получить mean
каждого столбца id
это начинается с acc
library(dplyr)
df1 <- df %>%
group_by(id) %>%
summarise_each(funs(mean=mean(., na.rm=TRUE)), starts_with("acc")) %>%
rename(meanacc1=acc1, meanacc2=acc2, meanacc3=acc3, meanacc4=acc4) #this works but it requires more typing.
я мог бы rename
с помощью paste
# colnames(df1)[-1] <- paste0("mean", colnames(df1)[-1])
дает результат
# id meanacc1 meanacc2 meanacc3 meanacc4
#1 A 1.7061929 2.401601 2.057538 1.643627
#2 B 1.7172095 1.405389 2.132378 1.769410
#3 C 1.4424233 1.737187 1.998414 1.137112
#4 D 0.5468509 1.281781 1.790294 1.429353
Или используя data.table
library(data.table)
nm1 <- paste0("acc", 1:4) #names of columns to do the `means`
dt1 <- setDT(df)[, lapply(.SD, mean, na.rm=TRUE), by=id, .SDcols=nm1]
Вот.SD
подразумевает Subset of Data.table
, .SDcols
столбцы, к которым мы применяем mean
операция.
setnames(dt1, 2:5, paste0("mean", nm1)) #change the names of the concerned columns in the result
dt1
(Это должно быть задано не менее 20 раз.) Функция агрегирования применяет одну и ту же функцию (заданную в качестве третьего аргумента) ко всем столбцам своего первого аргумента в группах, определенных ее вторым аргументом:
aggregate(df[-(1:2)], df[1],mean)
Если вы хотите добавить буквы "означают" к именам столбцов:
names(df2) <- paste0("mean", names(df2)
Если бы вы хотели сделать выбор столбцов автоматически, то сработали бы grep или grepl:
aggregate(df[ grepl("acc", names(df) )], df[1], mean)
Вот несколько других базовых вариантов R:
split
+ vapply
(так как мы знаем vapply
упростил бы до матрицы по возможности)
t(vapply(split(df[-c(1, 2)], df[, 1]), colMeans, numeric(4L)))
by
(с do.call(rbind, ...)
чтобы получить окончательную структуру)
do.call(rbind, by(data = df[-c(1, 2)], INDICES = df[[1]], FUN = colMeans))
И то, и другое даст вам что-то вроде этого:
# acc1 acc2 acc3 acc4
# A 1.337496 2.091926 1.978835 1.799669
# B 1.287303 1.447884 1.297933 1.312325
# C 1.870008 1.145385 1.768011 1.252027
# D 1.682446 1.413716 1.582506 1.274925
Пример данных, использованных здесь был (с set.seed
для воспроизводимости):
set.seed(1)
df = data.frame(id = rep(LETTERS[1:4], 4),
sub = rep(c(1:4), 4),
acc1 = runif(16, 0, 3),
acc2 = runif(16, 0, 3),
acc3 = runif(16, 0, 3),
acc4 = runif(16, 0, 3))
Масштабирование до 1М строк позволяет работать достаточно хорошо (хотя, очевидно, не так быстро, как "dplyr" или "data.table").
Вы можете сделать это в самом базовом пакете, используя это:
a <- list();
for (i in 1:nlevels(df$id))
{
a[[i]] = colMeans(subset(df, id==levels(df$id)[i])[,c(3,4,5,6)]) ##select columns of df of which you want to compute the means. In your example, 3, 4, 5 and 6 are the columns
}
meanDF <- cbind(data.frame(levels(df$id)), data.frame(matrix(unlist(a), nrow=4, ncol=4, byrow=T)))
colnames(meanDF) = c("id", "meanacc1", "meanacc2", "meanacc3", "meanacc4")
meanDF
id meanacc1 meanacc2 meanacc3 meanacc4
A 1.464635 1.645898 1.7461862 1.026917
B 1.807555 1.097313 1.7135346 1.517892
C 1.350708 1.922609 0.8068907 1.607274
D 1.458911 0.726527 2.4643733 2.141865