| 1549 | return stats |
| 1550 | |
| 1551 | def _optimize_sambo() -> Union[pd.Series, |
| 1552 | Tuple[pd.Series, pd.Series], |
| 1553 | Tuple[pd.Series, pd.Series, dict]]: |
| 1554 | try: |
| 1555 | import sambo |
| 1556 | except ImportError: |
| 1557 | raise ImportError("Need package 'sambo' for method='sambo'. pip install sambo") from None |
| 1558 | |
| 1559 | nonlocal max_tries |
| 1560 | max_tries = (200 if max_tries is None else |
| 1561 | max(1, int(max_tries * _grid_size())) if 0 < max_tries <= 1 else |
| 1562 | max_tries) |
| 1563 | |
| 1564 | dimensions = [] |
| 1565 | for key, values in kwargs.items(): |
| 1566 | values = np.asarray(values) |
| 1567 | if values.dtype.kind in 'mM': # timedelta, datetime64 |
| 1568 | # these dtypes are unsupported in SAMBO, so convert to raw int |
| 1569 | # TODO: save dtype and convert back later |
| 1570 | values = values.astype(np.int64) |
| 1571 | |
| 1572 | if values.dtype.kind in 'iumM': |
| 1573 | dimensions.append((values.min(), values.max() + 1)) |
| 1574 | elif values.dtype.kind == 'f': |
| 1575 | dimensions.append((values.min(), values.max())) |
| 1576 | else: |
| 1577 | dimensions.append(values.tolist()) |
| 1578 | |
| 1579 | # Avoid recomputing re-evaluations |
| 1580 | @lru_cache() |
| 1581 | def memoized_run(tup): |
| 1582 | nonlocal maximize, self |
| 1583 | stats = self.run(**dict(tup)) |
| 1584 | return -maximize(stats) |
| 1585 | |
| 1586 | progress = iter(_tqdm(repeat(None), total=max_tries, leave=False, |
| 1587 | desc=self.optimize.__qualname__, mininterval=2)) |
| 1588 | _names = tuple(kwargs.keys()) |
| 1589 | |
| 1590 | def objective_function(x): |
| 1591 | nonlocal progress, memoized_run, constraint, _names |
| 1592 | next(progress) |
| 1593 | value = memoized_run(tuple(zip(_names, x))) |
| 1594 | return 0 if np.isnan(value) else value |
| 1595 | |
| 1596 | def cons(x): |
| 1597 | nonlocal constraint, _names |
| 1598 | return constraint(AttrDict(zip(_names, x))) |
| 1599 | |
| 1600 | res = sambo.minimize( |
| 1601 | fun=objective_function, |
| 1602 | bounds=dimensions, |
| 1603 | constraints=cons, |
| 1604 | max_iter=max_tries, |
| 1605 | method='sceua', |
| 1606 | rng=random_state) |
| 1607 | |
| 1608 | stats = self.run(**dict(zip(kwargs.keys(), res.x))) |