Converts complete long-format exposure profiles into one epidemic-level design row per `epi_id`. For each exposure, the function reconstructs a new DLNM cross-basis from that epidemic's observed exposure profile using the **effective basis parameterization stored in the supplied training template**, then retains the final cross-basis row after chronological ordering.
Usage
build_design(
data,
cb_templates,
max_lag = NULL,
include_response = TRUE,
groups = "epi_id"
)Arguments
- data
Non-empty long-format data frame containing `epi_id`, `time`, and every exposure represented in `cb_templates`. Rows are ordered internally by `epi_id` and `time`. Under the EpiExposure exact-profile contract, every epidemic must contain exactly the common fitted `max_lag + 1` time points. Because all exposure variables are finite columns of those same rows, all fitted exposures necessarily use the same temporal support and profile length.
If a column `y` is present and `include_response = TRUE`, `y` must contain exactly one finite numeric outcome value per epidemic.
- cb_templates
Named list of `dlnm::crossbasis` objects, normally returned by `define_exposures()`. Every element must contain valid effective `argvar`, `arglag`, and `lag` attributes.
The cross-basis objects themselves are not reused numerically for new epidemics. Their stored effective parameterization is reused to transform each new exposure profile.
- max_lag
Optional lag validation argument retained for backward compatibility. `cb_templates` are the authoritative source of the fitted lag definition and `max_lag` never overrides them.
All templates must share one common maximum lag. If `NULL`, that common lag is read directly from the templates. If supplied, `max_lag` may be one non-negative integer scalar or the legacy two-element form `c(0, L)`; after normalization its maximum must equal the common template lag. Exposure-specific/named lag windows are not supported by the current EpiExposure exact-profile contract.
- include_response
Logical. If `TRUE` and `data` contains `y`, append one response value per epidemic. If `FALSE`, `y` is ignored.
- groups
Non-empty character vector of identifier columns to preserve in the final design. Must include `"epi_id"`; the default is `"epi_id"`. Additional identifiers, such as `"block"`, `"site"`, or `"year"`, must exist in `data`, contain no missing values, and be constant within each `epi_id`. They do not redefine the exposure-profile unit, which remains exclusively `epi_id`.
Value
A data frame with one row per epidemic containing the identifier columns specified in `groups`, canonical cross-basis columns named `cb_<exposure>_<column_index>`, and, optionally, `y`.
The returned data frame stores the following attributes:
- `"cb_templates"`: the original supplied cross-basis templates; - `"epiexposure_spec"`: effective per-exposure basis specification synchronized to the template attributes; - `"epiexposure_cb_cols"`: canonical cross-basis column order; - `"epiexposure_vars"`: exposure names; - `"epiexposure_max_lag"`: common fitted maximum lag; - `"epiexposure_history_length"`: exact required profile length, `max_lag + 1`; - `"epiexposure_history_contract"`: `"all_fitted_exposures_same_exact_max_lag_plus_one"`; - `"epiexposure_time_step"`: common time-series spacing, or `NA` when `max_lag = 0` because a one-point profile has no estimable spacing; - `"epiexposure_design_contract"`: `"final_crossbasis_row_per_group"`; - `"epiexposure_group_cols"`: identifier columns preserved in the design.
Details
`build_design()` never re-estimates spline knots, boundary knots, degrees of freedom, or lag-basis parameters from the input `data`. The supplied `cb_templates` are authoritative for basis transport.
## Temporal requirements
A vector supplied to `dlnm::crossbasis()` is interpreted as one complete, equally spaced exposure profile. Accordingly, `build_design()` requires finite numeric time, unique times within epidemics, constant spacing within each epidemic when more than one time point is present, and the same spacing across epidemics.
If the common fitted maximum lag is `L`, every epidemic must contain exactly
$$ L + 1 $$
observations. Profiles with fewer or more observations are rejected. `build_design()` never truncates an older profile, selects a trailing window, pads a shorter profile, or silently aligns exposures with different lag windows. Since every exposure is evaluated on the same rows of `data`, all fitted exposures have identical temporal length and support.
For `max_lag = 0`, the exact profile length is one observation. In that special case no within-profile time interval exists, so `epiexposure_time_step` is stored as `NA`.
## Training-template transport
For each exposure `x`, reconstruction is conceptually:
“` dlnm::crossbasis( x, lag = attr(training_template, "lag"), argvar = attr(training_template, "argvar"), arglag = attr(training_template, "arglag") ) “`
The numerical cross-basis values change with the new exposure profile while the training basis definition remains fixed. Reconstructed bases must retain the training template's number of columns and native column names/order before canonical EpiExposure names are assigned.
## Template storage
`attr(result, "cb_templates")` stores the **original supplied templates**, not a cross-basis reconstructed from the first epidemic. This preserves the original training basis definition for later prediction and validation.
