Skip to content

Commit ffd8c04

Browse files
committed
Add getting learnerto pandas; add learner.as_dataframe
1 parent 2c8d2ad commit ffd8c04

File tree

6 files changed

+157
-4
lines changed

6 files changed

+157
-4
lines changed

adaptive/learner/average_learner.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@
99
from adaptive.learner.base_learner import BaseLearner
1010
from adaptive.notebook_integration import ensure_holoviews
1111
from adaptive.types import Float, Real
12-
from adaptive.utils import cache_latest
12+
from adaptive.utils import cache_latest, default_parameters
13+
14+
try:
15+
import pandas
16+
17+
with_pandas = True
18+
19+
except ModuleNotFoundError:
20+
with_pandas = False
1321

1422

1523
class AverageLearner(BaseLearner):
@@ -70,6 +78,21 @@ def to_numpy(self):
7078
"""Data as NumPy array of size (npoints, 2) with seeds and values."""
7179
return np.array(sorted(self.data.items()))
7280

81+
def to_dataframe(
82+
self,
83+
with_default_function_args: bool = True,
84+
function_prefix: str = "function.",
85+
seed_name: str = "seed",
86+
y_name: str = "y",
87+
) -> pandas.DataFrame:
88+
if not with_pandas:
89+
raise ImportError("pandas is not installed.")
90+
df = pandas.DataFrame(sorted(self.data.items()), columns=[seed_name, y_name])
91+
if with_default_function_args:
92+
defaults = default_parameters(self.function, function_prefix)
93+
df = df.assign(**defaults)
94+
return df
95+
7396
def ask(self, n: int, tell_pending: bool = True) -> tuple[list[int], list[Float]]:
7497
points = list(range(self.n_requested, self.n_requested + n))
7598

adaptive/learner/average_learner1D.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
from adaptive.learner.learner1D import Learner1D, _get_intervals
1616
from adaptive.notebook_integration import ensure_holoviews
1717
from adaptive.types import Real
18+
from adaptive.utils import default_parameters
19+
20+
try:
21+
import pandas
22+
23+
with_pandas = True
24+
25+
except ModuleNotFoundError:
26+
with_pandas = False
1827

1928
Point = Tuple[int, Real]
2029
Points = List[Point]
@@ -127,6 +136,45 @@ 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 = True) -> 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 = True,
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+
if not with_pandas:
161+
raise ImportError("pandas is not installed.")
162+
if mean:
163+
data = sorted(self.data.items())
164+
columns = [x_name, y_name]
165+
else:
166+
data = [
167+
(seed, x, y)
168+
for x, seed_y in sorted(self._data_samples.items())
169+
for seed, y in sorted(seed_y.items())
170+
]
171+
columns = [seed_name, x_name, y_name]
172+
df = pandas.DataFrame(data, columns=columns)
173+
if with_default_function_args:
174+
defaults = default_parameters(self.function, function_prefix)
175+
df = df.assign(**defaults)
176+
return df
177+
130178
def ask(self, n: int, tell_pending: bool = True) -> tuple[Points, list[float]]:
131179
"""Return 'n' points that are expected to maximally reduce the loss."""
132180
# If some point is undersampled, resample it

adaptive/learner/integrator_learner.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,15 @@
1313
from adaptive.learner import integrator_coeffs as coeff
1414
from adaptive.learner.base_learner import BaseLearner
1515
from adaptive.notebook_integration import ensure_holoviews
16-
from adaptive.utils import cache_latest, restore
16+
from adaptive.utils import cache_latest, default_parameters, restore
17+
18+
try:
19+
import pandas
20+
21+
with_pandas = True
22+
23+
except ModuleNotFoundError:
24+
with_pandas = False
1725

1826

1927
def _downdate(c, nans, depth):
@@ -550,6 +558,21 @@ def to_numpy(self):
550558
"""Data as NumPy array of size (npoints, 2)."""
551559
return np.array(sorted(self.data.items()))
552560

