Skip to contents

Extract and tidy penalty matrices


penalty(object, ...)

# S3 method for default
penalty(object, rescale = FALSE, data, knots = NULL, constraints = FALSE, ...)

# S3 method for gam
  select = NULL,
  smooth = deprecated(),
  rescale = FALSE,
  partial_match = FALSE,

# S3 method for mgcv.smooth
penalty(object, rescale = FALSE, ...)

# S3 method for tensor.smooth
penalty(object, margins = FALSE, ...)

# S3 method for t2.smooth
penalty(object, margins = FALSE, ...)

# S3 method for re.smooth.spec
penalty(object, data, ...)



a fitted GAM or a smooth.


additional arguments passed to methods.


logical; by default, mgcv will scale the penalty matrix for better performance in mgcv::gamm(). If rescale is TRUE, this scaling will be undone to put the penalty matrix back on the original scale.


data frame; a data frame of values for terms mentioned in the smooth specification.


a list or data frame with named components containing knots locations. Names must match the covariates for which the basis is required. See mgcv::smoothCon().


logical; should identifiability constraints be applied to the smooth basis. See argument absorb.cons in mgcv::smoothCon().


character, logical, or numeric; which smooths to extract penalties for. If NULL, the default, then penalties for all model smooths are drawn. Numeric select indexes the smooths in the order they are specified in the formula and stored in object. Character select matches the labels for smooths as shown for example in the output from summary(object). Logical select operates as per numeric select in the order that smooths are stored.


[Deprecated] Use select instead.


logical; should smooths be selected by partial matches with select? If TRUE, select can only be a single string to match against.


logical; extract the penalty matrices for the tensor product or the marginal smooths of the tensor product?


A 'tibble' (data frame) of class penalty_df inheriting from tbl_df, with the following components:

  • .smooth - character; the label mgcv uses to refer to the smooth,

  • .type - character; the type of smooth,

  • .penalty - character; the label for the specific penalty. Some smooths have multiple penalty matrices, so the penalty component identifies the particular penalty matrix and uses the labelling that mgcv uses internally,

  • .row - character; a label of the form fn where n is an integer for the nth basis function, referencing the columns of the penalty matrix,

  • .col - character; a label of the form fn where n is an integer for the nth basis function, referencing the columns of the penalty matrix,

  • .value - double; the value of the penalty matrix for the combination of row and col,


The print() method uses base::zapsmall() to turn very small numbers into 0s for display purposes only; the underlying values of the penalty matrix or matrices are not changed.

For smooths that are subject to an eigendecomposition (e.g. the default thin plate regression splines, bs = "tp"), the signs of the eigenvectors are not defined and as such you can expect differences across systems in the penalties for such smooths that are system-, OS-, and CPU architecture- specific.


Gavin L. Simpson


# \dontshow{
op <- options(cli.unicode = FALSE, pillar.sigfig = 3)
# }
dat <- data_sim("eg4", n = 400, seed = 42)
m <- gam(
  y ~ s(x0, bs = "cr") + s(x1, bs = "cr") +
    s(x2, by = fac, bs = "cr"),
  data = dat, method = "REML"

# penalties for all smooths
#> # A tibble: 405 x 6
#>    .smooth .type .penalty .row  .col   .value
#>    <chr>   <chr> <chr>    <chr> <chr>   <dbl>
#>  1 s(x0)   CRS   s(x0)    F1    F1     0.783 
#>  2 s(x0)   CRS   s(x0)    F1    F2    -0.635 
#>  3 s(x0)   CRS   s(x0)    F1    F3     0.265 
#>  4 s(x0)   CRS   s(x0)    F1    F4    -0.0203
#>  5 s(x0)   CRS   s(x0)    F1    F5     0.0441
#>  6 s(x0)   CRS   s(x0)    F1    F6     0.0378
#>  7 s(x0)   CRS   s(x0)    F1    F7     0.0482
#>  8 s(x0)   CRS   s(x0)    F1    F8     0.0216
#>  9 s(x0)   CRS   s(x0)    F1    F9     0.0247
#> 10 s(x0)   CRS   s(x0)    F2    F1    -0.635 
#> # i 395 more rows

# for a specific smooth
penalty(m, select = "s(x2):fac1")
#> # A tibble: 81 x 6
#>    .smooth    .type .penalty   .row  .col   .value
#>    <chr>      <chr> <chr>      <chr> <chr>   <dbl>
#>  1 s(x2):fac1 CRS   s(x2):fac1 F1    F1     1.66  
#>  2 s(x2):fac1 CRS   s(x2):fac1 F1    F2    -0.755 
#>  3 s(x2):fac1 CRS   s(x2):fac1 F1    F3     0.430 
#>  4 s(x2):fac1 CRS   s(x2):fac1 F1    F4     0.0846
#>  5 s(x2):fac1 CRS   s(x2):fac1 F1    F5     0.192 
#>  6 s(x2):fac1 CRS   s(x2):fac1 F1    F6     0.152 
#>  7 s(x2):fac1 CRS   s(x2):fac1 F1    F7     0.188 
#>  8 s(x2):fac1 CRS   s(x2):fac1 F1    F8     0.164 
#>  9 s(x2):fac1 CRS   s(x2):fac1 F1    F9     0.0597
#> 10 s(x2):fac1 CRS   s(x2):fac1 F2    F1    -0.755 
#> # i 71 more rows

# \dontshow{
# }