# SelectBoost for Dense Spectra

For dense spectra or finely sampled signals, `SelectBoost` is often most useful when grouping is constrained by functional structure instead of using a purely global correlation graph. The end-to-end workflow still starts from raw curves and optional scalar covariates.

## Construct a spectral design object

    library(SelectBoost.FDA)
    data("spectra_example", package = "SelectBoost.FDA")

    spectra <- fda_grid(
      spectra_example$predictors$signal,
      argvals = spectra_example$grid,
      name = "signal",
      unit = "nm"
    )
    nuisance <- fda_grid(
      spectra_example$predictors$nuisance,
      argvals = spectra_example$grid,
      name = "nuisance",
      unit = "nm"
    )

    design <- fda_design(
      response = spectra_example$response,
      predictors = list(signal = spectra, nuisance = nuisance),
      scalar_covariates = spectra_example$scalar_covariates,
      scalar_transform = fda_standardize(),
      family = "gaussian"
    )

    head(selection_map(design))
    #>           feature predictor  block position           argval representation
    #> signal.1 signal_1    signal signal        1             1100           grid
    #> signal.2 signal_2    signal signal        2 1135.89743589744           grid
    #> signal.3 signal_3    signal signal        3 1171.79487179487           grid
    #> signal.4 signal_4    signal signal        4 1207.69230769231           grid
    #> signal.5 signal_5    signal signal        5 1243.58974358974           grid
    #> signal.6 signal_6    signal signal        6 1279.48717948718           grid
    #>          basis_type transform source_predictor source_representation
    #> signal.1       <NA>  identity           signal                  grid
    #> signal.2       <NA>  identity           signal                  grid
    #> signal.3       <NA>  identity           signal                  grid
    #> signal.4       <NA>  identity           signal                  grid
    #> signal.5       <NA>  identity           signal                  grid
    #> signal.6       <NA>  identity           signal                  grid
    #>          source_position_start source_position_end source_argval_start
    #> signal.1                     1                   1                1100
    #> signal.2                     2                   2    1135.89743589744
    #> signal.3                     3                   3    1171.79487179487
    #> signal.4                     4                   4    1207.69230769231
    #> signal.5                     5                   5    1243.58974358974
    #> signal.6                     6                   6    1279.48717948718
    #>          source_argval_end     domain_start       domain_end component unit
    #> signal.1              1100             1100             1100      <NA>   nm
    #> signal.2  1135.89743589744 1135.89743589744 1135.89743589744      <NA>   nm
    #> signal.3  1171.79487179487 1171.79487179487 1171.79487179487      <NA>   nm
    #> signal.4  1207.69230769231 1207.69230769231 1207.69230769231      <NA>   nm
    #> signal.5  1243.58974358974 1243.58974358974 1243.58974358974      <NA>   nm
    #> signal.6  1279.48717948718 1279.48717948718 1279.48717948718      <NA>   nm
    #>          feature_index basis_component        domain_label
    #> signal.1             1            <NA>             1100 nm
    #> signal.2             2            <NA> 1135.89743589744 nm
    #> signal.3             3            <NA> 1171.79487179487 nm
    #> signal.4             4            <NA> 1207.69230769231 nm
    #> signal.5             5            <NA> 1243.58974358974 nm
    #> signal.6             6            <NA> 1279.48717948718 nm

## Fit FDA-aware SelectBoost

