% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/hop-index.R
\name{hop_index}
\alias{hop_index}
\alias{hop_index_vec}
\title{Hop relative to an index}
\usage{
hop_index(.x, .i, .starts, .stops, .f, ...)

hop_index_vec(.x, .i, .starts, .stops, .f, ..., .ptype = NULL)
}
\arguments{
\item{.x}{\verb{[vector]}

The vector to iterate over and apply \code{.f} to.}

\item{.i}{\verb{[vector]}

The index vector that determines the window sizes. It is fairly common to
supply a date vector as the index, but not required.

There are 3 restrictions on the index:
\itemize{
\item The size of the index must match the size of \code{.x}, they will not be
recycled to their common size.
\item The index must be an \emph{increasing} vector, but duplicate values
are allowed.
\item The index cannot have missing values.
}}

\item{.starts, .stops}{\verb{[vector]}

Vectors of boundary values that make up the windows to bucket \code{.i} with.
Both \code{.starts} and \code{.stops} will be recycled to their common size, and
that common size will be the size of the result. Both vectors will be cast
to the type of \code{.i} using \code{\link[vctrs:vec_cast]{vctrs::vec_cast()}}. These boundaries are both
\emph{inclusive}, meaning that the slice of \code{.x} that will be used in each call
to \code{.f} is where \code{.i >= start & .i <= stop} returns \code{TRUE}.}

\item{.f}{\verb{[function / formula]}

If a \strong{function}, it is used as is.

If a \strong{formula}, e.g. \code{~ .x + 2}, it is converted to a function. There
are three ways to refer to the arguments:
\itemize{
\item For a single argument function, use \code{.}
\item For a two argument function, use \code{.x} and \code{.y}
\item For more arguments, use \code{..1}, \code{..2}, \code{..3} etc
}

This syntax allows you to create very compact anonymous functions.}

\item{...}{Additional arguments passed on to the mapped function.}

\item{.ptype}{\verb{[vector(0) / NULL]}

A prototype corresponding to the type of the output.

If \code{NULL}, the default, the output type is determined by computing the
common type across the results of the calls to \code{.f}.

If supplied, the result of each call to \code{.f} will be cast to that type,
and the final output will have that type.

If \code{getOption("vctrs.no_guessing")} is \code{TRUE}, the \code{.ptype} must be
supplied. This is a way to make production code demand fixed types.}
}
\value{
A vector fulfilling the following invariants:

\subsection{\code{hop_index()}}{
\itemize{
\item \code{vec_size(hop_index(.x, .starts, .stops)) == vec_size_common(.starts, .stops)}
\item \code{vec_ptype(hop_index(.x, .starts, .stops)) == list()}
}

}

\subsection{\code{hop_index_vec()}}{
\itemize{
\item \code{vec_size(hop_index_vec(.x, .starts, .stops)) == vec_size_common(.starts, .stops)}
\item \code{vec_size(hop_index_vec(.x, .starts, .stops)[[1]]) == 1L}
\item \code{vec_ptype(hop_index_vec(.x, .starts, .stops, .ptype = ptype)) == ptype}
}

}
}
\description{
\code{hop_index()} is the lower level engine that powers \code{\link[=slide_index]{slide_index()}}. It
has slightly different invariants than \code{slide_index()}, and is useful when
you either need to hand craft boundary values, or want to compute a result
with a size that is different from \code{.x}.
}
\examples{
library(vctrs)
library(lubridate, warn.conflicts = FALSE)

# ---------------------------------------------------------------------------
# Returning a size smaller than `.x`

i <- as.Date("2019-01-25") + c(0, 1, 2, 3, 10, 20, 35, 42, 45)

# slide_index() allows you to slide relative to `i`
slide_index(i, i, ~.x, .before = weeks(1))

# But you might be more interested in coarser summaries. This groups
# by year-month and computes 2 `.f` on 2 month windows.
i_yearmonth <- year(i) + (month(i) - 1) / 12
slide_index(i, i_yearmonth, ~.x, .before = 1)

# ^ This works nicely when working with dplyr if you are trying to create
# a new column in a data frame, but you'll notice that there are really only
# 3 months, so only 3 values are being calculated. If you only want to return
# a vector of those 3 values, you can use `hop_index()`. You'll have to
# hand craft the boundaries, but this is a general strategy
# I've found useful:
first_start <- floor_date(i[1], "months")
last_stop <- ceiling_date(i[length(i)], "months")
dates <- seq(first_start, last_stop, "1 month")
inner <- dates[2:(length(dates) - 1L)]
starts <- vec_c(first_start, inner)
stops <- vec_c(inner - 1, last_stop)

hop_index(i, i, starts, stops, ~.x)

# ---------------------------------------------------------------------------
# Non-existant dates with `lubridate::months()`

# Imagine you want to compute a 1 month rolling average on this
# irregular daily data.
i <- vec_c(as.Date("2019-02-27") + 0:3, as.Date("2019-03-27") + 0:5)
x <- rnorm(vec_seq_along(i))

# You might try `slide_index()` like this, but you'd run into this error
library(rlang)

with_options(
  catch_cnd(
    slide_index(x, i, mean, .before = months(1))
  ),
  rlang_backtrace_on_error = current_env()
)

# This is because when you actually compute the `.i - .before` sequence,
# you hit non-existant dates. i.e. `"2019-03-29" - months(1)` doesn't exist.
i - months(1)

# To get around this, lubridate provides `add_with_rollback()`,
# and the shortcut operation `\%m-\%`, which subtracts the month, then rolls
# forward/backward if it hits an `NA`. You can manually generate boundaries,
# then provide them to `hop_index()`.
starts <- i \%m-\% months(1)
stops <- i

hop_index(x, i, starts, stops, mean)

hop_index(i, i, starts, stops, ~.x)

}
\seealso{
\code{\link[=slide]{slide()}}, \code{\link[=slide_index]{slide_index()}}, \code{\link[=hop_index2]{hop_index2()}}
}