561+
def to_dataframe(
562+
self,
563+
with_default_function_args: bool = True,
564+
function_prefix: str = "function.",
565+
x_name: str = "x",
566+
y_name: str = "y",
567+
) -> pandas.DataFrame:
568+
if not with_pandas:
569+
raise ImportError("pandas is not installed.")
570+
df = pandas.DataFrame(sorted(self.data.items()), columns=[x_name, y_name])
571+
if with_default_function_args:
572+
defaults = default_parameters(self.function, function_prefix)
573+
df = df.assign(**defaults)
574+
return df
575+
553576
def _get_data(self):
554577
# Change the defaultdict of SortedSets to a normal dict of sets.
555578
x_mapping = {k: set(v) for k, v in self.x_mapping.items()}

adaptive/learner/learner1D.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@
1616
from adaptive.learner.triangulation import simplex_volume_in_embedding
1717
from adaptive.notebook_integration import ensure_holoviews
1818
from adaptive.types import Float, Int, Real
19-
from adaptive.utils import cache_latest
19+
from adaptive.utils import cache_latest, default_parameters
20+
21+
try:
22+
import pandas
23+
24+
with_pandas = True
25+
26+
except ModuleNotFoundError:
27+
with_pandas = False
2028

2129
# -- types --
2230

@@ -321,6 +329,21 @@ def to_numpy(self):
321329
and ``(npoints, 1+vdim)`` if ``learner.function`` returns a vector of length ``vdim``."""
322330
return np.array([(x, *np.atleast_1d(y)) for x, y in sorted(self.data.items())])
323331

332+
def to_dataframe(
333+
self,
334+
with_default_function_args: bool = True,
335+
function_prefix: str = "function.",
336+
x_name: str = "x",
337+
y_name: str = "y",
338+
) -> pandas.DataFrame:
339+
if not with_pandas:
340+
raise ImportError("pandas is not installed.")
341+
df = pandas.DataFrame(sorted(self.data.items()), columns=[x_name, y_name])
342+
if with_default_function_args:
343+
defaults = default_parameters(self.function, function_prefix)
344+
df = df.assign(**defaults)
345+
return df
346+
324347
@property
325348
def npoints(self) -> int:
326349
"""Number of evaluated points."""

adaptive/learner/learner2D.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,15 @@
1111
from adaptive.learner.base_learner import BaseLearner
1212
from adaptive.learner.triangulation import simplex_volume_in_embedding
1313
from adaptive.notebook_integration import ensure_holoviews
14-
from adaptive.utils import cache_latest
14+
from adaptive.utils import cache_latest, default_parameters
15+
16+
try:
17+
import pandas
18+
19+
with_pandas = True
20+
21+
except ModuleNotFoundError:
22+
with_pandas = False
1523

1624
# Learner2D and helper functions.
1725

@@ -385,6 +393,23 @@ def to_numpy(self):
385393
[(x, y, *np.atleast_1d(z)) for (x, y), z in sorted(self.data.items())]
386394
)
387395

396+
def to_dataframe(
397+
self,
398+
with_default_function_args: bool = True,
399+
function_prefix: str = "function.",
400+
x_name: str = "x",
401+
y_name: str = "y",
402+
z_name: str = "z",
403+
) -> pandas.DataFrame:
404+
if not with_pandas:
405+
raise ImportError("pandas is not installed.")
406+
data = sorted((x, y, z) for (x, y), z in self.data.items())
407+
df = pandas.DataFrame(data, columns=[x_name, y_name, z_name])
408+
if with_default_function_args:
409+
defaults = default_parameters(self.function, function_prefix)
410+
df = df.assign(**defaults)
411+
return df
412+
388413
def _scale(self, points):
389414
points = np.asarray(points, dtype=float)
390415
return (points - self.xy_mean) / self.xy_scale

adaptive/utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import abc
22
import functools
33
import gzip
4+
import inspect
45
import os
56
import pickle
67
from contextlib import contextmanager
@@ -98,3 +99,13 @@ def __call__(self, *args, **kwargs):
9899
msg = f"The attribute '{name}' should be of type {type_}, not {type(x)}."
99100
raise TypeError(msg)
100101
return obj
102+
103+
104+
def default_parameters(function, function_prefix="", start_index=1):
105+
sig = inspect.signature(function)
106+
defaults = {
107+
f"{function_prefix}{k}": v.default
108+
for i, (k, v) in enumerate(sig.parameters.items())
109+
if v.default != inspect._empty and i >= start_index
110+
}
111+
return defaults

0 commit comments

Comments
 (0)