Если вы объединяете фильтрацию и вычисления в одну функцию, вы можете поместить ее в summarize_at
, чтобы легко применить ее к каждому столбцу. Поскольку данные в вашем примере не полностью воспроизводимы, я буду использовать набор данных iris
. В вашем случае вы бы заменили Species
на Date
, а Petal.Width
на Return
:
library(dplyr)
top_iris <- iris %>%
group_by(Species) %>%
summarize_at(vars(one_of('Sepal.Length', 'Sepal.Width', 'Petal.Length')),
funs(return = sum(Petal.Width[. > quantile(., .666)]) / length(Petal.Width[. > quantile(., .666)])))
top_iris
# A tibble: 3 x 4
Species Sepal.Length_return Sepal.Width_return Petal.Length_return
<fct> <dbl> <dbl> <dbl>
1 setosa 0.257 0.262 0.308
2 versicolor 1.44 1.49 1.49
3 virginica 2.1 2.22 2.09
Проблема с использованием filter
состоит в том, что каждая функция в конвейере работает по порядку, поэтому любые критерии, которые вы задаете для filter_*
, должны быть применены ко всему фрейму data.frame, прежде чем результат будет передан в summarize_at
, Вместо этого мы просто используем один оператор summarize_at
и фильтруем каждый столбец, когда к нему применяется функция суммирования.
Чтобы объяснить это более подробно, summarize_at
принимает 2 аргумента:
Первый аргумент - это одна или несколько функций выбора переменных, описанных в ?select_helpers
, заключенных в функцию vars
. Здесь мы используем one_of
, который просто берет вектор имен столбцов, но мы также можем использовать matches
для выбора с использованием регулярного выражения или starts_with
для выбора на основе префикса, например.
Второй аргумент - это список из одного или нескольких вызовов функций, которые должны выполняться в каждом выбранном столбце, заключенный в функцию funs
. Здесь у нас есть 1 вызов функции, которому мы дали имя return
.
Как и для любой функции tidyverse, она оценивается в локальной среде, созданной из данных, переданных по каналу. Таким образом, имена переменных, например Petal.Width
, обозначают data$Petal.Width
. В функциях *_at
.
представляет переданную переменную, поэтому при суммировании столбца Sepal.Length
:
Petal.Width[. > quantile(., .666)]
означает:
data$Petal.Width[data$Sepal.Length > quantile(data$Sepal.Length, .666)]
Наконец, так как функция в funs
названа (это return =
), то результирующие итоговые столбцы имеют имя функции (return
), добавленное к исходным именам столбцов.
Если вы хотите удалить отсутствующие данные перед выполнением этих вычислений, вы можете использовать na.omit
, чтобы убрать NA
значений.
Чтобы удалить все строки , содержащие NA
, просто передайте данные через na.omit
перед группировкой:
iris2 <- iris
iris2[c(143:149), c(1:2)] <- NA
iris2 %>%
na.omit() %>%
group_by(Species) %>%
summarize_at(vars(one_of('Sepal.Length', 'Sepal.Width', 'Petal.Length')),
funs(return = sum(Petal.Width[. > quantile(., .666)]) / length(Petal.Width[. > quantile(., .666)])))
Species Sepal.Length_return Sepal.Width_return Petal.Length_return
<fct> <dbl> <dbl> <dbl>
1 setosa 0.257 0.262 0.308
2 versicolor 1.44 1.49 1.49
3 virginica 2.09 2.19 2.07
Чтобы убрать NA
значений из каждого столбца во время суммирования, вам нужно переместить na.omit
внутри функции суммирования:
iris2 %>%
group_by(Species) %>%
summarize_at(vars(one_of('Sepal.Length', 'Sepal.Width', 'Petal.Length')),
funs(return = {
var <- na.omit(.)
length(Petal.Width[var > quantile(var, .666)])
}))
# A tibble: 3 x 4
Species Sepal.Length_return Sepal.Width_return Petal.Length_return
<fct> <dbl> <dbl> <dbl>
1 setosa 0.257 0.262 0.308
2 versicolor 1.44 1.49 1.49
3 virginica 2.11 2.2 2.09
Здесь мы используем фигурные скобки, чтобы расширить функцию, которую мы запускаем в summarize_at
, на несколько выражений. Сначала мы удаляем NA
значений, затем вычисляем возвращаемые значения. Поскольку эта функция находится в summarize_at
, она применяется к каждой переменной на основе группировки, установленной group_by
.