Вычислить среднее и стандартное отклонение по группам для нескольких переменных в data.frame
Изменить. Этот вопрос первоначально был назван < < Длительное масштабирование данных в R →
Я просто изучаю R и пытаюсь найти способы применить его, чтобы помочь другим в моей жизни. В качестве тестового примера я работаю над изменением некоторых данных, и у меня возникают проблемы с примерами, которые я нашел в Интернете. Я начинаю с того, что выглядит следующим образом:
ID Obs 1 Obs 2 Obs 3
1 43 48 37
1 27 29 22
1 36 32 40
2 33 38 36
2 29 32 27
2 32 31 35
2 25 28 24
3 45 47 42
3 38 40 36
И то, что я хочу в итоге, будет выглядеть так:
ID Obs 1 mean Obs 1 std dev Obs 2 mean Obs 2 std dev
1 x x x x
2 x x x x
3 x x x x
И так далее. Я не уверен в том, нужна ли мне дополнительная информация в моих данных длинной формы или что. Я предполагаю, что математическая часть (поиск средних и стандартных отклонений) будет легкой частью, но я не смог найти способ, который, похоже, работает, чтобы правильно изменить данные, чтобы начать в этом процессе.
Большое спасибо за любую помощь.
Ответы
Ответ 1
Это проблема агрегации, а не проблема изменения в качестве первоначально заданного вопроса - мы хотим объединить каждый столбец в среднее и стандартное отклонение по идентификатору. Существует множество пакетов, которые обрабатывают такие проблемы. В базе R это можно сделать, используя aggregate
следующим образом (предполагая, что DF
- это входной кадр данных):
ag <- aggregate(. ~ ID, DF, function(x) c(mean = mean(x), sd = sd(x)))
Примечание 1: комментатор отметил, что ag
- это кадр данных, для которого некоторые столбцы являются матрицами. Хотя изначально это может показаться странным, на самом деле это упрощает доступ. ag
имеет такое же количество столбцов, что и вход DF
. Его первый столбец ag[[1]]
равен ID
, а i-й столбец остатка ag[[i+1]]
(или эквивалентно ag[-1][[i]]
) является матрицей статистики для i-го столбца входных наблюдений. Если вы хотите получить доступ к j-й статистике i-го наблюдения, то поэтому ag[[i+1]][, j]
также можно записать как ag[-1][[i]][, j]
.
С другой стороны, предположим, что существуют статистические столбцы k
для каждого наблюдения на входе (где k = 2 в вопросе). Тогда, если мы сглаживаем выход, то для доступа к j-й статистике i-го столбца наблюдения мы должны использовать более сложный ag[[k*(i-1)+j+1]]
или эквивалентно ag[-1][[k*(i-1)+j]]
.
Например, сравните простоту первого выражения со вторым:
ag[-1][[2]]
## mean sd
## [1,] 36.333 10.2144
## [2,] 32.250 4.1932
## [3,] 43.500 4.9497
ag_flat <- do.call("data.frame", ag) # flatten
ag_flat[-1][, 2 * (2-1) + 1:2]
## Obs_2.mean Obs_2.sd
## 1 36.333 10.2144
## 2 32.250 4.1932
## 3 43.500 4.9497
Примечание 2: Ввод в воспроизводимой форме:
Lines <- "ID Obs_1 Obs_2 Obs_3
1 43 48 37
1 27 29 22
1 36 32 40
2 33 38 36
2 29 32 27
2 32 31 35
2 25 28 24
3 45 47 42
3 38 40 36"
DF <- read.table(text = Lines, header = TRUE)
Ответ 2
Вот, наверное, самый простой способ сделать это (с воспроизводимым примером):
library(plyr)
df <- data.frame(ID=rep(1:3, 3), Obs_1=rnorm(9), Obs_2=rnorm(9), Obs_3=rnorm(9))
ddply(df, .(ID), summarize, Obs_1_mean=mean(Obs_1), Obs_1_std_dev=sd(Obs_1),
Obs_2_mean=mean(Obs_2), Obs_2_std_dev=sd(Obs_2))
ID Obs_1_mean Obs_1_std_dev Obs_2_mean Obs_2_std_dev
1 1 -0.13994642 0.8258445 -0.15186380 0.4251405
2 2 1.49982393 0.2282299 0.50816036 0.5812907
3 3 -0.09269806 0.6115075 -0.01943867 1.3348792
РЕДАКТИРОВАТЬ: Следующий подход позволяет вам много печатать при работе со многими столбцами.
ddply(df, .(ID), colwise(mean))
ID Obs_1 Obs_2 Obs_3
1 1 -0.3748831 0.1787371 1.0749142
2 2 -1.0363973 0.0157575 -0.8826969
3 3 1.0721708 -1.1339571 -0.5983944
ddply(df, .(ID), colwise(sd))
ID Obs_1 Obs_2 Obs_3
1 1 0.8732498 0.4853133 0.5945867
2 2 0.2978193 1.0451626 0.5235572
3 3 0.4796820 0.7563216 1.4404602
Ответ 3
Есть несколько разных способов сделать это. reshape2
- полезный пакет.
Лично мне нравится использовать data.table
Ниже приводится шаг за шагом
Если myDF
- ваш data.frame
:
library(data.table)
DT <- data.table(myDF)
DT
# this will get you your mean and SD for each column
DT[, sapply(.SD, function(x) list(mean=mean(x), sd=sd(x)))]
# adding a `by` argument will give you the groupings
DT[, sapply(.SD, function(x) list(mean=mean(x), sd=sd(x))), by=ID]
# If you would like to round the values:
DT[, sapply(.SD, function(x) list(mean=round(mean(x), 3), sd=round(sd(x), 3))), by=ID]
# If we want to add names to the columns
wide <- setnames(DT[, sapply(.SD, function(x) list(mean=round(mean(x), 3), sd=round(sd(x), 3))), by=ID], c("ID", sapply(names(DT)[-1], paste0, c(".men", ".SD"))))
wide
ID Obs.1.men Obs.1.SD Obs.2.men Obs.2.SD Obs.3.men Obs.3.SD
1: 1 35.333 8.021 36.333 10.214 33.0 9.644
2: 2 29.750 3.594 32.250 4.193 30.5 5.916
3: 3 41.500 4.950 43.500 4.950 39.0 4.243
Кроме того, это может быть или не быть полезным
> DT[, sapply(.SD, summary), .SDcols=names(DT)[-1]]
Obs.1 Obs.2 Obs.3
Min. 25.00 28.00 22.00
1st Qu. 29.00 31.00 27.00
Median 33.00 32.00 36.00
Mean 34.22 36.11 33.22
3rd Qu. 38.00 40.00 37.00
Max. 45.00 48.00 42.00
Ответ 4
Здесь еще один ответ на вопрос data.table
, используя данные @Carson, немного читабельнее (а также немного быстрее, из-за использования lapply
вместо sapply
):
library(data.table)
set.seed(1)
dt = data.table(ID=c(1:3), Obs_1=rnorm(9), Obs_2=rnorm(9), Obs_3=rnorm(9))
dt[, c(mean = lapply(.SD, mean), sd = lapply(.SD, sd)), by = ID]
# ID mean.Obs_1 mean.Obs_2 mean.Obs_3 sd.Obs_1 sd.Obs_2 sd.Obs_3
#1: 1 0.4854187 -0.3238542 0.7410611 1.1108687 0.2885969 0.1067961
#2: 2 0.4171586 -0.2397030 0.2041125 0.2875411 1.8732682 0.3438338
#3: 3 -0.3601052 0.8195368 -0.4087233 0.8105370 0.3829833 1.4705692
Ответ 5
Я добавляю решение dplyr
.
set.seed(1)
df <- data.frame(ID=rep(1:3, 3), Obs_1=rnorm(9), Obs_2=rnorm(9), Obs_3=rnorm(9))
library(dplyr)
df %>% group_by(ID) %>% summarise_each(funs(mean, sd))
# ID Obs_1_mean Obs_2_mean Obs_3_mean Obs_1_sd Obs_2_sd Obs_3_sd
# (int) (dbl) (dbl) (dbl) (dbl) (dbl) (dbl)
# 1 1 0.4854187 -0.3238542 0.7410611 1.1108687 0.2885969 0.1067961
# 2 2 0.4171586 -0.2397030 0.2041125 0.2875411 1.8732682 0.3438338
# 3 3 -0.3601052 0.8195368 -0.4087233 0.8105370 0.3829833 1.4705692