From d6a5c27f5151db16641a028fd3a36c54b74ac662 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 01:37:52 +0000 Subject: [PATCH 1/3] fix: handle list-form treatment_variable in estimate_effect_naive estimate_effect_naive() failed with a ValueError when treatment_variable or outcome_variable were lists (as returned by parse_state), because data[[list]] == 1 produces a 2D boolean DataFrame that cannot be used as a .loc index key. Also fix hardcoded treatment_value=1 / control_value=0: now uses self._treatment_value and self._control_value (set by update_input()) so non-binary treatments work correctly. Fixes #416 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: github-actions[bot] --- dowhy/causal_estimator.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dowhy/causal_estimator.py b/dowhy/causal_estimator.py index 23de0587ac..60b116336f 100755 --- a/dowhy/causal_estimator.py +++ b/dowhy/causal_estimator.py @@ -206,13 +206,17 @@ def estimate_effect_naive(self, data: pd.DataFrame): """ :param data: Pandas dataframe to estimate effect """ - # TODO Only works for binary treatment - df_withtreatment = data.loc[data[self._target_estimand.treatment_variable] == 1] - df_notreatment = data.loc[data[self._target_estimand.treatment_variable] == 0] - est = np.mean(df_withtreatment[self._target_estimand.outcome_variable]) - np.mean( - df_notreatment[self._target_estimand.outcome_variable] - ) - return CausalEstimate(data, None, None, est, None, control_value=0, treatment_value=1) + # TODO Only works for a single treatment variable + treatment_variable = self._target_estimand.treatment_variable + treatment_name = treatment_variable[0] if isinstance(treatment_variable, list) else treatment_variable + outcome_variable = self._target_estimand.outcome_variable + outcome_name = outcome_variable[0] if isinstance(outcome_variable, list) else outcome_variable + treatment_value = getattr(self, "_treatment_value", 1) + control_value = getattr(self, "_control_value", 0) + df_withtreatment = data.loc[data[treatment_name] == treatment_value] + df_notreatment = data.loc[data[treatment_name] == control_value] + est = np.mean(df_withtreatment[outcome_name]) - np.mean(df_notreatment[outcome_name]) + return CausalEstimate(data, None, None, est, None, control_value=control_value, treatment_value=treatment_value) def _estimate_effect_fn(self, data_df): """Function used in conditional effect estimation. This function is to be overridden by each child estimator. From 76c130cbdcb6a8f4b5108a41e36af650b259b449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emre=20K=C4=B1c=C4=B1man?= Date: Fri, 17 Apr 2026 00:14:47 -0700 Subject: [PATCH 2/3] Potential fix for pull request finding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Emre Kıcıman --- dowhy/causal_estimator.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/dowhy/causal_estimator.py b/dowhy/causal_estimator.py index 60b116336f..483f70c900 100755 --- a/dowhy/causal_estimator.py +++ b/dowhy/causal_estimator.py @@ -208,9 +208,25 @@ def estimate_effect_naive(self, data: pd.DataFrame): """ # TODO Only works for a single treatment variable treatment_variable = self._target_estimand.treatment_variable - treatment_name = treatment_variable[0] if isinstance(treatment_variable, list) else treatment_variable + if isinstance(treatment_variable, list): + if len(treatment_variable) != 1: + raise ValueError( + "estimate_effect_naive only supports exactly one treatment variable, " + f"got {len(treatment_variable)}: {treatment_variable}" + ) + treatment_name = treatment_variable[0] + else: + treatment_name = treatment_variable outcome_variable = self._target_estimand.outcome_variable - outcome_name = outcome_variable[0] if isinstance(outcome_variable, list) else outcome_variable + if isinstance(outcome_variable, list): + if len(outcome_variable) != 1: + raise ValueError( + "estimate_effect_naive only supports exactly one outcome variable, " + f"got {len(outcome_variable)}: {outcome_variable}" + ) + outcome_name = outcome_variable[0] + else: + outcome_name = outcome_variable treatment_value = getattr(self, "_treatment_value", 1) control_value = getattr(self, "_control_value", 0) df_withtreatment = data.loc[data[treatment_name] == treatment_value] From 09df007b401942f5a7bb8695bee72aa33f0c6aef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emre=20K=C4=B1c=C4=B1man?= Date: Fri, 17 Apr 2026 00:15:38 -0700 Subject: [PATCH 3/3] Potential fix for pull request finding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Emre Kıcıman --- dowhy/causal_estimator.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dowhy/causal_estimator.py b/dowhy/causal_estimator.py index 483f70c900..29ac341344 100755 --- a/dowhy/causal_estimator.py +++ b/dowhy/causal_estimator.py @@ -232,7 +232,15 @@ def estimate_effect_naive(self, data: pd.DataFrame): df_withtreatment = data.loc[data[treatment_name] == treatment_value] df_notreatment = data.loc[data[treatment_name] == control_value] est = np.mean(df_withtreatment[outcome_name]) - np.mean(df_notreatment[outcome_name]) - return CausalEstimate(data, None, None, est, None, control_value=control_value, treatment_value=treatment_value) + return CausalEstimate( + data, + treatment_name, + outcome_name, + est, + None, + control_value=control_value, + treatment_value=treatment_value, + ) def _estimate_effect_fn(self, data_df): """Function used in conditional effect estimation. This function is to be overridden by each child estimator.