Задний план
Функция вычисляет движущуюся структуру и предлагает некоторые другие второстепенные виджеты, такие как возможность вернуть фрейм данных в исходном порядке или автоматически получить имя переменной для скользящего среднего. В большинстве реальных случаев использования аналогичных результатов можно легко достичь, используя комбинации обычных подозреваемых, таких как across
, mutate
и так далее. Однако меня интересовала реализация, которая:
- Достаточно общий и легко применимый к нескольким наборам данных
- Использует стандартные сказочные глаголы dplyr для облегчения использования в
sparklyr
, особенно при работе со старыми серверными модулями Spark, которые не поддерживаютapply
. Функция оказалась запутанной, поэтому я чувствую, что не смог достичь этой цели, но это побочный момент.
Искал обратную связь
Лучший подход к созданию нескольких
lag
звонки. Через манипуляции со строками я прихожу кlag(var, n)...
а затем выполните:dplyr::mutate(data_sorted,"{{val}}_mavg" := !!rlang::parse_expr(lag_call))
Это кажется пустяком, и я был бы благодарен за предложения по улучшению.
Есть ли элегантный способ принудительного вычисления в левой части
:=
. В настоящее время занимаюсь:if (res_val != "{{val}}_mavg") { data_avg <- dplyr::rename(res_val = "{{val}}_mavg") }
Это работает, но однострочно, как оценка
res_val
а потом делать потенциально необходимую магию с кудрявый было бы здорово.Любые другие наблюдения
Функция
#' Add Moving Average for an Arbitrary Number of Intervals
#"https://codereview.stackexchange.com/questions/254621/#" The functions adds moving average for an arbitrary number of intervals. The
#' data can be returned sorted or according to the original order.
#"https://codereview.stackexchange.com/questions/254621/#" @details The function can be used independently or within dplyr pipeline.
#"https://codereview.stackexchange.com/questions/254621/#" @param .data A tibble or data frame.
#' @param sort_cols Columns used for sorting passed in a manner consistent with
#' code{link[dplyr]{arrange}}
#' @param val Column used to calculate moving average passed as bare column
#' name or a character string.
#' @param res_val Resulting moving average, defaults to name of code{val}
#' suffixed with code{_mavg}.
#' @param restore_order A logical, defaults to code{FALSE} if code{TRUE} it
#' will restore original data order.
#"https://codereview.stackexchange.com/questions/254621/#" @return A tibble with appended moving average.
#' @export
#"https://codereview.stackexchange.com/questions/254621/#" @examples
#' add_moving_average(mtcars, sort_cols = c("mpg", "cyl"), val = hp, intervals = 2)
add_moving_average <-
function(.data,
sort_cols,
val,
intervals = 2,
res_val = "{{val}}_mavg",
restore_order = FALSE) {
unique_id_name <- tail(make.unique(c(colnames(.data), "ID")), 1)
data_w_index <- dplyr::mutate(.data, {{unique_id_name}} := dplyr::row_number())
index_col_name <- tail(names(data_w_index), 1)
# Create desired number of calls to get moving average calculation
lag_calls <- paste0("lag(", rlang::as_string(rlang::ensym(val)), ", ", 1:intervals, ")")
lag_call <- paste(lag_calls, collapse = " + ")
lag_call <- paste0("(", lag_call, ") / ", intervals)
data_sorted <- dplyr::arrange(data_w_index, dplyr::across(sort_cols))
data_avg <- dplyr::mutate(data_sorted,"{{val}}_mavg" := !!rlang::parse_expr(lag_call))
if (res_val != "{{val}}_mavg") {
data_avg <- dplyr::rename(data_avg, res_val = "{{val}}_mavg")
}
if (restore_order) {
data_avg <- dplyr::arrange(data_avg, !!rlang::sym(index_col_name))
}
data_avg <- dplyr::select(data_avg, -dplyr::last_col(1))
data_avg
}
Тесты
add_moving_average(.data = mtcars, sort_cols = c("am", "gear"), val = disp, intervals = 3)
add_moving_average(.data = mtcars, sort_cols = c("am", "gear"), val = disp, intervals = 3)
add_moving_average(.data = mtcars, sort_cols = c("am", "gear"), val = disp, intervals = 3,
restore_order = TRUE)