Skip to content

[Repo Assist] fix(pss): stop _get_strata from mutating the caller's DataFrame - #1789

Draft
github-actions[bot] wants to merge 1 commit into
mainfrom
repo-assist/fix-pss-get-strata-dataframe-mutation-1a9e32b7d4bcc3b4
Draft

[Repo Assist] fix(pss): stop _get_strata from mutating the caller's DataFrame#1789
github-actions[bot] wants to merge 1 commit into
mainfrom
repo-assist/fix-pss-get-strata-dataframe-mutation-1a9e32b7d4bcc3b4

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🤖 This PR was created by Repo Assist, an automated AI assistant.

Problem

PropensityScoreStratificationEstimator._get_strata directly mutates the DataFrame passed to it by adding four internal bookkeeping columns:

data["strata"] = ...
data["dbar"] = ...
data["d_y"] = ...
data["dbar_y"] = ...

Because estimate_effect() passes the caller's data argument straight into _get_strata, any code that reuses the same DataFrame after calling estimate_effect() finds four unexpected columns polluting its data.

Example of the bug:

model.estimate_effect(estimand, method_name="backdoor.propensity_score_stratification", ...)
print(data.columns)
# Index(['W', 'T', 'Y', 'propensity_score', 'strata', 'dbar', 'd_y', 'dbar_y'], ...)
#                                              ^^^^^^  unexpected internal columns ^

Fix

Add data = data.copy() at the start of _get_strata so all mutations are local to the method. The copy is a shallow/view-friendly pandas copy and adds negligible overhead since _get_strata is called at most a handful of times per estimate_effect invocation.

The clipped subset returned by the method still carries the newly added columns (required by the aggregation in estimate_effect()), so correctness is unaffected.

Test

Added test_estimate_effect_does_not_mutate_input_dataframe() to tests/causal_estimators/test_propensity_score_stratification_estimator.py. The test:

  1. Creates a simple linear dataset.
  2. Calls estimate_effect with PSS.
  3. Asserts that none of the four internal column names (strata, dbar, d_y, dbar_y) are present on the original DataFrame.

Test Status

  • black --check passes on all modified files
  • flake8 — no new violations introduced
  • ⚠️ Full test suite requires poetry install (causallearn not available in the CI-lite environment); the logic of _get_strata is unchanged — only a .copy() is prepended

Generated by 🌈 Repo Assist, see workflow run. Learn more.

Generated by 🌈 Repo Assist, see workflow run. Learn more.

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@11c9a2c442e519ff2b427bf58679f5a525353f76

PropensityScoreStratificationEstimator._get_strata added four internal
columns (strata, dbar, d_y, dbar_y) directly to the DataFrame passed in
by the caller.  Any code that reused the same DataFrame after calling
estimate_effect() would see these unexpected columns in its data.

Fix: make a shallow copy of data at the start of _get_strata so the
internal bookkeeping columns are confined to that local copy.  The
clipped subset returned by the method retains the columns it needs for
the downstream groupby aggregations in estimate_effect(), but the
caller's original DataFrame is unchanged.

Also adds a regression test that asserts none of the four internal
column names appear on the input DataFrame after estimate_effect()
returns.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants