22
33# copyright: hyperactive developers, MIT License (see LICENSE file)
44
5+ from __future__ import annotations
6+
7+ import time
8+
59import numpy as np
610from skbase .base import BaseObject
711
12+ from hyperactive .base ._history import SearchHistory
13+
814
915class BaseExperiment (BaseObject ):
1016 """Base class for experiment."""
@@ -21,6 +27,7 @@ class BaseExperiment(BaseObject):
2127
2228 def __init__ (self ):
2329 super ().__init__ ()
30+ self ._history = SearchHistory ()
2431
2532 def __call__ (self , params ):
2633 """Score parameters. Same as score call, returns only a first element."""
@@ -77,8 +84,20 @@ def evaluate(self, params):
7784 f"Parameters passed to { type (self )} .evaluate do not match: "
7885 f"expected { paramnames } , got { list (params .keys ())} ."
7986 )
87+
88+ start_time = time .perf_counter ()
8089 res , metadata = self ._evaluate (params )
90+ eval_time = time .perf_counter () - start_time
91+
8192 res = np .float64 (res )
93+
94+ self ._history .record (
95+ params = params ,
96+ score = res ,
97+ metadata = metadata ,
98+ eval_time = eval_time ,
99+ )
100+
82101 return res , metadata
83102
84103 def _evaluate (self , params ):
@@ -141,3 +160,42 @@ def score(self, params):
141160 metadata = eval_res [1 ]
142161
143162 return sign * value , metadata
163+
164+ @property
165+ def data (self ) -> SearchHistory :
166+ """Access the collected data from optimization runs.
167+
168+ Tracks all evaluations during optimization. Data accumulates across
169+ multiple optimization runs on the same experiment instance.
170+
171+ Returns
172+ -------
173+ SearchHistory
174+ The data object with the following attributes and methods:
175+
176+ Attributes:
177+ - ``history``: list[dict] - all recorded evaluations
178+ - ``n_trials``: int - total number of trials
179+ - ``n_runs``: int - number of optimization runs
180+ - ``best_trial``: dict | None - trial with highest score
181+ - ``best_score``: float | None - highest score
182+ - ``best_params``: dict | None - parameters of best trial
183+
184+ Methods:
185+ - ``get_run(run_id)``: get trials from specific run
186+ - ``clear()``: reset all data
187+ - ``new_run()``: signal start of new run (call before each run)
188+
189+ Examples
190+ --------
191+ >>> experiment.data.history # all evaluations as list of dicts
192+ >>> experiment.data.best_score # highest score
193+ >>> experiment.data.get_run(0) # evaluations from first run
194+ >>> experiment.data.clear() # reset data
195+
196+ To convert to a pandas DataFrame::
197+
198+ import pandas as pd
199+ df = pd.DataFrame(experiment.data.history)
200+ """
201+ return self ._history
0 commit comments