FAQ¶
Why does fit() raise TypeError: Unsupported model type?
Decision-point extraction reads the serialized trees and accepts only a
LightGBM Booster or an XGBoost Booster. The scikit-learn wrappers
(LGBMClassifier, XGBClassifier, …) are not accepted directly — pass the
underlying booster instead, e.g. SWIFTMonitor(model=clf.booster_) for
LightGBM, or train with the native API (lgb.train).
Why is no p-value ever exactly zero?
The permutation test uses the conservative formula
\(p = (1 + \#\{\text{permutation score} \ge \text{observed}\}) / (1 + B)\),
so the smallest attainable p-value is \(1/(1+B)\). With the default
n_permutations=1000 that is roughly 0.001; raise n_permutations when you
need finer resolution.
Can I compare two production windows instead of testing against the
reference?
Yes. score() and test() accept X_compare: the comparison then runs
between X and X_compare, while the SHAP transformation (buckets + mean
SHAP) is always the one fitted on the reference. See
scikit-learn integration.
How are missing values handled?
Every feature's bucket set includes a null bucket (index 0). NaN values map to
it during transform(), so missingness gets its own mean-SHAP level and a
change in the missing-value rate is visible to the drift test. See
Buckets.
What happens to a feature the model never splits on? It gets no decision points, so its whole domain is a single catch-all bucket \((-\infty, +\infty)\). Every value transforms to the same mean SHAP, both distributions become identical after transformation, and the feature's SWIFT score is 0 — a feature the model ignores cannot raise a drift alarm. This is intended behavior, not a bug. See Buckets.
What is n_synthetic for?
Buckets with zero reference observations have no data to average SHAP over.
During fit(), SWIFT samples n_synthetic real reference rows, places the
feature value inside the empty bucket, and computes SHAP on those synthetic
rows. If no model were available the bucket would fall back to
mean_shap = 0.0 with a warning. See
Normalization.
Which strings does correction accept?
"benjamini-hochberg" (aliases "bh", "fdr") and "bonferroni" (alias
"bonf"), case-insensitively; enum members from
swift.types.CorrectionMethod also work. Anything else raises ValueError
listing the valid values.
The permutation test is slow on large datasets — what can I do?
Set max_samples: when the pooled reference + monitoring data exceeds it,
both samples are randomly subsampled (preserving the reference/monitoring
ratio) before the permutation loop — a significant speedup with negligible
impact on statistical power. Lowering n_permutations (e.g. to 200 for
exploratory runs) also helps; see
configuration.
Do I need to re-fit after changing parameters?
Only when the fitted state depends on them: changing model or n_synthetic
requires calling fit() again. Test-time parameters — order,
n_permutations, alpha, correction, max_samples — are read from the
instance on each test() call, so set_params() is enough.