Skip to content

fix(propensity): seed and stratify the early-stopping validation split - #1051

Merged
jeongyoonlee merged 1 commit into
uber:masterfrom
ismailvc1111:fix/propensity-early-stop-seed-stratify
Oct 3, 2026
Merged

jeongyoonlee merged 1 commit into
uber:masterfrom
ismailvc1111:fix/propensity-early-stop-seed-stratify

Conversation

@ismailvc1111

Copy link
Copy Markdown
Contributor

Fixes #1045.

GradientBoostedPropensityModel.fit() drew its early-stopping validation set with no random_state and no stratify. The classifier was seeded, but the split came from the global numpy stream, so the same seed gave different propensity scores on each fit (up to ~0.55 apart in the issue's example). The split was also not stratified on treatment, so rare-treatment data could leave the validation set without treated units.

Changes:

  • Use the same seed the classifier uses, self.model_kwargs.get("random_state", 42), so random_state=None still means random.
  • Stratify on treatment when every class has at least two members. For degenerate treatment vectors it falls back to a plain split, so this does not add a new ValueError path.

Validation:

  • Two regression tests in tests/test_propensity.py: repeated fits with the same seed return identical scores, and the split receives the seed and treatment stratification. Both fail on master and pass with this change.
  • pytest tests/test_propensity.py: 9/9 pass.
  • Full pytest tests: 561 passed. 4 failures are in the uplift tree visualization tests (pydotplus vs the installed pyparsing). They fail the same way without this change.
  • black --check on both changed files: clean.

GradientBoostedPropensityModel drew its early-stopping validation set
with no random_state and no stratification. The classifier was seeded,
but the split came from the global numpy stream, so the same seed gave
different propensity scores on every fit. The split was also not
stratified on treatment, so rare-treatment data could leave the
validation set with no treated units.

Pass the same seed the classifier uses, and stratify on treatment when
every class has at least two members. Fall back to a plain split for
degenerate treatment vectors so this does not introduce a new error.

Adds two regression tests: repeated fits with the same seed agree, and
the split receives the seed and treatment stratification.
@CLAassistant

CLAassistant commented Oct 3, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@jeongyoonlee
jeongyoonlee self-requested a review October 3, 2026 19:35

@jeongyoonlee jeongyoonlee left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. Thanks for your contribution.

@jeongyoonlee
jeongyoonlee merged commit 1d35d55 into uber:master Oct 3, 2026
13 of 15 checks passed
@jeongyoonlee jeongyoonlee mentioned this pull request Oct 11, 2026
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.

GradientBoostedPropensityModel early-stopping split ignores random_state and is not stratified

3 participants