Skip to content

Commit ade2692

Browse files
shrutipatel31facebook-github-bot
authored andcommitted
Improve Summary Analysis by Relativize the metric results if there is a status quo to relativize against
Differential Revision: D82658357
1 parent cd0b6ab commit ade2692

File tree

3 files changed

+119
-3
lines changed

3 files changed

+119
-3
lines changed

ax/analysis/summary.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,6 @@ def compute(
7373
trial_indices=self.trial_indices,
7474
omit_empty_columns=self.omit_empty_columns,
7575
trial_statuses=self.trial_statuses,
76+
relativize=True,
7677
),
7778
)

ax/core/experiment.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,7 @@ def to_df(
19641964
trial_indices: Iterable[int] | None = None,
19651965
trial_statuses: Sequence[TrialStatus] | None = None,
19661966
omit_empty_columns: bool = True,
1967+
relativize: bool = False,
19671968
) -> pd.DataFrame:
19681969
"""
19691970
High-level summary of the Experiment with one row per arm. Any values missing at
@@ -1985,10 +1986,22 @@ def to_df(
19851986
trial_indices: If specified, only include these trial indices.
19861987
omit_empty_columns: If True, omit columns where every value is None.
19871988
trial_status: If specified, only include trials with this status.
1989+
relativize: If True and experiment has a status quo, relativize metrics
19881990
"""
19891991

19901992
records = []
1991-
data_df = self.lookup_data(trial_indices=trial_indices).df
1993+
data = self.lookup_data(trial_indices=trial_indices)
1994+
data_df = data.df
1995+
1996+
# Relativize metrics if requested and experiment has status quo
1997+
if relativize and self.status_quo is not None:
1998+
relativized_data = data.relativize(
1999+
status_quo_name=none_throws(self.status_quo).name,
2000+
as_percent=True,
2001+
include_sq=True,
2002+
)
2003+
data_df = relativized_data.df
2004+
19922005
trials = (
19932006
self.get_trials_by_indices(trial_indices=trial_indices)
19942007
if trial_indices
@@ -2048,6 +2061,7 @@ def to_df(
20482061
records.append(record)
20492062

20502063
df = pd.DataFrame(records)
2064+
20512065
if omit_empty_columns:
20522066
df = df.loc[:, df.notnull().any()]
20532067
return df

ax/core/tests/test_experiment.py

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
)
7575
from ax.utils.testing.mock import mock_botorch_optimize
7676
from pandas.testing import assert_frame_equal
77-
from pyre_extensions import assert_is_instance
77+
from pyre_extensions import assert_is_instance, none_throws
7878

7979
DUMMY_RUN_METADATA_KEY = "test_run_metadata_key"
8080
DUMMY_RUN_METADATA_VALUE = "test_run_metadata_value"
@@ -360,7 +360,7 @@ def test_StatusQuoSetter(self) -> None:
360360
sq_parameters["w"] = 3.5
361361
self.experiment.status_quo = Arm(sq_parameters)
362362
self.assertEqual(self.experiment.status_quo.parameters["w"], 3.5)
363-
self.assertEqual(self.experiment.status_quo.name, "status_quo_e0")
363+
self.assertEqual(none_throws(self.experiment.status_quo).name, "status_quo_e0")
364364

365365
# Verify all None values
366366
self.experiment.status_quo = Arm({n: None for n in sq_parameters.keys()})
@@ -1512,6 +1512,107 @@ def test_to_df(self) -> None:
15121512
)
15131513
self.assertTrue(df_completed.equals(expected_completed_df))
15141514

1515+
def test_to_df_with_relativize(self) -> None:
1516+
"""Test the relativize flag in to_df method with status quo."""
1517+
# Create an experiment with status quo and completed trials
1518+
experiment = get_branin_experiment(with_status_quo=True)
1519+
1520+
# Create two completed trials
1521+
for _ in range(2):
1522+
sobol_run = get_sobol(search_space=experiment.search_space).gen(n=1)
1523+
trial = experiment.new_trial(generator_run=sobol_run)
1524+
trial.mark_running(no_runner_required=True)
1525+
trial.mark_completed()
1526+
1527+
# Fetch and add status quo data
1528+
experiment.fetch_data()
1529+
sq_data = Data(
1530+
df=pd.DataFrame(
1531+
[
1532+
{
1533+
"trial_index": i,
1534+
"arm_name": "status_quo",
1535+
"metric_name": "branin",
1536+
"metric_signature": "branin",
1537+
"mean": 10.0,
1538+
"sem": 0.1,
1539+
}
1540+
for i in range(2)
1541+
]
1542+
)
1543+
)
1544+
experiment.attach_data(sq_data)
1545+
1546+
# Test without relativization
1547+
df_no_rel = experiment.to_df(relativize=False)
1548+
1549+
# Test with relativization
1550+
df_with_rel = experiment.to_df(relativize=True)
1551+
1552+
# Basic structure should be the same
1553+
self.assertEqual(len(df_with_rel), len(df_no_rel))
1554+
self.assertEqual(set(df_with_rel.columns), set(df_no_rel.columns))
1555+
1556+
# Find metric columns and verify relativization occurred
1557+
metric_cols = [
1558+
col
1559+
for col in df_no_rel.columns
1560+
if col
1561+
not in ["trial_index", "arm_name", "trial_status", "name", "x1", "x2"]
1562+
]
1563+
1564+
if metric_cols:
1565+
metric_name = metric_cols[0]
1566+
orig_values = df_no_rel[metric_name].dropna()
1567+
rel_values = df_with_rel[metric_name].dropna()
1568+
1569+
# Values should change for non-status-quo trials
1570+
non_sq_changed = any(
1571+
abs(o - r) > 1e-10 for o, r in zip(orig_values, rel_values) if o != 10.0
1572+
)
1573+
self.assertTrue(non_sq_changed, "Relativization should change some values")
1574+
1575+
def test_to_df_relativize_without_status_quo(self) -> None:
1576+
"""Test that relativize=True has no effect when there's no status quo."""
1577+
# Create experiment without status quo
1578+
experiment = Experiment(
1579+
name="test_no_sq",
1580+
search_space=get_search_space(),
1581+
optimization_config=get_optimization_config(),
1582+
# No status_quo parameter
1583+
)
1584+
1585+
# Add some trials with data
1586+
trial1 = experiment.new_trial()
1587+
trial1.add_arm(Arm({"w": 1.0, "x": 2, "y": "foo", "z": True}))
1588+
trial1.mark_running(no_runner_required=True)
1589+
1590+
# Attach some data
1591+
data = Data(
1592+
df=pd.DataFrame(
1593+
[
1594+
{
1595+
"trial_index": 0,
1596+
"arm_name": trial1.arm.name if trial1.arm else "unknown",
1597+
"metric_name": "m1",
1598+
"metric_signature": "m1",
1599+
"mean": 10.0,
1600+
"sem": 1.0,
1601+
}
1602+
]
1603+
)
1604+
)
1605+
experiment.attach_data(data)
1606+
1607+
# Both relativize=True and relativize=False should return the same result
1608+
df_no_relativize = experiment.to_df(relativize=False)
1609+
# Since there's no status quo, relativize=True should work but have no effect
1610+
# We need to pass relativize_func even though it won't be used
1611+
df_with_relativize = experiment.to_df(relativize=True)
1612+
1613+
# DataFrames should be identical when no status quo exists
1614+
pd.testing.assert_frame_equal(df_no_relativize, df_with_relativize)
1615+
15151616

15161617
class ExperimentWithMapDataTest(TestCase):
15171618
def setUp(self) -> None:

0 commit comments

Comments
 (0)