The fitting chunk below is evaluated only when `glmnet` is installed.

    sb_fit <- fit_selectboost(
      design,
      selector = "glmnet",
      selector_args = list(lambda_rule = "lambda.min"),
      mode = "fast",
      group_method = "threshold",
      bandwidth = 3,
      steps.seq = c(0.6, 0.2),
      B = 10,
      seed = 1
    )

    sb_fit
    #> FDA SelectBoost result
    #>   family: gaussian
    #>   mode: fast
    #>   features: 82
    #>   groups: 4
    #>   c0 values: 4
    summary(sb_fit)
    #> FDA SelectBoost summary
    #>   family: gaussian
    #>   predictors: 4
    #>   mode: fast
    #>   features: 82
    #>   groups: 4
    #>   c0 values: 4
    head(selection_map(sb_fit, c0 = colnames(sb_fit$feature_selection)[1]))
    #>           feature predictor  block position           argval representation
    #> signal.1 signal_1    signal signal        1             1100           grid
    #> signal.2 signal_2    signal signal        2 1135.89743589744           grid
    #> signal.3 signal_3    signal signal        3 1171.79487179487           grid
    #> signal.4 signal_4    signal signal        4 1207.69230769231           grid
    #> signal.5 signal_5    signal signal        5 1243.58974358974           grid
    #> signal.6 signal_6    signal signal        6 1279.48717948718           grid
    #>          basis_type transform source_predictor source_representation
    #> signal.1       <NA>  identity           signal                  grid
    #> signal.2       <NA>  identity           signal                  grid
    #> signal.3       <NA>  identity           signal                  grid
    #> signal.4       <NA>  identity           signal                  grid
    #> signal.5       <NA>  identity           signal                  grid
    #> signal.6       <NA>  identity           signal                  grid
    #>          source_position_start source_position_end source_argval_start
    #> signal.1                     1                   1                1100
    #> signal.2                     2                   2    1135.89743589744
    #> signal.3                     3                   3    1171.79487179487
    #> signal.4                     4                   4    1207.69230769231
    #> signal.5                     5                   5    1243.58974358974
    #> signal.6                     6                   6    1279.48717948718
    #>          source_argval_end     domain_start       domain_end component unit
    #> signal.1              1100             1100             1100      <NA>   nm
    #> signal.2  1135.89743589744 1135.89743589744 1135.89743589744      <NA>   nm
    #> signal.3  1171.79487179487 1171.79487179487 1171.79487179487      <NA>   nm
    #> signal.4  1207.69230769231 1207.69230769231 1207.69230769231      <NA>   nm
    #> signal.5  1243.58974358974 1243.58974358974 1243.58974358974      <NA>   nm
    #> signal.6  1279.48717948718 1279.48717948718 1279.48717948718      <NA>   nm
    #>          feature_index basis_component        domain_label selection     c0
    #> signal.1             1            <NA>             1100 nm       0.0 c0 = 1
    #> signal.2             2            <NA> 1135.89743589744 nm       0.0 c0 = 1
    #> signal.3             3            <NA> 1171.79487179487 nm       0.0 c0 = 1
    #> signal.4             4            <NA> 1207.69230769231 nm       0.0 c0 = 1
    #> signal.5             5            <NA> 1243.58974358974 nm       0.1 c0 = 1
    #> signal.6             6            <NA> 1279.48717948718 nm       0.0 c0 = 1
    #>          group_id  group
    #> signal.1        1 signal
    #> signal.2        1 signal
    #> signal.3        1 signal
    #> signal.4        1 signal
    #> signal.5        1 signal
    #> signal.6        1 signal
    selected(sb_fit, level = "group", c0 = colnames(sb_fit$feature_selection)[1])
    #>   predictor group_id     group representation basis_type source_representation
    #> 1    signal        1    signal           grid                             grid
    #> 2  nuisance        2  nuisance           grid                             grid
    #> 3       age        3       age         scalar                           scalar
    #> 4 treatment        4 treatment         scalar                           scalar
    #>   n_features start_position end_position start_argval end_argval domain_start
    #> 1         40              1           40         1100       2500         1100
    #> 2         40              1           40         1100       2500         1100
    #> 3          1              1            1          age        age          age
    #> 4          1              1            1    treatment  treatment    treatment
    #>   domain_end     c0 mean_selection max_selection selected_features
    #> 1       2500 c0 = 1          0.160             1                 9
    #> 2       2500 c0 = 1          0.155             1                10
    #> 3        age c0 = 1          1.000             1                 1
    #> 4  treatment c0 = 1          1.000             1                 1
    plot(
      sb_fit,
      type = "group",
      value = "mean",
      legend_title = "Mean selection",
      palette = grDevices::terrain.colors(24)
    )

The `selection_map()` method keeps the wavelength information attached to each coefficient, which is the main advantage of moving from raw matrices to FDA-native design objects.