Ddply + суммировать для повторения одной и той же статистической функции по большому числу столбцов
Хорошо, второй вопрос R быстро.
Мои данные:
Timestamp St_01 St_02 ...
1 2008-02-08 00:00:00 26.020 25.840 ...
2 2008-02-08 00:10:00 25.985 25.790 ...
3 2008-02-08 00:20:00 25.930 25.765 ...
4 2008-02-08 00:30:00 25.925 25.730 ...
5 2008-02-08 00:40:00 25.975 25.695 ...
...
В принципе, я бы использовал комбинацию ddply
и summarize
для вычисления ансамблей (например, для каждого часа в течение всего года).
В приведенном выше случае я бы создал категорию, например. час (например, strptime(data$Timestamp,"%H") -> data$hour
, а затем используйте эту категорию в ddply
, например ddply(data,"hour", summarize, St_01=mean(St_01), St_02=mean(St_02)...)
, чтобы усреднять по категориям по каждому столбцу.
но здесь он становится липким. У меня более 40 столбцов, и я не готов вводить их все по одному в качестве параметров функции summarize
. Я использовал, чтобы написать цикл в оболочке, чтобы сгенерировать этот код, но это не то, как программисты решают проблемы, не так ли?
Итак, молитесь, кто-нибудь имеет лучший способ добиться того же результата, но с меньшими нажатиями клавиш?
Ответы
Ответ 1
Вы можете использовать numcolwise()
для запуска сводки по всем числовым столбцам.
Вот пример использования iris
:
ddply(iris, .(Species), numcolwise(mean))
Species Sepal.Length Sepal.Width Petal.Length Petal.Width
1 setosa 5.006 3.428 1.462 0.246
2 versicolor 5.936 2.770 4.260 1.326
3 virginica 6.588 2.974 5.552 2.026
Аналогично, существует catcolwise()
для суммирования по всем категориальным столбцам.
Подробнее см. ?numcolwise
.
ИЗМЕНИТЬ
Альтернативный подход - использовать reshape2
(предложенный @gsk3). В этом примере это больше нажатий клавиш, но дает вам огромную гибкость:
Библиотека (reshape2)
miris <- melt(iris, id.vars="Species")
x <- ddply(miris, .(Species, variable), summarize, mean=mean(value))
dcast(x, Species~variable, value.var="mean")
Species Sepal.Length Sepal.Width Petal.Length Petal.Width
1 setosa 5.006 3.428 1.462 0.246
2 versicolor 5.936 2.770 4.260 1.326
3 virginica 6.588 2.974 5.552 2.026
Ответ 2
Вы даже можете упростить второй подход, предложенный Андри, полностью опустив вызов ddply. Просто укажите mean
как функцию агрегации в вызове dcast:
library(reshape2)
miris <- melt(iris, id.vars="Species")
dcast(miris, Species ~ variable, mean)
Species Sepal.Length Sepal.Width Petal.Length Petal.Width
1 setosa 5.006 3.428 1.462 0.246
2 versicolor 5.936 2.770 4.260 1.326
3 virginica 6.588 2.974 5.552 2.026
Тот же результат можно также вычислить очень быстро, используя пакет data.table
. Переменная .SD
в выражении j представляет собой специальную переменную data.table, содержащую подмножество данных для каждой группы, исключая все столбцы, используемые в by
.
library(data.table)
dt_iris <- as.data.table(iris)
dt_iris[, lapply(.SD, mean), by = Species]
Species Sepal.Length Sepal.Width Petal.Length Petal.Width
1: setosa 5.006 3.428 1.462 0.246
2: versicolor 5.936 2.770 4.260 1.326
3: virginica 6.588 2.974 5.552 2.026
Еще одним вариантом будет новая версия 0.2 пакета Hadley dplyr
library(dplyr)
group_by(iris, Species) %>% summarise_each(funs(mean))
Source: local data frame [3 x 5]
Species Sepal.Length Sepal.Width Petal.Length Petal.Width
1 setosa 5.006 3.428 1.462 0.246
2 versicolor 5.936 2.770 4.260 1.326
3 virginica 6.588 2.974 5.552 2.026