Skip to content

New strategy to deal with monotonic constraints with dropped columns - #1025

Open
Marc-Antoine Schmidt (MarcAntoineSchmidtQC) wants to merge 4 commits into
mainfrom
monotonic-spans-intercept-main
Open

Marc-Antoine Schmidt (MarcAntoineSchmidtQC) wants to merge 4 commits into
mainfrom
monotonic-spans-intercept-main

Conversation

@MarcAntoineSchmidtQC

Copy link
Copy Markdown
Member

Paired with tabmat's pr 550, this PR fixes issue #1021. It uses a more direct approach compared to #1023.

Checklist

  • Added a CHANGELOG.rst entry

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical constraint-handling issues can exclude valid categorical-interaction fits and silently leave spline monotonicity unenforced on supported tabmat versions lacking the required metadata.

2 open issues
What changed in this PR

This PR addresses #1021 by accounting for implicitly zero coefficients when constructing monotonic constraints for dropped spline bases and categorical levels. Spline detection relies on metadata introduced by tabmat PR #550.

Changes:

  • Track dropped-column metadata and add sign constraints for the first remaining coefficient.
  • Pass that metadata through the estimator’s constraint setup.
  • Add prediction-level regression tests and document the fix and dependency caveat.
File Description
tests/​glm/​test_formula.py Tests monotone predictions with dropped columns and preserves unconstrained offsets for full spline bases.
src/​glum/​_glm.py Passes dropped-column metadata into constraint construction.
src/​glum/​_formula.py Detects dropped columns and anchors the first remaining coefficient.
CHANGELOG.rst Describes the fix and required tabmat metadata.

Review effort: Balanced

Comment thread src/glum/_formula.py
Comment on lines +197 to +199
_, state = model_spec.encoder_state.get(expr, (None, {}))
column_state: dict[str, Any] = next(iter(state.values()), {})
return column_state.get("spans_intercept") is False
Comment thread src/glum/_formula.py Resolved

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leveraging formulaic's spans_intercept here instead of reimplementing the parsing makes total sense, thanks for the implementation.

Comment thread src/glum/_formula.py Outdated
dropped_first: set[tuple[str, str]] = set()

for _term, scoped_terms, column_names in model_spec.structure:
# A term like C(a):C(b) without main effects splits into several scoped

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really get this comment.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair, let me reword it.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants