diff --git a/NEWS.md b/NEWS.md index 59af7d535..8bc91e7f0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -182,6 +182,9 @@ BREAKING CHANGES AND DEPRECATIONS for the previous default behaviour (i.e. only returning the newly created variables) (#579). +* The `"diff"` method in `smoothness()` was revised and now has a reversed + interpretation. Documentation was updated accordingly. (#374). + CHANGES * `rescale_weights()` gets a `method` argument, to choose method to rescale diff --git a/R/smoothness.R b/R/smoothness.R index db73d5179..aaf617a83 100644 --- a/R/smoothness.R +++ b/R/smoothness.R @@ -1,4 +1,10 @@ -#' Quantify the smoothness of a vector +#' Series smoothness +#' +#' Functions to quantify the smoothness of a vector, which can be used in some cases +#' as an index of "linearity". A smooth series is one that does not have abrupt changes in +#' its values. The smoothness of a series can be approximated in different ways, such +#' as the standard deviation of the standardized differences or the lag-one +#' autocorrelation. #' #' @param x Numeric vector (similar to a time series). #' @param method Can be `"diff"` (the standard deviation of the standardized @@ -12,6 +18,17 @@ #' plot(x) #' smoothness(x, method = "cor") #' smoothness(x, method = "diff") +#' +#' # A bootstrapped value can also be computed +#' smoothness(x, iterations = 100) +#' +#' # When perfectly linear, the "smoothness" is 1 +#' smoothness(1:10) +#' +#' # And closer to zero for random +#' smoothness(rnorm(1000)) +#' smoothness(rnorm(1000), method = "diff") +#' #' @return Value of smoothness. #' @references https://stats.stackexchange.com/questions/24607/how-to-measure-smoothness-of-a-time-series-in-r #' @@ -39,9 +56,10 @@ smoothness.numeric <- function(x, } if (method == "cor") { - smooth_data <- stats::cor(utils::head(x, length(x) - lag), utils::tail(x, length(x) - lag)) + smooth_value <- stats::cor(utils::head(x, length(x) - lag), utils::tail(x, length(x) - lag)) } else { - smooth_data <- stats::sd(diff(x, lag = lag)) / abs(mean(diff(x, lag = lag))) + diff <- standardize(diff(x)) + smooth_value <- 1 - mean((diff(diff) ** 2) / 4) # Note the reversal to match the other method } if (!is.null(iterations)) { @@ -54,14 +72,14 @@ smoothness.numeric <- function(x, lag = lag ) out_se <- stats::sd(results$t, na.rm = TRUE) - smooth_data <- data.frame(Smoothness = smooth_data, SE = out_se) + smooth_value <- data.frame(Smoothness = smooth_value, SE = out_se) } else { insight::format_warning("Package 'boot' needed for bootstrapping SEs.") } } - class(smooth_data) <- unique(c("parameters_smoothness", class(smooth_data))) - smooth_data + class(smooth_value) <- unique(c("parameters_smoothness", class(smooth_value))) + smooth_value } @@ -71,14 +89,13 @@ smoothness.data.frame <- function(x, lag = 1, iterations = NULL, ...) { - .smoothness <- - lapply( - x, - smoothness, - method = method, - lag = lag, - iterations = iterations - ) + .smoothness <- lapply( + x, + smoothness, + method = method, + lag = lag, + iterations = iterations + ) .smoothness <- cbind(Parameter = names(.smoothness), do.call(rbind, .smoothness)) class(.smoothness) <- unique(c("parameters_smoothness", class(.smoothness))) .smoothness diff --git a/man/smoothness.Rd b/man/smoothness.Rd index f2e1d2662..9b0b380a9 100644 --- a/man/smoothness.Rd +++ b/man/smoothness.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/smoothness.R \name{smoothness} \alias{smoothness} -\title{Quantify the smoothness of a vector} +\title{Series smoothness} \usage{ smoothness(x, method = "cor", lag = 1, iterations = NULL, ...) } @@ -24,13 +24,28 @@ errors. If \code{NULL} (default), parametric standard errors are computed.} Value of smoothness. } \description{ -Quantify the smoothness of a vector +Functions to quantify the smoothness of a vector, which can be used in some cases +as an index of "linearity". A smooth series is one that does not have abrupt changes in +its values. The smoothness of a series can be approximated in different ways, such +as the standard deviation of the standardized differences or the lag-one +autocorrelation. } \examples{ x <- (-10:10)^3 + rnorm(21, 0, 100) plot(x) smoothness(x, method = "cor") smoothness(x, method = "diff") + +# A bootstrapped value can also be computed +smoothness(x, iterations = 100) + +# When perfectly linear, the "smoothness" is 1 +smoothness(1:10) + +# And closer to zero for random +smoothness(rnorm(1000)) +smoothness(rnorm(1000), method = "diff") + } \references{ https://stats.stackexchange.com/questions/24607/how-to-measure-smoothness-of-a-time-series-in-r diff --git a/tests/testthat/test-distributions.R b/tests/testthat/test-distributions.R index 39d06d957..9605b73c1 100644 --- a/tests/testthat/test-distributions.R +++ b/tests/testthat/test-distributions.R @@ -7,6 +7,6 @@ test_that("distributions", { expect_equal(kurtosis(x)$Kurtosis, -0.1119534, tolerance = 0.01) expect_equal(skewness(x)$Skewness, -5.881466e-17, tolerance = 0.01) - expect_equal(as.numeric(smoothness(x, "diff")), 1.183699, tolerance = 0.01) + expect_equal(as.numeric(smoothness(x, "diff")), 0.9409494, tolerance = 0.01) expect_equal(as.numeric(smoothness(x, "cor")), 0.9979799, tolerance = 0.01) }) diff --git a/tests/testthat/test-smoothness.R b/tests/testthat/test-smoothness.R index 07a81c07b..e7d2f48c1 100644 --- a/tests/testthat/test-smoothness.R +++ b/tests/testthat/test-smoothness.R @@ -2,7 +2,7 @@ test_that("smoothness works", { set.seed(123) x <- (-10:10)^3 + rnorm(21, 0, 100) expect_equal(smoothness(x)[[1]], 0.9030014, tolerance = 0.001) - expect_equal(smoothness(x, method = "auto")[[1]], 1.750452, tolerance = 0.001) + expect_equal(smoothness(x, method = "auto")[[1]], 0.5131369, tolerance = 0.001) }) test_that("smoothness works with iterations", { @@ -11,7 +11,7 @@ test_that("smoothness works with iterations", { set.seed(123) x <- (-10:10)^3 + rnorm(21, 0, 100) expect_equal(smoothness(x, iterations = 100)[[1]], 0.9030014, tolerance = 0.001) - expect_equal(smoothness(x, method = "auto", iterations = 100)[[1]], 1.750452, tolerance = 0.001) + expect_equal(smoothness(x, method = "auto", iterations = 100)[[1]], 0.5131369, tolerance = 0.001) })