1414
1515from adaptive .learner .learner1D import Learner1D , _get_intervals
1616from adaptive .notebook_integration import ensure_holoviews
17- from adaptive .types import Real
17+ from adaptive .types import Int , Real
18+ from adaptive .utils import assign_defaults , partial_function_from_dataframe
19+
20+ try :
21+ import pandas
22+
23+ with_pandas = True
24+
25+ except ModuleNotFoundError :
26+ with_pandas = False
1827
1928Point = Tuple [int , Real ]
2029Points = List [Point ]
@@ -127,6 +136,112 @@ def min_samples_per_point(self) -> int:
127136 return 0
128137 return min (self ._number_samples .values ())
129138
139+ def to_numpy (self , mean : bool = False ) -> np .ndarray :
140+ if mean :
141+ return super ().to_numpy ()
142+ else :
143+ return np .array (
144+ [
145+ (seed , x , * np .atleast_1d (y ))
146+ for x , seed_y in self ._data_samples .items ()
147+ for seed , y in seed_y .items ()
148+ ]
149+ )
150+
151+ def to_dataframe (
152+ self ,
153+ mean : bool = False ,
154+ with_default_function_args : bool = True ,
155+ function_prefix : str = "function." ,
156+ seed_name : str = "seed" ,
157+ x_name : str = "x" ,
158+ y_name : str = "y" ,
159+ ) -> pandas .DataFrame :
160+ """Return the data as a `pandas.DataFrame`.
161+
162+ Parameters
163+ ----------
164+ with_default_function_args : bool, optional
165+ Include the ``learner.function``'s default arguments as a
166+ column, by default True
167+ function_prefix : str, optional
168+ Prefix to the ``learner.function``'s default arguments' names,
169+ by default "function."
170+ seed_name : str, optional
171+ Name of the ``seed`` parameter, by default "seed"
172+ x_name : str, optional
173+ Name of the ``x`` parameter, by default "x"
174+ y_name : str, optional
175+ Name of the output value, by default "y"
176+
177+ Returns
178+ -------
179+ pandas.DataFrame
180+
181+ Raises
182+ ------
183+ ImportError
184+ If `pandas` is not installed.
185+ """
186+ if not with_pandas :
187+ raise ImportError ("pandas is not installed." )
188+ if mean :
189+ data = sorted (self .data .items ())
190+ columns = [x_name , y_name ]
191+ else :
192+ data = [
193+ (seed , x , y )
194+ for x , seed_y in sorted (self ._data_samples .items ())
195+ for seed , y in sorted (seed_y .items ())
196+ ]
197+ columns = [seed_name , x_name , y_name ]
198+ df = pandas .DataFrame (data , columns = columns )
199+ df .attrs ["inputs" ] = [seed_name , x_name ]
200+ df .attrs ["output" ] = y_name
201+ if with_default_function_args :
202+ assign_defaults (self .function , df , function_prefix )
203+ return df
204+
205+ def load_dataframe (
206+ self ,
207+ df : pandas .DataFrame ,
208+ with_default_function_args : bool = True ,
209+ function_prefix : str = "function." ,
210+ seed_name : str = "seed" ,
211+ x_name : str = "x" ,
212+ y_name : str = "y" ,
213+ ):
214+ """Load data from a `pandas.DataFrame`.
215+
216+ If ``with_default_function_args`` is True, then ``learner.function``'s
217+ default arguments are set (using `functools.partial`) from the values
218+ in the `pandas.DataFrame`.
219+
220+ Parameters
221+ ----------
222+ df : pandas.DataFrame
223+ The data to load.
224+ with_default_function_args : bool, optional
225+ The ``with_default_function_args`` used in ``to_dataframe()``,
226+ by default True
227+ function_prefix : str, optional
228+ The ``function_prefix`` used in ``to_dataframe``, by default "function."
229+ seed_name : str, optional
230+ The ``seed_name`` used in ``to_dataframe``, by default "seed"
231+ x_name : str, optional
232+ The ``x_name`` used in ``to_dataframe``, by default "x"
233+ y_name : str, optional
234+ The ``y_name`` used in ``to_dataframe``, by default "y"
235+ """
236+ # Were using zip instead of df[[seed_name, x_name]].values because that will
237+ # make the seeds into floats
238+ seed_x = list (zip (df [seed_name ].values .tolist (), df [x_name ].values .tolist ()))
239+ self .tell_many (seed_x , df [y_name ].values )
240+ if with_default_function_args :
241+ self .function = partial_function_from_dataframe (
242+ self .function , df , function_prefix
243+ )
244+
130245 def ask (self , n : int , tell_pending : bool = True ) -> tuple [Points , list [float ]]:
131246 """Return 'n' points that are expected to maximally reduce the loss."""
132247 # If some point is undersampled, resample it
@@ -362,7 +477,9 @@ def _calc_error_in_mean(self, ys: Iterable[Real], y_avg: Real, n: int) -> float:
362477 t_student = scipy .stats .t .ppf (1 - self .alpha , df = n - 1 )
363478 return t_student * (variance_in_mean / n ) ** 0.5
364479
365- def tell_many (self , xs : Points , ys : Sequence [Real ]) -> None :
480+ def tell_many (
481+ self , xs : Points | np .ndarray , ys : Sequence [Real ] | np .ndarray
482+ ) -> None :
366483 # Check that all x are within the bounds
367484 # TODO: remove this requirement, all other learners add the data
368485 # but ignore it going forward.
@@ -373,7 +490,7 @@ def tell_many(self, xs: Points, ys: Sequence[Real]) -> None:
373490 )
374491
375492 # Create a mapping of points to a list of samples
376- mapping : DefaultDict [Real , DefaultDict [int , Real ]] = defaultdict (
493+ mapping : DefaultDict [Real , DefaultDict [Int , Real ]] = defaultdict (
377494 lambda : defaultdict (dict )
378495 )
379496 for (seed , x ), y in zip (xs , ys ):
0 commit comments