import whittaker as wk
# Load data and fit single-smooth GAM
data = wk.load_dataset("mcycle")
model = wk.GAM("accel ~ s(times)").fit(data)Check Basis Dimension Adequacy
Every smooth in a Whittaker GAM is represented by k basis functions. If k is too small, the smooth cannot capture the true shape of the relationship, no matter how much data you have. The k-index test detects this by comparing the spatial autocorrelation of the residuals against what you would expect from a well-fitted smooth.
Run the check
Fit a simple GAM as a starting point.
model.k_check() returns one KCheckResult per smooth term. For a single-smooth model the element of interest is the first one.
kc = model.k_check()
kc[0].k_index1.08658177153535
A k-index at or above 1 indicates that the basis dimension is adequate. Values below 0.8 are a warning sign that k is too small to capture the true shape of the relationship.
kc[0].p_value0.8725
A p-value below 0.05 would corroborate that warning. Here both diagnostics are healthy, so the default k = 10 is sufficient for this dataset.
The diagnostic table also includes the effective degrees of freedom (EDF) used by the smooth and the basis dimension k itself.
k_prime: the number of basis functions available to the smooth (the value passed ask, minus one for the identifiability constraint).edf: the effective degrees of freedom actually used. If EDF is close tok_prime, the smooth is pressing against the basis limit.k_index: residual autocorrelation relative to its expected value. At or above 1 is fine whereas below 0.8 is a concern.- p_value: significance of the k-index test. Small values (<0.05) suggest inadequacy.
What to do if k is too small
If either diagnostic raises a concern, refit with a larger k inside the s() call. Common choices are 20 or 30.
# Refit with a larger basis dimension
model_k20 = wk.GAM("accel ~ s(times, k=20)").fit(data)
kc20 = model_k20.k_check()Compare the EDF before and after increasing k. If the EDF rises substantially, the original k was genuinely constraining the smooth.
# original model: k = 10
kc[0].edf7.916222078330314
# refitted model: k = 20
kc20[0].edf8.860806579903668
The EDF barely changes here, which confirms that the default basis was not too small. Look at the full summaries side by side to see how the other diagnostics compare.
model.summary()GAM fit summary
============================================================
Formula: accel ~ s(times)
Family: Gaussian(link='identity')
Observations: 133
Coefficients: 10
Parametric coefficients:
Term Estimate Std.Err t value p-value
------------------------ ---------- ---------- ---------- ----------
(Intercept) -45.6924 1.8364 -24.882 < 1e-16
Approximate significance of smooth terms:
Term EDF Ref.df Chi.sq p-value
------------------------ ------ ------ ---------- ----------
s(times) 7.92 8 663.396 < 1e-16
Total EDF: 8.92
Deviance: 55653.7152
Null dev: 357878.4929
Dev. expl: 84.4%
GCV score: 480.746119
Scale est: 448.517253
AIC: 1198.44
BIC: 1224.22
model_k20.summary()GAM fit summary
============================================================
Formula: accel ~ s(times, k=20)
Family: Gaussian(link='identity')
Observations: 133
Coefficients: 20
Parametric coefficients:
Term Estimate Std.Err t value p-value
------------------------ ---------- ---------- ---------- ----------
(Intercept) -45.6924 1.8426 -24.798 < 1e-16
Approximate significance of smooth terms:
Term EDF Ref.df Chi.sq p-value
------------------------ ------ ------ ---------- ----------
s(times, k=20) 8.86 9 654.303 < 1e-16
Total EDF: 9.86
Deviance: 55603.4152
Null dev: 357878.4929
Dev. expl: 84.5%
GCV score: 487.708696
Scale est: 451.549289
AIC: 1200.29
BIC: 1228.79
Rule of thumb
A well-chosen k leaves room to spare: the EDF should be noticeably below k − 1. If EDF ≈ k − 1 (within about 0.5), the penalty is pressing against the basis dimension limit rather than controlling the smooth’s wiggliness, and a larger k is warranted. There is little cost to using a generous k (penalization will shrink the smooth back toward the appropriate flexibility) so err on the side of too large rather than too small.