diff --git a/.gitignore b/.gitignore index 9b039ac..1dcaca0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ dist/ *.egg-info/ .idea/ .cache/ +docs/_build # mac OS users .DS_Store diff --git a/build_tools/circle/deploy.sh b/build_tools/circle/deploy.sh index ba6dc24..630b86b 100644 --- a/build_tools/circle/deploy.sh +++ b/build_tools/circle/deploy.sh @@ -14,7 +14,7 @@ git clone -b master "git@github.com:scikit-optimize/scikit-optimize.github.io" d cd deploy git rm -r notebooks/* cd .. -cp -r ${HOME}/doc/skopt/* deploy +cp -r ${HOME}/doc/* deploy # Move into deployment directory cd deploy diff --git a/build_tools/circle/execute.sh b/build_tools/circle/execute.sh index 742d225..903b22c 100644 --- a/build_tools/circle/execute.sh +++ b/build_tools/circle/execute.sh @@ -6,18 +6,8 @@ python --version python -c "import numpy; print('numpy %s' % numpy.__version__)" python -c "import scipy; print('scipy %s' % scipy.__version__)" -# Generating documentation -for nb in examples/*ipynb; do - jupyter nbconvert --ExecutePreprocessor.timeout=3600 --execute "$nb" --to markdown |& tee nb_to_md.txt - traceback=$(grep "Traceback (most recent call last):" nb_to_md.txt) - if [[ $traceback ]]; then - exit 1 - fi -done - -cd ~ -mkdir -p ${HOME}/doc/skopt/notebooks -cp ${SKOPT_HOME}/examples/*md ${HOME}/doc/skopt/notebooks -find ${SKOPT_HOME}/examples -name \*_files -exec cp -r {} ${HOME}/doc/skopt/notebooks \; -python ${SKOPT_HOME}/build_tools/circle/make_doc.py --overwrite --html --html-dir ./doc --template-dir ${SKOPT_HOME}/build_tools/circle/templates --notebook-dir ./doc/skopt/notebooks skopt -cp -r ./doc ${CIRCLE_ARTIFACTS} +cd ${SKOPT_HOME}/docs +make html +cp -r ./_build/html/* ${CIRCLE_ARTIFACTS} +mkdir ~/doc/ +cp -r ./_build/html/* ~/doc/ diff --git a/build_tools/circle/install.sh b/build_tools/circle/install.sh index b4d4a17..596866b 100644 --- a/build_tools/circle/install.sh +++ b/build_tools/circle/install.sh @@ -37,7 +37,7 @@ pip install -e. export SKOPT_HOME=$(pwd) conda install --yes jupyter -pip install pdoc==0.3.2 pygments +pip install sphinx numpydoc nbsphinx # importing matplotlib once builds the font caches. This avoids # having warnings in our example notebooks diff --git a/build_tools/circle/make_doc.py b/build_tools/circle/make_doc.py deleted file mode 100644 index 598a45b..0000000 --- a/build_tools/circle/make_doc.py +++ /dev/null @@ -1,349 +0,0 @@ -from __future__ import absolute_import, division, print_function -import argparse - -import codecs -import datetime -import imp -import os -import os.path as path -import subprocess -import sys -import tempfile -import glob - -import pdoc - -# `xrange` is `range` with Python3. -try: - xrange = xrange -except NameError: - xrange = range - -version_suffix = '%d.%d' % (sys.version_info[0], sys.version_info[1]) -default_http_dir = path.join(tempfile.gettempdir(), 'pdoc-%s' % version_suffix) - -parser = argparse.ArgumentParser( - description='Automatically generate API docs for Python modules.', - formatter_class=argparse.ArgumentDefaultsHelpFormatter) -aa = parser.add_argument -aa('module_name', type=str, nargs='?', - help='The Python module name. This may be an import path resolvable in ' - 'the current environment, or a file path to a Python module or ' - 'package.') -aa('ident_name', type=str, nargs='?', - help='When specified, only identifiers containing the name given ' - 'will be shown in the output. Search is case sensitive. ' - 'Has no effect when --http is set.') -aa('--version', action='store_true', - help='Print the version of pdoc and exit.') -aa('--html', action='store_true', - help='When set, the output will be HTML formatted.') -aa('--html-dir', type=str, default='.', - help='The directory to output HTML files to. This option is ignored when ' - 'outputting documentation as plain text.') -aa('--html-no-source', action='store_true', - help='When set, source code will not be viewable in the generated HTML. ' - 'This can speed up the time required to document large modules.') -aa('--overwrite', action='store_true', - help='Overwrites any existing HTML files instead of producing an error.') -aa('--all-submodules', action='store_true', - help='When set, every submodule will be included, regardless of whether ' - '__all__ is set and contains the submodule.') -aa('--external-links', action='store_true', - help='When set, identifiers to external modules are turned into links. ' - 'This is automatically set when using --http.') -aa('--template-dir', type=str, default=None, - help='Specify a directory containing Mako templates. ' - 'Alternatively, put your templates in $XDG_CONFIG_HOME/pdoc and ' - 'pdoc will automatically find them.') -aa('--notebook-dir', type=str, default=None, - help='Specify a directory containing Notebooks. ') -aa('--link-prefix', type=str, default='', - help='A prefix to use for every link in the generated documentation. ' - 'No link prefix results in all links being relative. ' - 'Has no effect when combined with --http.') -aa('--only-pypath', action='store_true', - help='When set, only modules in your PYTHONPATH will be documented.') -aa('--http', action='store_true', - help='When set, pdoc will run as an HTTP server providing documentation ' - 'of all installed modules. Only modules found in PYTHONPATH will be ' - 'listed.') -aa('--http-dir', type=str, default=default_http_dir, - help='The directory to cache HTML documentation when running as an HTTP ' - 'server.') -aa('--http-host', type=str, default='localhost', - help='The host on which to run the HTTP server.') -aa('--http-port', type=int, default=8080, - help='The port on which to run the HTTP server.') -aa('--http-html', action='store_true', - help='Internal use only. Do not set.') -args = parser.parse_args() - - -def quick_desc(imp, name, ispkg): - if not hasattr(imp, 'path'): - # See issue #7. - return '' - - if ispkg: - fp = path.join(imp.path, name, '__init__.py') - else: - fp = path.join(imp.path, '%s.py' % name) - if os.path.isfile(fp): - with codecs.open(fp, 'r', 'utf-8') as f: - quotes = None - doco = [] - for i, line in enumerate(f): - if i == 0: - if len(line) >= 3 and line[0:3] in ("'''", '"""'): - quotes = line[0:3] - line = line[3:] - else: - break - line = line.rstrip() - if line.endswith(quotes): - doco.append(line[0:-3]) - break - else: - doco.append(line) - desc = '\n'.join(doco) - if len(desc) > 200: - desc = desc[0:200] + '...' - return desc - return '' - - -def _eprint(*args, **kwargs): - kwargs['file'] = sys.stderr - print(*args, **kwargs) - - -def last_modified(fp): - try: - return datetime.datetime.fromtimestamp(os.stat(fp).st_mtime) - except: - return datetime.datetime.min - - -def module_file(m): - mbase = path.join(args.html_dir, *m.name.split('.')) - if m.is_package(): - return path.join(mbase, pdoc.html_package_name) - else: - return '%s%s' % (mbase, pdoc.html_module_suffix) - - -def quit_if_exists(m): - def check_file(f): - if os.access(f, os.R_OK): - _eprint('%s already exists. Delete it or run with --overwrite' % f) - sys.exit(1) - - if args.overwrite: - return - f = module_file(m) - check_file(f) - - # If this is a package, make sure the package directory doesn't exist - # either. - if m.is_package(): - check_file(path.dirname(f)) - - -def html_out(m, html=True, all_notebooks=[]): - f = module_file(m) - if not html: - f = module_file(m).replace(".html", ".md") - dirpath = path.dirname(f) - if not os.access(dirpath, os.R_OK): - os.makedirs(dirpath) - try: - with codecs.open(f, 'w+', 'utf-8') as w: - if not html: - out = m.text() - else: - out = m.html(external_links=args.external_links, - link_prefix=args.link_prefix, - http_server=args.http_html, - source=not args.html_no_source, - notebook=None, - all_notebooks=all_notebooks) - print(out, file=w) - except Exception: - try: - os.unlink(f) - except: - pass - raise - for submodule in m.submodules(): - html_out(submodule, html, all_notebooks=all_notebooks) - - -def html_out_notebook(m, notebook, all_notebooks=[]): - f = module_file(m) - f = f.rsplit(sep="/", maxsplit=1)[0] + "/notebooks/" + notebook.rsplit(sep="/", maxsplit=1)[-1][:-3] + ".html" - - dirpath = path.dirname(f) - if not os.access(dirpath, os.R_OK): - os.makedirs(dirpath) - try: - with codecs.open(f, 'w+', 'utf-8') as w: - out = m.html(external_links=args.external_links, - link_prefix=args.link_prefix, - http_server=args.http_html, - source=not args.html_no_source, - notebook=notebook, - all_notebooks=all_notebooks) - print(out, file=w) - except Exception: - try: - os.unlink(f) - except: - pass - raise - - - -def process_html_out(impath): - # This unfortunate kludge is the only reasonable way I could think of - # to support reloading of modules. It's just too difficult to get - # modules to reload in the same process. - - cmd = [sys.executable, - path.realpath(__file__), - '--html', - '--html-dir', args.html_dir, - '--http-html', - '--overwrite', - '--link-prefix', args.link_prefix] - if args.external_links: - cmd.append('--external-links') - if args.all_submodules: - cmd.append('--all-submodules') - if args.only_pypath: - cmd.append('--only-pypath') - if args.html_no_source: - cmd.append('--html-no-source') - if args.template_dir: - cmd.append('--template-dir') - cmd.append(args.template_dir) - cmd.append(impath) - - # Can we make a good faith attempt to support 2.6? - # YES WE CAN! - p = subprocess.Popen(cmd, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - out = p.communicate()[0].strip().decode('utf-8') - if p.returncode > 0: - err = subprocess.CalledProcessError(p.returncode, cmd) - err.output = out - raise err - if len(out) > 0: - print(out) - - -if __name__ == '__main__': - if args.version: - print(pdoc.__version__) - sys.exit(0) - - # We close stdin because some modules, upon import, are not very polite - # and block on stdin. - try: - sys.stdin.close() - except: - pass - - if not args.http and args.module_name is None: - _eprint('No module name specified.') - sys.exit(1) - if args.template_dir is not None: - pdoc.tpl_lookup.directories.insert(0, args.template_dir) - - # If PYTHONPATH is set, let it override everything if we want it to. - pypath = os.getenv('PYTHONPATH') - if args.only_pypath and pypath is not None and len(pypath) > 0: - pdoc.import_path = pypath.split(path.pathsep) - - docfilter = None - if args.ident_name and len(args.ident_name.strip()) > 0: - search = args.ident_name.strip() - - def docfilter(o): - rname = o.refname - if rname.find(search) > -1 or search.find(o.name) > -1: - return True - if isinstance(o, pdoc.Class): - return search in o.doc or search in o.doc_init - return False - - # Try to do a real import first. I think it's better to prefer - # import paths over files. If a file is really necessary, then - # specify the absolute path, which is guaranteed not to be a - # Python import path. - try: - module = pdoc.import_module(args.module_name) - except Exception as e: - module = None - - # Get the module that we're documenting. Accommodate for import paths, - # files and directories. - if module is None: - print(module) - isdir = path.isdir(args.module_name) - isfile = path.isfile(args.module_name) - if isdir or isfile: - fp = path.realpath(args.module_name) - module_name = path.basename(fp) - if isdir: - fp = path.join(fp, '__init__.py') - else: - module_name, _ = path.splitext(module_name) - - # Use a special module name to avoid import conflicts. - # It is hidden from view via the `Module` class. - with open(fp) as f: - module = imp.load_source('__pdoc_file_module__', fp, f) - if isdir: - module.__path__ = [path.realpath(args.module_name)] - module.__pdoc_module_name = module_name - else: - module = pdoc.import_module(args.module_name) - module = pdoc.Module(module, docfilter=docfilter, - allsubmodules=args.all_submodules) - - # Plain text? - if not args.html and not args.all_submodules: - output = module.text() - try: - print(output) - except IOError as e: - # This seems to happen for long documentation. - # This is obviously a hack. What's the real cause? Dunno. - if e.errno == 32: - pass - else: - raise e - sys.exit(0) - - # Hook notebook generation - all_notebooks = [] - - if args.notebook_dir: - all_notebooks = [f for f in sorted(glob.glob("%s/*.md" % args.notebook_dir))] - - for notebook in all_notebooks: - html_out_notebook(module, notebook, all_notebooks=all_notebooks) - - # HTML output depends on whether the module being documented is a package - # or not. If not, then output is written to {MODULE_NAME}.html in - # `html-dir`. If it is a package, then a directory called {MODULE_NAME} - # is created, and output is written to {MODULE_NAME}/index.html. - # Submodules are written to {MODULE_NAME}/{MODULE_NAME}.m.html and - # subpackages are written to {MODULE_NAME}/{MODULE_NAME}/index.html. And - # so on... The same rules apply for `http_dir` when `pdoc` is run as an - # HTTP server. - if not args.http: - quit_if_exists(module) - html_out(module, args.html, all_notebooks=all_notebooks) - sys.exit(0) diff --git a/circle.yml b/circle.yml index 8b49775..6ef6812 100644 --- a/circle.yml +++ b/circle.yml @@ -8,7 +8,6 @@ test: override: - bash ./build_tools/circle/execute.sh: timeout: 3600 - - if grep -q "Traceback (most recent call last):" nb_to_md.txt; then false; else true; fi deployment: push: diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..c8aa9b2 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = scikit-optimize +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 0000000..8bbace2 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,3 @@ +.function { + padding-bottom: 30px; +} diff --git a/docs/_static/logo.png b/docs/_static/logo.png new file mode 100644 index 0000000..2c66c00 Binary files /dev/null and b/docs/_static/logo.png differ diff --git a/docs/api/acquisition.rst b/docs/api/acquisition.rst new file mode 100644 index 0000000..c2888f1 --- /dev/null +++ b/docs/api/acquisition.rst @@ -0,0 +1,23 @@ +.. _acquisition-functions: + +``skopt.acquisition``, acquisition functions +============================================ + +Overview +-------- + +.. currentmodule:: skopt.acquisition + +.. autosummary:: + + gaussian_acquisition_1D + gaussian_ei + gaussian_lcb + gaussian_pi + + +Details +------- + +.. automodule:: skopt.acquisition + :members: diff --git a/docs/api/bayessearchcv.rst b/docs/api/bayessearchcv.rst new file mode 100644 index 0000000..b5d42af --- /dev/null +++ b/docs/api/bayessearchcv.rst @@ -0,0 +1,10 @@ +.. _bayessearchcv: + +``skopt.BayesSearchCV``, GridSearchCV compatible estimator +========================================================== + +Use ``BayesSearchCV`` as a replacement for scikit-learn's GridSearchCV. + +.. currentmodule:: skopt.BayesSearchCV +.. autoclass:: skopt.BayesSearchCV + :members: diff --git a/docs/api/callbacks.rst b/docs/api/callbacks.rst new file mode 100644 index 0000000..f92b41e --- /dev/null +++ b/docs/api/callbacks.rst @@ -0,0 +1,23 @@ +.. _callback-functions: + +``skopt.callbacks``, callback functions +============================================ + +Overview +-------- + +.. currentmodule:: skopt.callbacks + +.. autosummary:: + + DeltaXStopper + DeltaYStopper + TimerCallback + VerboseCallback + + +Details +------- + +.. automodule:: skopt.callbacks + :members: diff --git a/docs/api/index.rst b/docs/api/index.rst new file mode 100644 index 0000000..eb3e4fa --- /dev/null +++ b/docs/api/index.rst @@ -0,0 +1,17 @@ +============= +API Reference +============= + +Details on the complete API of scikit-optimize. + +.. toctree:: + :maxdepth: 1 + + minimize_functions + optimizer + bayessearchcv + acquisition + callbacks + plots + space + utils diff --git a/docs/api/minimize_functions.rst b/docs/api/minimize_functions.rst new file mode 100644 index 0000000..5cb2464 --- /dev/null +++ b/docs/api/minimize_functions.rst @@ -0,0 +1,29 @@ +.. _minimize-functions: + +``skopt``'s top level minimization functions +============================================ + +These are easy to get started with. They mirror the ``scipy.optimize`` +API and provide a high level interface to various pre-configured +optimizers. + +Overview +-------- + +.. currentmodule:: skopt + +.. autosummary:: + + dummy_minimize + forest_minimize + gbrt_minimize + gp_minimize + + +Details +------- + +.. autofunction:: skopt.dummy_minimize +.. autofunction:: skopt.forest_minimize +.. autofunction:: skopt.gbrt_minimize +.. autofunction:: skopt.gp_minimize diff --git a/docs/api/optimizer.rst b/docs/api/optimizer.rst new file mode 100644 index 0000000..eefe0a0 --- /dev/null +++ b/docs/api/optimizer.rst @@ -0,0 +1,12 @@ +.. _optimizer: + +``skopt.Optimizer``, ask-and-tell interface +=========================================== + +Use the ``Optimizer`` class directly when you want to control the optimization +loop. We refer to this as the ask-and-tell interface. This class is used +internally to implement the :ref:`minimize-functions`. + +.. currentmodule:: skopt.Optimizer +.. autoclass:: skopt.Optimizer + :members: diff --git a/docs/api/plots.rst b/docs/api/plots.rst new file mode 100644 index 0000000..8bf4c3a --- /dev/null +++ b/docs/api/plots.rst @@ -0,0 +1,23 @@ +.. _plotting-functions: + +``skopt.plots``, plotting tools +=============================== + +Overview +-------- + +.. currentmodule:: skopt.plots + +.. autosummary:: + + partial_dependence + plot_convergence + plot_evaluations + plot_objective + + +Details +------- + +.. automodule:: skopt.plots + :members: diff --git a/docs/api/space.rst b/docs/api/space.rst new file mode 100644 index 0000000..4517329 --- /dev/null +++ b/docs/api/space.rst @@ -0,0 +1,29 @@ +.. _optimization-space: + +``skopt.space``, define the optimization space +============================================== + +Overview +-------- + +.. currentmodule:: skopt.space + +.. autosummary:: + + check_dimension + Dimension + Categorical + Integer + Real + Space + + +Details +------- + +.. autofunction:: skopt.space.check_dimension +.. autoclass:: skopt.space.Space +.. autoclass:: skopt.space.Categorical +.. autoclass:: skopt.space.Integer +.. autoclass:: skopt.space.Real +.. autoclass:: skopt.space.Dimension diff --git a/docs/api/utils.rst b/docs/api/utils.rst new file mode 100644 index 0000000..1bbdf71 --- /dev/null +++ b/docs/api/utils.rst @@ -0,0 +1,30 @@ +.. _utility-functions: + +``skopt.utils``, utility functions +================================== + +Overview +-------- + +This is a list of public utility functions. Other functions in this module +are meant for internal use. + +.. currentmodule:: skopt + +.. autosummary:: + + utils.check_x_in_space + utils.cook_estimator + utils.dimensions_aslist + utils.expected_minimum + utils.dump + utils.load + utils.point_asdict + utils.point_aslist + + +Details +------- + +.. automodule:: skopt.utils + :members: diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..a437f52 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# scikit-optimize documentation build configuration file, created by +# sphinx-quickstart on Tue Jul 11 16:28:14 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', + 'sphinx.ext.githubpages', + 'numpydoc', + 'nbsphinx', + ] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'scikit-optimize' +copyright = '2017, The scikit-optimize contributors' +author = 'The scikit-optimize contributors' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.4' +# The full version, including alpha/beta/rc tags. +release = '0.4-dev' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +html_sidebars = { + '**': [ + 'about.html', + 'navigation.html', + 'relations.html', + 'searchbox.html', + 'donate.html', + ] +} + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +html_theme_options = { + 'logo': 'logo.png', + 'github_user': 'scikit-optimize', + 'github_repo': 'scikit-optimize', + 'fixed_sidebar': False, + 'github_button': False, + 'github_banner': True, + } + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'scikit-optimizedoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'scikit-optimize.tex', 'scikit-optimize Documentation', + 'The scikit-optimize contributors', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'scikit-optimize', 'scikit-optimize Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'scikit-optimize', 'scikit-optimize Documentation', + author, 'scikit-optimize', 'One line description of project.', + 'Miscellaneous'), +] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..a7588d1 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,28 @@ +=========================================== +Welcome to scikit-optimize's documentation! +=========================================== + +Scikit-Optimize, or ``skopt``, is a simple and efficient library to +minimize (very) expensive and noisy black-box functions. It implements +several methods for sequential model-based optimization. ``skopt`` aims +to be accessible and easy to use in many contexts. + +The library is built on top of NumPy, SciPy and Scikit-Learn. + +We do not perform gradient-based optimization. For gradient-based +optimization algorithms look at +``scipy.optimize`` +`here `_. + +.. figure:: https://rawgit.com/scikit-optimize/scikit-optimize/master/media/bo-objective.png + :alt: Approximated objective + +Approximated objective function after 50 iterations of ``gp_minimize``. +Plot made using ``skopt.plots.plot_objective``. + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + intro + api/index diff --git a/docs/intro.rst b/docs/intro.rst new file mode 100644 index 0000000..1f04159 --- /dev/null +++ b/docs/intro.rst @@ -0,0 +1,21 @@ +========== +Quickstart +========== + +Find the minimum of the noisy function ``f(x)`` over the range ``-2 < x < 2`` +with ``skopt``:: + + import numpy as np + from skopt import gp_minimize + + def f(x): + return (np.sin(5 * x[0]) * (1 - np.tanh(x[0] ** 2)) * + np.random.randn() * 0.1) + + res = gp_minimize(f, [(-2.0, 2.0)]) + +For more read our `introduction to bayesian optimization`_ and the other +`examples`_. + +.. _introduction to bayesian optimization: https://scikit-optimize.github.io/notebooks/bayesian-optimization.html +.. _examples: https://github.com/scikit-optimize/scikit-optimize/tree/master/examples diff --git a/skopt/__init__.py b/skopt/__init__.py index 621faee..b7ede4f 100644 --- a/skopt/__init__.py +++ b/skopt/__init__.py @@ -1,49 +1,7 @@ """ -Scikit-Optimize, or `skopt`, is a simple and efficient library to +Scikit-Optimize, or ``skopt``, is a simple and efficient library to minimize (very) expensive and noisy black-box functions. It implements -several methods for sequential model-based optimization. `skopt` is reusable -in many contexts and accessible. - -[![Build Status](https://travis-ci.org/scikit-optimize/scikit-optimize.svg?branch=master)](https://travis-ci.org/scikit-optimize/scikit-optimize) - -## Install - -``` -pip install scikit-optimize -``` - -## Getting started - -Find the minimum of the noisy function `f(x)` over the range `-2 < x < 2` -with `skopt`: - -```python -import numpy as np -from skopt import gp_minimize - -def f(x): - return (np.sin(5 * x[0]) * (1 - np.tanh(x[0] ** 2)) * - np.random.randn() * 0.1) - -res = gp_minimize(f, [(-2.0, 2.0)]) -``` - -For more read our [introduction to bayesian optimization](https://scikit-optimize.github.io/notebooks/bayesian-optimization.html) -and the other [examples](https://github.com/scikit-optimize/scikit-optimize/tree/master/examples). - - -## Development - -The library is still experimental and under heavy development. - -The development version can be installed through: - - git clone https://github.com/scikit-optimize/scikit-optimize.git - cd scikit-optimize - pip install -r requirements.txt - python setup.py develop - -Run the tests by executing `pytest` in the top level directory. +several methods for sequential model-based optimization. """ from . import acquisition diff --git a/skopt/acquisition.py b/skopt/acquisition.py index 8693fea..5fb5bd4 100644 --- a/skopt/acquisition.py +++ b/skopt/acquisition.py @@ -9,7 +9,7 @@ def gaussian_acquisition_1D(X, model, y_opt=None, acq_func="LCB", """ A wrapper around the acquisition function that is called by fmin_l_bfgs_b. - This is because lbfgs allows only 1-D input. + This is because lbfgs accepts only 1-D input. """ return _gaussian_acquisition(np.expand_dims(X, axis=0), model, y_opt, acq_func=acq_func, @@ -96,16 +96,16 @@ def gaussian_lcb(X, model, kappa=1.96, return_grad=False): Parameters ---------- - * `X` [array-like, shape=(n_samples, n_features)]: + X : array-like, shape=[n_samples, n_features] Values where the acquisition function should be computed. - * `model` [sklearn estimator that implements predict with ``return_std``]: + model : sklearn estimator that implements predict with ``return_std`` The fit estimator that approximates the function through the method ``predict``. It should have a ``return_std`` parameter that returns the standard deviation. - * `kappa`: [float, default 1.96 or 'inf']: + kappa : float or 'inf', optional (default=1.96) Controls how much of the variance in the predicted values should be taken into account. If set to be very high, then we are favouring exploration over exploitation and vice versa. @@ -113,17 +113,17 @@ def gaussian_lcb(X, model, kappa=1.96, return_grad=False): which is useful in a pure exploration setting. Useless if ``method`` is set to "LCB". - * `return_grad`: [boolean, optional]: + return_grad : boolean, optional (default=False) Whether or not to return the grad. Implemented only for the case where ``X`` is a single sample. Returns ------- - * `values`: [array-like, shape=(X.shape[0],)]: - Acquisition function values computed at X. + values : array-like, shape=[X.shape[0]] + Acquisition function values computed at ``X``. - * `grad`: [array-like, shape=(n_samples, n_features)]: - Gradient at X. + grad : array-like, shape=[n_samples, n_features] + Gradient at ``X``. """ # Compute posterior. with warnings.catch_warnings(): @@ -149,12 +149,12 @@ def gaussian_pi(X, model, y_opt=0.0, xi=0.01, return_grad=False): """ Use the probability of improvement to calculate the acquisition values. - The conditional probability `P(y=f(x) | x)`form a gaussian with a + The conditional probability ``P(y=f(x) | x)`` form a gaussian with a certain mean and standard deviation approximated by the model. The PI condition is derived by computing ``E[u(f(x))]`` where ``u(f(x)) = 1``, if ``f(x) < y_opt`` and ``u(f(x)) = 0``, - if``f(x) > y_opt``. + if ``f(x) > y_opt``. This means that the PI condition does not care about how "better" the predictions are than the previous values, since it gives an equal reward @@ -165,30 +165,33 @@ def gaussian_pi(X, model, y_opt=0.0, xi=0.01, return_grad=False): Parameters ---------- - * `X` [array-like, shape=(n_samples, n_features)]: + X : array-like, shape=[n_samples, n_features] Values where the acquisition function should be computed. - * `model` [sklearn estimator that implements predict with ``return_std``]: + model : sklearn estimator that implements predict with ``return_std`` The fit estimator that approximates the function through the method ``predict``. It should have a ``return_std`` parameter that returns the standard deviation. - * `y_opt` [float, default 0]: + y_opt : float, optional (default 0) Previous minimum value which we would like to improve upon. - * `xi`: [float, default=0.01]: + xi : float, optional (default=0.01) Controls how much improvement one wants over the previous best values. Useful only when ``method`` is set to "EI" - * `return_grad`: [boolean, optional]: + return_grad : boolean, optional (default=False) Whether or not to return the grad. Implemented only for the case where ``X`` is a single sample. Returns ------- - * `values`: [array-like, shape=(X.shape[0],)]: - Acquisition function values computed at X. + values : array-like, shape=[X.shape[0]] + Acquisition function values computed at ``X``. + + grad : array-like, shape=[n_samples, n_features] + Gradient at ``X``. """ with warnings.catch_warnings(): warnings.simplefilter("ignore") @@ -239,30 +242,33 @@ def gaussian_ei(X, model, y_opt=0.0, xi=0.01, return_grad=False): Parameters ---------- - * `X` [array-like, shape=(n_samples, n_features)]: + X : array-like, shape=[n_samples, n_features] Values where the acquisition function should be computed. - * `model` [sklearn estimator that implements predict with ``return_std``]: + model : sklearn estimator that implements predict with ``return_std`` The fit estimator that approximates the function through the method ``predict``. It should have a ``return_std`` parameter that returns the standard deviation. - * `y_opt` [float, default 0]: + y_opt : float, optional (default 0) Previous minimum value which we would like to improve upon. - * `xi`: [float, default=0.01]: + xi : float, optional (default=0.01) Controls how much improvement one wants over the previous best values. Useful only when ``method`` is set to "EI" - * `return_grad`: [boolean, optional]: + return_grad : boolean, optional (default=False) Whether or not to return the grad. Implemented only for the case where ``X`` is a single sample. Returns ------- - * `values`: [array-like, shape=(X.shape[0],)]: - Acquisition function values computed at X. + values : array-like, shape=[X.shape[0]] + Acquisition function values computed at ``X``. + + grad : array-like, shape=[n_samples, n_features] + Gradient at ``X``. """ with warnings.catch_warnings(): warnings.simplefilter("ignore") diff --git a/skopt/callbacks.py b/skopt/callbacks.py index 048ceac..6870c15 100644 --- a/skopt/callbacks.py +++ b/skopt/callbacks.py @@ -2,7 +2,7 @@ Callbacks are callables which are invoked after each iteration of the optimizer and are passed the results "so far". Callbacks can monitor progress, or stop -the optimization early by returning `True`. +the optimization early by returning ``True``. Monitoring callbacks -------------------- @@ -11,7 +11,10 @@ Early stopping callbacks ------------------------ +* DeadlineStopper * DeltaXStopper +* DeltaYStopper +* TimerCallback """ from collections import Callable from time import time @@ -44,19 +47,19 @@ class VerboseCallback(object): Parameters ---------- - * `n_init` [int, optional]: + n_total : int + Total number of func calls. + + n_init : int, optional (default=0) Number of points provided by the user which are yet to be evaluated. This is equal to `len(x0)` when `y0` is None - * `n_random` [int, optional]: + n_random : int, optional (default=0) Number of points randomly chosen. - * `n_total` [int]: - Total number of func calls. - Attributes ---------- - * `iter_no`: [int]: + iter_no : int Number of iterations of the optimization routine. """ @@ -97,7 +100,7 @@ def __call__(self, res): """ Parameters ---------- - * `res` [`OptimizeResult`, scipy object]: + res : ``OptimizeResult``, scipy object The optimization as a OptimizeResult object. """ time_taken = time() - self._start_time @@ -120,13 +123,13 @@ class TimerCallback(object): """ Log the elapsed time between each iteration of the minimization loop. - The time for each iteration is stored in the `iter_time` attribute which + The time for each iteration is stored in the ``iter_time`` attribute which you can inspect after the minimization has completed. Attributes ---------- - * `iter_time`: [list, shape=(n_iter,)]: - `iter_time[i-1]` gives the time taken to complete iteration `i` + iter_time : list, shape=(n_iter,) + ``iter_time[i-1]`` gives the time taken to complete iteration ``i`` """ def __init__(self): self._time = time() @@ -136,7 +139,7 @@ def __call__(self, res): """ Parameters ---------- - * `res` [`OptimizeResult`, scipy object]: + res : ``OptimizeResult``, scipy object The optimization as a OptimizeResult object. """ elapsed_time = time() - self._time @@ -144,7 +147,7 @@ def __call__(self, res): self._time = time() -class EarlyStopper(object): +class _EarlyStopper(object): """Decide to continue or not given the results so far. The optimization procedure will be stopped if the callback returns True. @@ -153,7 +156,7 @@ def __call__(self, result): """ Parameters ---------- - * `result` [`OptimizeResult`, scipy object]: + res : ``OptimizeResult``, scipy object The optimization as a OptimizeResult object. """ return self._criterion(result) @@ -179,14 +182,14 @@ def _criterion(self, result): " by subclasses of EarlyStopper.") -class DeltaXStopper(EarlyStopper): - """Stop the optimization when |x1 - x2| < `delta` +class DeltaXStopper(_EarlyStopper): + """Stop the optimization when |x1 - x2| < ``delta`` If the last two positions at which the objective has been evaluated - are less than `delta` apart stop the optimization procedure. + are less than ``delta`` apart stop the optimization procedure. """ def __init__(self, delta): - super(EarlyStopper, self).__init__() + super(_EarlyStopper, self).__init__() self.delta = delta def _criterion(self, result): @@ -198,14 +201,14 @@ def _criterion(self, result): return None -class DeltaYStopper(EarlyStopper): - """Stop the optimization if the `n_best` minima are within `delta` +class DeltaYStopper(_EarlyStopper): + """Stop the optimization if the ``n_best`` minima are within ``delta`` - Stop the optimizer if the absolute difference between the `n_best` - objective values is less than `delta`. + Stop the optimizer if the absolute difference between the ``n_best`` + objective values is less than ``delta``. """ def __init__(self, delta, n_best=5): - super(EarlyStopper, self).__init__() + super(_EarlyStopper, self).__init__() self.delta = delta self.n_best = n_best @@ -222,19 +225,19 @@ def _criterion(self, result): return None -class DeadlineStopper(EarlyStopper): - """ - Stop the optimization before running out of a fixed budget of time. +class DeadlineStopper(_EarlyStopper): + """Stop the optimization before running out of a fixed budget of time. - Attributes + Parameters ---------- - * `iter_time`: [list, shape=(n_iter,)]: - `iter_time[i-1]` gives the time taken to complete iteration `i` + total_time : float + Time (in seconds) that the optimization must finish within. - Parameters + Attributes ---------- - * `total_time`: fixed budget of time (seconds) that the optimization must - finish within. + iter_time : list, shape=(n_iter,) + ``iter_time[i-1]`` gives the time taken to complete iteration ``i`` + """ def __init__(self, total_time): super(DeadlineStopper, self).__init__() diff --git a/skopt/optimizer/gbrt.py b/skopt/optimizer/gbrt.py index c368f60..f9eae53 100644 --- a/skopt/optimizer/gbrt.py +++ b/skopt/optimizer/gbrt.py @@ -14,121 +14,140 @@ def gbrt_minimize(func, dimensions, base_estimator=None, """Sequential optimization using gradient boosted trees. Gradient boosted regression trees are used to model the (very) - expensive to evaluate function `func`. The model is improved + expensive to evaluate function ``func``. The model is improved by sequentially evaluating the expensive function at the next best point. Thereby finding the minimum of `func` with as few evaluations as possible. - The total number of evaluations, `n_calls`, are performed like the - following. If `x0` is provided but not `y0`, then the elements of `x0` - are first evaluated, followed by `n_random_starts` evaluations. - Finally, `n_calls - len(x0) - n_random_starts` evaluations are - made guided by the surrogate model. If `x0` and `y0` are both - provided then `n_random_starts` evaluations are first made then - `n_calls - n_random_starts` subsequent evaluations are made + The total number of evaluations, ``n_calls``, are performed like the + following. If ``x0`` is provided but not ``y0``, then the elements of + ``x0`` are first evaluated, followed by ``n_random_starts`` evaluations. + Finally, ``n_calls - len(x0) - n_random_starts`` evaluations are + made guided by the surrogate model. If ``x0`` and ``y0`` are both + provided then ``n_random_starts`` evaluations are first made then + ``n_calls - n_random_starts`` subsequent evaluations are made guided by the surrogate model. Parameters ---------- - * `func` [callable]: + func : callable Function to minimize. Should take a array of parameters and return the function values. - * `dimensions` [list, shape=(n_dims,)]: + dimensions : list, shape=(n_dims,) List of search space dimensions. Each search dimension can be defined either as - - a `(upper_bound, lower_bound)` tuple (for `Real` or `Integer` + - a ``(lower_bound, upper_bound)`` tuple (for ``Real`` or ``Integer`` dimensions), - - a `(upper_bound, lower_bound, "prior")` tuple (for `Real` + - a ``(lower_bound, upper_bound, "prior")`` tuple (for ``Real`` dimensions), - - as a list of categories (for `Categorical` dimensions), or - - an instance of a `Dimension` object (`Real`, `Integer` or - `Categorical`). + - as a list of categories (for ``Categorical`` dimensions), or + - an instance of a ``Dimension`` object (``Real``, ``Integer`` or + ``Categorical``). - * `base_estimator` [`GradientBoostingQuantileRegressor`]: - The regressor to use as surrogate model + NOTE: The upper and lower bounds are inclusive for ``Integer`` + dimensions. - * `n_calls` [int, default=100]: - Number of calls to `func`. + base_estimator : ``GradientBoostingQuantileRegressor`` + The regressor to use as surrogate model. - * `n_random_starts` [int, default=10]: - Number of evaluations of `func` with random points before - approximating it with `base_estimator`. + n_calls : int, optional (default=100) + Number of calls to ``func``. - * `acq_func` [string, default=`"LCB"`]: + n_random_starts : int, optional (default=10) + Number of evaluations of ``func`` with random points before + approximating it with ``base_estimator``. + + acq_func : string, optional (default="LCB") Function to minimize over the forest posterior. Can be either - - `"LCB"` for lower confidence bound. - - `"EI"` for negative expected improvement. - - `"PI"` for negative probability of improvement. - - ``"EIps"`` for negated expected improvement per second to take into + - "LCB" for lower confidence bound. + - "EI" for negative expected improvement. + - "PI" for negative probability of improvement. + - "gp_hedge" Probabilistically choose one of the above three + acquisition functions at every iteration. The weightage + given to these gains can be set by ``\eta`` through + ``acq_func_kwargs``. + - The gains ``g_i`` are initialized to zero. + - At every iteration, + - Each acquisition function is optimised independently to + propose an candidate point ``X_i``. + - Out of all these candidate points, the next point ``X_best`` + is chosen by ``softmax(\eta g_i)``. + - After fitting the surrogate model with ``(X_best, y_best)``, + the gains are updated such that ``g_i -= \mu(X_i)`` + - "EIps" for negated expected improvement per second to take into account the function compute time. Then, the objective function is assumed to return two values, the first being the objective value and the second being the time taken. - - `"PIps"` for negated probability of improvement per second. + - "PIps" for negated probability of improvement per second. - * `x0` [list, list of lists or `None`]: + x0 : list, list of lists or ``None`` Initial input points. - If it is a list of lists, use it as a list of input points. - If it is a list, use it as a single initial input point. - - If it is `None`, no initial input points are used. + - If it is ``None``, no initial input points are used. - * `y0` [list, scalar or `None`]: + y0 : list, scalar or ``None`` Evaluation of initial input points. - If it is a list, then it corresponds to evaluations of the function - at each element of `x0` : the i-th element of `y0` corresponds - to the function evaluated at the i-th element of `x0`. + at each element of ``x0`` : the i-th element of ``y0`` corresponds + to the function evaluated at the i-th element of ``x0``. - If it is a scalar, then it corresponds to the evaluation of the - function at `x0`. - - If it is None and `x0` is provided, then the function is evaluated - at each element of `x0`. + function at ``x0``. + - If it is None and ``x0`` is provided, then the function is evaluated + at each element of ``x0``. - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set random state to something other than None for reproducible results. - * `verbose` [boolean, default=False]: + verbose : boolean (default=False) Control the verbosity. It is advised to set the verbosity to True for long optimization runs. - * `callback` [callable, optional] - If provided, then `callback(res)` is called after call to func. - - * `n_points` [int, default=10000]: - Number of points to sample when minimizing the acquisition function. + callback : callable, list of callables, optional + If callable then ``callback(res)`` is called after each call to + ``func``. If list of callables, then each callable in the list is + called. - * `xi` [float, default=0.01]: - Controls how much improvement one wants over the previous best - values. Used when the acquisition is either `"EI"` or `"PI"`. + n_points : int, optional (default=10000) + Number of points to sample to determine the next "best" point. + Useless if acq_optimizer is set to ``lbfgs``. - * `kappa` [float, default=1.96]: + kappa : float, optional (default=1.96) Controls how much of the variance in the predicted values should be taken into account. If set to be very high, then we are favouring exploration over exploitation and vice versa. - Used when the acquisition is `"LCB"`. + Used when the acquisition is "LCB". + + xi : float, optional (default=0.01) + Controls how much improvement one wants over the previous best + values. Used when the acquisition is either "EI" or "PI". - * `n_jobs` [int, default=1]: - The number of jobs to run in parallel for `fit` and `predict`. - If -1, then the number of jobs is set to the number of cores. + n_jobs : int, optional (default=1) + Number of cores used to parallize fitting of ``base_estimator``. + Defaults to 1 core. If ``n_jobs=-1``, then number of jobs is set + to number of cores. Returns ------- - * `res` [`OptimizeResult`, scipy object]: + res : ``OptimizeResult``, scipy object The optimization result returned as a OptimizeResult object. Important attributes are: - - `x` [list]: location of the minimum. - - `fun` [float]: function value at the minimum. - - `models`: surrogate models used for each iteration. - - `x_iters` [list of lists]: location of function evaluation for each + - ``x`` [list]: location of the minimum. + - ``fun`` [float]: function value at the minimum. + - ``models``: surrogate models used for each iteration. + - ``x_iters`` [list of lists]: location of function evaluation for each iteration. - - `func_vals` [array]: function value for each iteration. - - `space` [Space]: the optimization space. - - `specs` [dict]`: the call specifications. - - `rng` [RandomState instance]: State of the random state + - ``func_vals`` [array]: function value for each iteration. + - ``space`` [Space]: the optimization space. + - ``specs`` [dict]: the call specifications. + - ``rng`` [RandomState instance]: State of the random state at the end of minimization. For more details related to the OptimizeResult object, refer diff --git a/skopt/optimizer/gp.py b/skopt/optimizer/gp.py index 5f52d6d..2d0dfdf 100644 --- a/skopt/optimizer/gp.py +++ b/skopt/optimizer/gp.py @@ -31,37 +31,37 @@ def gp_minimize(func, dimensions, base_estimator=None, next parameter to evaluate can be made by the acquisition function over the Gaussian prior which is much quicker to evaluate. - The total number of evaluations, `n_calls`, are performed like the - following. If `x0` is provided but not `y0`, then the elements of `x0` - are first evaluated, followed by `n_random_starts` evaluations. - Finally, `n_calls - len(x0) - n_random_starts` evaluations are - made guided by the surrogate model. If `x0` and `y0` are both - provided then `n_random_starts` evaluations are first made then - `n_calls - n_random_starts` subsequent evaluations are made + The total number of evaluations, ``n_calls``, are performed like the + following. If ``x0`` is provided but not ``y0``, then the elements of ``x0`` + are first evaluated, followed by ``n_random_starts`` evaluations. + Finally, ``n_calls - len(x0) - n_random_starts`` evaluations are + made guided by the surrogate model. If ``x0`` and ``y0`` are both + provided then ``n_random_starts`` evaluations are first made then + ``n_calls - n_random_starts`` subsequent evaluations are made guided by the surrogate model. Parameters ---------- - * `func` [callable]: + func : callable Function to minimize. Should take a array of parameters and return the function values. - * `dimensions` [list, shape=(n_dims,)]: + dimensions : list, shape=(n_dims,) List of search space dimensions. Each search dimension can be defined either as - - a `(upper_bound, lower_bound)` tuple (for `Real` or `Integer` + - a ``(lower_bound, upper_bound)`` tuple (for ``Real`` or ``Integer`` dimensions), - - a `(upper_bound, lower_bound, "prior")` tuple (for `Real` + - a ``(lower_bound, upper_bound, "prior")`` tuple (for ``Real`` dimensions), - - as a list of categories (for `Categorical` dimensions), or - - an instance of a `Dimension` object (`Real`, `Integer` or - `Categorical`). + - as a list of categories (for ``Categorical`` dimensions), or + - an instance of a ``Dimension`` object (``Real``, ``Integer`` or + ``Categorical``). - NOTE: The upper and lower bounds are inclusive for `Integer` + NOTE: The upper and lower bounds are inclusive for ``Integer`` dimensions. - * `base_estimator` [a Gaussian process estimator]: + base_estimator : a Gaussian process estimator The Gaussian process estimator to use for optimization. By default, a Matern kernel is used with the following hyperparameters tuned. @@ -70,106 +70,108 @@ def gp_minimize(func, dimensions, base_estimator=None, - Noise that is added to the matern kernel. The noise is assumed to be iid gaussian. - * `n_calls` [int, default=100]: - Number of calls to `func`. + n_calls : int (default=100) + Number of calls to ``func``. - * `n_random_starts` [int, default=10]: - Number of evaluations of `func` with random points before - approximating it with `base_estimator`. + n_random_starts : int (default=10) + Number of evaluations of ``func`` with random points before + approximating it with ``base_estimator``. - * `acq_func` [string, default=`"EI"`]: + acq_func : string, (default="EI") Function to minimize over the gaussian prior. Can be either - - `"LCB"` for lower confidence bound. - - `"EI"` for negative expected improvement. - - `"PI"` for negative probability of improvement. - - `"gp_hedge"` Probabilistically choose one of the above three + - "LCB" for lower confidence bound. + - "EI" for negative expected improvement. + - "PI" for negative probability of improvement. + - "gp_hedge" Probabilistically choose one of the above three acquisition functions at every iteration. The weightage - given to these gains can be set by `\eta` through `acq_func_kwargs`. - - The gains `g_i` are initialized to zero. + given to these gains can be set by ``\eta`` through + ``acq_func_kwargs``. + - The gains ``g_i`` are initialized to zero. - At every iteration, - Each acquisition function is optimised independently to - propose an candidate point `X_i`. - - Out of all these candidate points, the next point `X_best` is - chosen by `softmax(\eta g_i)` - - After fitting the surrogate model with `(X_best, y_best)`, - the gains are updated such that `g_i -= \mu(X_i)` - - `"EIps"` for negated expected improvement per second to take into + propose an candidate point ``X_i``. + - Out of all these candidate points, the next point ``X_best`` + is chosen by ``softmax(\eta g_i)``. + - After fitting the surrogate model with ``(X_best, y_best)``, + the gains are updated such that ``g_i -= \mu(X_i)`` + - "EIps" for negated expected improvement per second to take into account the function compute time. Then, the objective function is assumed to return two values, the first being the objective value and the second being the time taken in seconds. - - `"PIps"` for negated probability of improvement per second. The + - "PIps" for negated probability of improvement per second. The return type of the objective function is assumed to be similar to - that of `"EIps + that of "EIps". - * `acq_optimizer` [string, `"sampling"` or `"lbfgs"`, default=`"lbfgs"`]: + acq_optimizer : string, "sampling" or "lbfgs" (default="lbfgs") Method to minimize the acquistion function. The fit model - is updated with the optimal value obtained by optimizing `acq_func` - with `acq_optimizer`. + is updated with the optimal value obtained by optimizing ``acq_func`` + with ``acq_optimizer``. - The `acq_func` is computed at `n_points` sampled randomly. + The ``acq_func`` is computed at ``n_points`` sampled randomly. - - If set to `"auto"`, then `acq_optimizer` is configured on the + - If set to "auto", then ``acq_optimizer`` is configured on the basis of the space searched over. - If the space is Categorical then this is set to be "sampling"`. - - If set to `"sampling"`, then the point among these `n_points` - where the `acq_func` is minimum is the next candidate minimum. - - If set to `"lbfgs"`, then - - The `n_restarts_optimizer` no. of points which the acquisition + If the space is ``Categorical`` then this is set to be "sampling". + - If set to "sampling", then the point among these ``n_points`` + where the ``acq_func`` is minimum is the next candidate minimum. + - If set to "lbfgs", then + - The ``n_restarts_optimizer`` no. of points which the acquisition function is least are taken as start points. - - `"lbfgs"` is run for 20 iterations with these points as initial + - "lbfgs" is run for 20 iterations with these points as initial points to find local minima. - The optimal of these local minima is used to update the prior. - * `x0` [list, list of lists or `None`]: + x0 : list, list of lists or ``None`` Initial input points. - If it is a list of lists, use it as a list of input points. - If it is a list, use it as a single initial input point. - - If it is `None`, no initial input points are used. + - If it is ``None``, no initial input points are used. - * `y0` [list, scalar or `None`] + y0 : list, scalar or ``None`` Evaluation of initial input points. - If it is a list, then it corresponds to evaluations of the function - at each element of `x0` : the i-th element of `y0` corresponds - to the function evaluated at the i-th element of `x0`. + at each element of ``x0`` : the i-th element of ``y0`` corresponds + to the function evaluated at the i-th element of ``x0``. - If it is a scalar, then it corresponds to the evaluation of the - function at `x0`. - - If it is None and `x0` is provided, then the function is evaluated - at each element of `x0`. + function at ``x0``. + - If it is None and ``x0`` is provided, then the function is evaluated + at each element of ``x0``. - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set random state to something other than None for reproducible results. - * `verbose` [boolean, default=False]: + verbose : boolean (default=False) Control the verbosity. It is advised to set the verbosity to True for long optimization runs. - * `callback` [callable, list of callables, optional] - If callable then `callback(res)` is called after each call to `func`. - If list of callables, then each callable in the list is called. + callback : callable, list of callables, optional + If callable then ``callback(res)`` is called after each call to + ``func``. If list of callables, then each callable in the list is + called. - * `n_points` [int, default=10000]: + n_points : int, optional (default=10000) Number of points to sample to determine the next "best" point. - Useless if acq_optimizer is set to `"lbfgs"`. + Useless if acq_optimizer is set to ``lbfgs``. - * `n_restarts_optimizer` [int, default=5]: - The number of restarts of the optimizer when `acq_optimizer` - is `"lbfgs"`. + n_restarts_optimizer : int, optional (default=5) + The number of restarts of the optimizer when ``acq_optimizer`` + is "lbfgs". - * `kappa` [float, default=1.96]: + kappa : float, optional (default=1.96) Controls how much of the variance in the predicted values should be taken into account. If set to be very high, then we are favouring exploration over exploitation and vice versa. - Used when the acquisition is `"LCB"`. + Used when the acquisition is "LCB". - * `xi` [float, default=0.01]: + xi : float, optional (default=0.01) Controls how much improvement one wants over the previous best - values. Used when the acquisition is either `"EI"` or `"PI"`. + values. Used when the acquisition is either "EI" or "PI". - * `noise` [float, default="gaussian"]: + noise : float, optional (default="gaussian") - Use noise="gaussian" if the objective returns noisy observations. The noise of each observation is assumed to be iid with mean zero and a fixed variance. @@ -178,28 +180,28 @@ def gp_minimize(func, dimensions, base_estimator=None, - Set this to a value close to zero (1e-10) if the function is noise-free. Setting to zero might cause stability issues. - * `n_jobs` [int, default=1] + n_jobs : int, optional (default=1) Number of cores to run in parallel while running the lbfgs optimizations over the acquisition function. Valid only - when `acq_optimizer` is set to "lbfgs." - Defaults to 1 core. If `n_jobs=-1`, then number of jobs is set + when ``acq_optimizer`` is set to "lbfgs". + Defaults to 1 core. If ``n_jobs=-1``, then number of jobs is set to number of cores. Returns ------- - * `res` [`OptimizeResult`, scipy object]: + res : ``OptimizeResult``, scipy object The optimization result returned as a OptimizeResult object. Important attributes are: - - `x` [list]: location of the minimum. - - `fun` [float]: function value at the minimum. - - `models`: surrogate models used for each iteration. - - `x_iters` [list of lists]: location of function evaluation for each + - ``x`` [list]: location of the minimum. + - ``fun`` [float]: function value at the minimum. + - ``models``: surrogate models used for each iteration. + - ``x_iters`` [list of lists]: location of function evaluation for each iteration. - - `func_vals` [array]: function value for each iteration. - - `space` [Space]: the optimization space. - - `specs` [dict]`: the call specifications. - - `rng` [RandomState instance]: State of the random state + - ``func_vals`` [array]: function value for each iteration. + - ``space`` [Space]: the optimization space. + - ``specs`` [dict]: the call specifications. + - ``rng`` [RandomState instance]: State of the random state at the end of minimization. For more details related to the OptimizeResult object, refer diff --git a/skopt/optimizer/optimizer.py b/skopt/optimizer/optimizer.py index a71872c..ad496ff 100644 --- a/skopt/optimizer/optimizer.py +++ b/skopt/optimizer/optimizer.py @@ -28,108 +28,109 @@ class Optimizer(object): """Run bayesian optimisation loop. - An `Optimizer` represents the steps of a bayesian optimisation loop. To + An ``Optimizer`` represents the steps of a bayesian optimisation loop. To use it you need to provide your own loop mechanism. The various - optimisers provided by `skopt` use this class under the hood. + optimisers provided by scikit-optimize use this class under the hood. Use this class directly if you want to control the iterations of your bayesian optimisation loop. Parameters ---------- - * `dimensions` [list, shape=(n_dims,)]: + dimensions : list, shape=[n_dims] List of search space dimensions. Each search dimension can be defined either as - a `(upper_bound, lower_bound)` tuple (for `Real` or `Integer` dimensions), - - a `(upper_bound, lower_bound, "prior")` tuple (for `Real` + - a `(upper_bound, lower_bound, 'prior')` tuple (for `Real` dimensions), - as a list of categories (for `Categorical` dimensions), or - an instance of a `Dimension` object (`Real`, `Integer` or `Categorical`). - * `base_estimator` ["GP", "RF", "ET", "GBRT" or sklearn regressor, default="GP"]: - Should inherit from `sklearn.base.RegressorMixin`. - In addition the `predict` method, should have an optional `return_std` - argument, which returns `std(Y | x)`` along with `E[Y | x]`. - If base_estimator is one of ["GP", "RF", "ET", "GBRT"], a default + base_estimator : {'GP', 'RF', 'ET', 'GBRT', sklearn regressor}, optional (default='GP') + If not a string then should inherit from + ``sklearn.base.RegressorMixin``. In addition the ``predict`` method, + should have an optional ``return_std`` argument, which returns + ``std(Y | x)`` along with ``E[Y | x]``. + If base_estimator is one of ['GP', 'RF', 'ET', 'GBRT'], a default surrogate model of the corresponding type is used corresponding to what is used in the minimize functions. - * `n_random_starts` [int, default=10]: - DEPRECATED, use `n_initial_points` instead. + n_random_starts : int, optional (default=10) + DEPRECATED, use ``n_initial_points`` instead. - * `n_initial_points` [int, default=10]: - Number of evaluations of `func` with initialization points - before approximating it with `base_estimator`. Points provided as - `x0` count as initialization points. If len(x0) < n_initial_points + n_initial_points : int, optional (default=10) + Number of evaluations of ``func`` with initialization points + before approximating it with ``base_estimator``. Points provided as + ``x0`` count as initialization points. If len(x0) < n_initial_points additional points are sampled at random. - * `acq_func` [string, default=`"EI"`]: + acq_func : string, optional (default='gp_hedge') Function to minimize over the posterior distribution. Can be either - - `"LCB"` for lower confidence bound. - - `"EI"` for negative expected improvement. - - `"PI"` for negative probability of improvement. - - `"gp_hedge"` Probabilistically choose one of the above three + - 'LCB' for lower confidence bound. + - 'EI' for negative expected improvement. + - 'PI' for negative probability of improvement. + - 'gp_hedge' Probabilistically choose one of the above three acquisition functions at every iteration. - - The gains `g_i` are initialized to zero. + - The gains ``g_i`` are initialized to zero. - At every iteration, - Each acquisition function is optimised independently to - propose an candidate point `X_i`. - - Out of all these candidate points, the next point `X_best` is - chosen by $softmax(\eta g_i)$ - - After fitting the surrogate model with `(X_best, y_best)`, - the gains are updated such that $g_i -= \mu(X_i)$ - - `"EIps" for negated expected improvement per second to take into + propose an candidate point ``X_i``. + - Out of all these candidate points, the next point ``X_best`` + is chosen by ``softmax(\eta g_i)`` + - After fitting the surrogate model with ``(X_best, y_best)``, + the gains are updated such that ``g_i -= \mu(X_i)`` + - 'EIps' for negated expected improvement per second to take into account the function compute time. Then, the objective function is assumed to return two values, the first being the objective value and the second being the time taken in seconds. - - `"PIps"` for negated probability of improvement per second. The + - 'PIps' for negated probability of improvement per second. The return type of the objective function is assumed to be similar to - that of `"EIps + that of 'EIps'. - * `acq_optimizer` [string, `"sampling"` or `"lbfgs"`, default=`"auto"`]: + acq_optimizer : {'sampling', 'lbfgs'}, optional (default='auto') Method to minimize the acquistion function. The fit model - is updated with the optimal value obtained by optimizing `acq_func` - with `acq_optimizer`. + is updated with the optimal value obtained by optimizing ``acq_func`` + with ``acq_optimizer``. - - If set to `"auto"`, then `acq_optimizer` is configured on the + - If set to 'auto', then ``acq_optimizer`` is configured on the basis of the base_estimator and the space searched over. If the space is Categorical or if the estimator provided based on - tree-models then this is set to be "sampling"`. - - If set to `"sampling"`, then `acq_func` is optimized by computing - `acq_func` at `n_points` randomly sampled points. - - If set to `"lbfgs"`, then `acq_func` is optimized by - - Sampling `n_restarts_optimizer` points randomly. - - `"lbfgs"` is run for 20 iterations with these points as initial + tree-models then this is set to be 'sampling'. + - If set to 'sampling', then ``acq_func`` is optimized by computing + ``acq_func`` at ``n_points`` randomly sampled points. + - If set to 'lbfgs', then ``acq_func`` is optimized by + - Sampling ``n_restarts_optimizer`` points randomly. + - 'lbfgs' is run for 20 iterations with these points as initial points to find local minima. - The optimal of these local minima is used to update the prior. - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set random state to something other than None for reproducible results. - * `acq_func_kwargs` [dict]: + acq_func_kwargs : dict Additional arguments to be passed to the acquistion function. - * `acq_optimizer_kwargs` [dict]: + acq_optimizer_kwargs : dict Additional arguments to be passed to the acquistion optimizer. Attributes ---------- - * `Xi` [list]: + Xi : list Points at which objective has been evaluated. - * `yi` [scalar]: - Values of objective at corresponding points in `Xi`. - * `models` [list]: + yi : scalar + Values of objective at corresponding points in ``Xi``. + models : list Regression models used to fit observations and compute acquisition function. - * `space` - An instance of `skopt.space.Space`. Stores parameter search space used - to sample points, bounds, and type of parameters. + space : skopt.space.Space + An instance of ``skopt.space.Space``. Stores parameter search space + used to sample points, bounds, and type of parameters. """ def __init__(self, dimensions, base_estimator="gp", @@ -243,7 +244,7 @@ def copy(self, random_state=None): Parameters ---------- - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set the random state of the copy. """ @@ -269,7 +270,9 @@ def copy(self, random_state=None): def ask(self, n_points=None, strategy="cl_min"): """Query point or multiple points at which objective should be evaluated. - * `n_points` [int or None, default=None]: + Parameters + ---------- + n_points : int or None, optional (default=None) Number of points returned by the ask method. If the value is None, a single point to evaluate is returned. Otherwise a list of points to evaluate is returned of size @@ -277,14 +280,14 @@ def ask(self, n_points=None, strategy="cl_min"): parallel, and thus obtain more objective function evaluations per unit of time. - * `strategy` [string, default=`"cl_min"`]: - Method to use to sample multiple points (see also `n_points` - description). This parameter is ignored if n_points = None. - Supported options are `"cl_min"`, `"cl_mean"` or `"cl_max"`. + strategy : string, optional (default='cl_min') + Method to use to sample multiple points (see also ``n_points`` + description). This parameter is ignored if ``n_points=None``. + Supported options are 'cl_min', 'cl_mean' or 'cl_max'. - - If set to `"cl_min"`, then constant liar strtategy is used + - If set to 'cl_min', then constant liar strtategy is used with lie objective value being minimum of observed objective - values. `"cl_mean"` and `"cl_max"` means mean and max of values + values. 'cl_mean' and 'cl_max' means mean and max of values respectively. For details on this strategy see: https://hal.archives-ouvertes.fr/hal-00732512/document @@ -294,7 +297,7 @@ def ask(self, n_points=None, strategy="cl_min"): optimizer with some fake objective (lie), the next point is asked from copy, it is also told to the copy with fake objective and so on. The type of lie defines different - flavours of `cl_x` strategies. + flavours of ``cl_x`` strategies. """ if n_points is None: @@ -342,8 +345,8 @@ def ask(self, n_points=None, strategy="cl_min"): def _ask(self): """Suggest next point at which to evaluate the objective. - Return a random point while not at least `n_initial_points` - observations have been `tell`ed, after that `base_estimator` is used + Return a random point while not at least ``n_initial_points`` + observations have been `tell`ed, after that ``base_estimator`` is used to determine the next point. """ if self._n_initial_points > 0 or self.base_estimator_ is None: @@ -369,11 +372,11 @@ def _ask(self): def tell(self, x, y, fit=True): """Record an observation (or several) of the objective function. - Provide values of the objective function at points suggested by `ask()` - or other points. By default a new model will be fit to all - observations. The new model is used to suggest the next point at - which to evaluate the objective. This point can be retrieved by calling - `ask()`. + Provide values of the objective function at points suggested by + ``ask()`` or other points. By default a new model will be + fit to all observations. The new model is used to suggest the next + point at which to evaluate the objective. This point can be retrieved + by calling ``ask()``. To add observations without fitting a new model set `fit` to False. @@ -382,16 +385,16 @@ def tell(self, x, y, fit=True): Parameters ---------- - * `x` [list or list-of-lists]: + x : list or list-of-lists Point at which objective was evaluated. - * `y` [scalar or list]: + y : scalar or list Value of objective at `x`. - * `fit` [bool, default=True] + fit : bool, optional (default=True) Fit a model to observed evaluations of the objective. A model will - only be fitted after `n_initial_points` points have been told to - the optimizer irrespective of the value of `fit`. + only be fitted after ``n_initial_points`` points have been told to + the optimizer irrespective of the value of ``fit``. """ check_x_in_space(x, self.space) @@ -512,7 +515,7 @@ def tell(self, x, y, fit=True): models=self.models) def run(self, func, n_iter=1): - """Execute ask() + tell() `n_iter` times""" + """Execute ask() + tell() ``n_iter`` times""" for _ in range(n_iter): x = self.ask() self.tell(x, func(x)) diff --git a/skopt/plots.py b/skopt/plots.py index 14f2586..3a71c76 100644 --- a/skopt/plots.py +++ b/skopt/plots.py @@ -15,28 +15,29 @@ def plot_convergence(*args, **kwargs): Parameters ---------- - * `args[i]` [`OptimizeResult`, list of `OptimizeResult`, or tuple]: + args[i] : ``OptimizeResult``, list of ``OptimizeResult``, or tuple The result(s) for which to plot the convergence trace. - - if `OptimizeResult`, then draw the corresponding single trace; - - if list of `OptimizeResult`, then draw the corresponding convergence - traces in transparency, along with the average convergence trace; - - if tuple, then `args[i][0]` should be a string label and `args[i][1]` - an `OptimizeResult` or a list of `OptimizeResult`. + - if ``OptimizeResult``, then draw the corresponding single trace; + - if list of ``OptimizeResult``, then draw the corresponding + convergence traces in transparency, along with the average + convergence trace; + - if tuple, then ``args[i][0]`` should be a string label and + ``args[i][1]`` an ``OptimizeResult`` or a list of ``OptimizeResult``. - * `ax` [`Axes`, optional]: + ax : `Axes`, optional (default=None) The matplotlib axes on which to draw the plot, or `None` to create a new one. - * `true_minimum` [float, optional]: + true_minimum : float, optional (default=None) The true minimum value of the function, if known. - * `yscale` [None or string, optional]: + yscale : None or string, optional (default=None) The scale for the y-axis. Returns ------- - * `ax`: [`Axes`]: + ax : ``Axes`` The matplotlib axes. """ # <3 legacy python @@ -147,58 +148,58 @@ def _format_scatter_plot_axes(ax, space, ylabel): def partial_dependence(space, model, i, j=None, sample_points=None, n_samples=250, n_points=40): - """Calculate the partial dependence for dimensions `i` and `j` with - respect to the objective value, as approximated by `model`. + """Calculate the partial dependence for dimensions ``i`` and ``j`` with + respect to the objective value, as approximated by ``model``. The partial dependence plot shows how the value of the dimensions - `i` and `j` influence the `model` predictions after "averaging out" + ``i`` and ``j`` influence the ``model`` predictions after "averaging out" the influence of all other dimensions. Parameters ---------- - * `space` [`Space`] + space : ``Space`` The parameter space over which the minimization was performed. - * `model` + model : skopt regressor Surrogate model for the objective function. - * `i` [int] + i : int The first dimension for which to calculate the partial dependence. - * `j` [int, default=None] + j : int, optional (default=None) The second dimension for which to calculate the partial dependence. - To calculate the 1D partial dependence on `i` alone set `j=None`. + To calculate the 1D partial dependence on ``i`` alone set ``j=None``. - * `sample_points` [np.array, shape=(n_points, n_dims), default=None] + sample_points : np.array, shape=[n_points, n_dims], optional (default=None) Randomly sampled and transformed points to use when averaging - the model function at each of the `n_points`. + the model function at each of the ``n_points``. - * `n_samples` [int, default=100] + n_samples : int, optional (default=100) Number of random samples to use for averaging the model function - at each of the `n_points`. Only used when `sample_points=None`. + at each of the ``n_points``. Only used when ``sample_points=None``. - * `n_points` [int, default=40] + n_points : int, optional (default=40) Number of points at which to evaluate the partial dependence - along each dimension `i` and `j`. + along each dimension ``i`` and ``j``. Returns ------- For 1D partial dependence: - * `xi`: [np.array]: + xi : np.array The points at which the partial dependence was evaluated. - * `yi`: [np.array]: - The value of the model at each point `xi`. + yi : np.array + The value of the model at each point ``xi``. For 2D partial dependence: - * `xi`: [np.array, shape=n_points]: + xi : np.array, shape=[n_points] The points at which the partial dependence was evaluated. - * `yi`: [np.array, shape=n_points]: + yi : np.array, shape=[n_points] The points at which the partial dependence was evaluated. - * `zi`: [np.array, shape=(n_points, n_points)]: - The value of the model at each point `(xi, yi)`. + zi : np.array, shape=[n_points, n_points] + The value of the model at each point ``(xi, yi)``. """ if sample_points is None: sample_points = space.transform(space.rvs(n_samples=n_samples)) @@ -243,43 +244,43 @@ def plot_objective(result, levels=10, n_points=40, n_samples=250, zscale='linear'): """Pairwise partial dependence plot of the objective function. - The diagonal shows the partial dependence for dimension `i` with + The diagonal shows the partial dependence for dimension ``i`` with respect to the objective function. The off-diagonal shows the - partial dependence for dimensions `i` and `j` with + partial dependence for dimensions ``i`` and ``j`` with respect to the objective function. The objective function is - approximated by `result.model.` + approximated by ``result.model``. Pairwise scatter plots of the points at which the objective function was directly evaluated are shown on the off-diagonal. A red point indicates the found minimum. - Note: search spaces that contain `Categorical` dimensions are + Note: search spaces that contain ``Categorical`` dimensions are currently not supported by this function. Parameters ---------- - * `result` [`OptimizeResult`] + result : `OptimizeResult`` The result for which to create the scatter plot matrix. - * `levels` [int, default=10] + levels : int, optional (default=10) Number of levels to draw on the contour plot, passed directly - to `plt.contour()`. + to ``plt.contour()``. - * `n_points` [int, default=40] + n_points : int, optional (default=40) Number of points at which to evaluate the partial dependence along each dimension. - * `n_samples` [int, default=250] + n_samples : int, optional (default=250) Number of random samples to use for averaging the model function - at each of the `n_points`. + at each of the ``n_points``. - * `zscale` [str, default='linear'] + zscale : str, optional (default='linear') Scale to use for the z axis of the contour plots. Either 'linear' or 'log'. Returns ------- - * `ax`: [`Axes`]: + ax : ``Axes`` The matplotlib axes. """ space = result.space @@ -337,20 +338,20 @@ def plot_evaluations(result, bins=20): The diagonal shows a histogram of sampled values for each dimension. A red point indicates the found minimum. - Note: search spaces that contain `Categorical` dimensions are + Note: search spaces that contain ``Categorical`` dimensions are currently not supported by this function. Parameters ---------- - * `result` [`OptimizeResult`] + result : ``OptimizeResult`` The result for which to create the scatter plot matrix. - * `bins` [int, bins=20]: + bins : int, optional (default=20) Number of bins to use for histograms on the diagonal. Returns ------- - * `ax`: [`Axes`]: + ax : ``Axes`` The matplotlib axes. """ space = result.space diff --git a/skopt/searchcv.py b/skopt/searchcv.py index 608fb9b..f288dc6 100644 --- a/skopt/searchcv.py +++ b/skopt/searchcv.py @@ -246,18 +246,13 @@ class BayesSearchCV(sk_model_sel.BaseSearchCV): The parameters selected are those that maximize the score of the held-out data, according to the scoring parameter. - If `n_jobs` was set to a value higher than one, the data is copied for each - parameter setting(and not `n_jobs` times). This is done for efficiency - reasons if individual jobs take very little time, but may raise errors if - the dataset is large and not enough memory is available. A workaround in - this case is to set `pre_dispatch`. Then, the memory is copied only - `pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 * - n_jobs`. - - See Also - -------- - :class:`GridSearchCV`: - Does exhaustive search over a grid of parameters. + If ``n_jobs`` was set to a value higher than one, the data is copied for + each parameter setting (and not ``n_jobs`` times). This is done for + efficiency reasons if individual jobs take very little time, but may raise + errors if the dataset is large and not enough memory is available. A + workaround in this case is to set ``pre_dispatch``. Then, the memory is + copied only ``pre_dispatch`` many times. A reasonable value for + ``pre_dispatch`` is ``2 * n_jobs``. """ diff --git a/skopt/space/__init__.py b/skopt/space/__init__.py index c48007e..8abd828 100644 --- a/skopt/space/__init__.py +++ b/skopt/space/__init__.py @@ -1,5 +1,10 @@ """ -Utilities to define a search space. +Define the search space of the optimization problem. """ -from .space import * +from .space import Categorical +from .space import Dimension +from .space import Integer +from .space import Real +from .space import Space +from .space import check_dimension diff --git a/skopt/space/space.py b/skopt/space/space.py index 6d04276..f0cbb9a 100644 --- a/skopt/space/space.py +++ b/skopt/space/space.py @@ -99,10 +99,10 @@ def rvs(self, n_samples=1, random_state=None): Parameters ---------- - * `n_samples` [int or None]: + n_samples : int or None, optional (default=1) The number of samples to be drawn. - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set random state to something other than None for reproducible results. """ @@ -145,32 +145,32 @@ def _uniform_inclusive(loc=0.0, scale=1.0): class Real(Dimension): - def __init__(self, low, high, prior="uniform", transform=None): - """Search space dimension that can take on any real value. + """Search space dimension that can take on any real value. - Parameters - ---------- - * `low` [float]: - Lower bound (inclusive). - - * `high` [float]: - Upper bound (inclusive). - - * `prior` ["uniform" or "log-uniform", default="uniform"]: - Distribution to use when sampling random points for this dimension. - - If `"uniform"`, points are sampled uniformly between the lower - and upper bounds. - - If `"log-uniform"`, points are sampled uniformly between - `log10(lower)` and `log10(upper)`.` - - * `transform` ["identity", "normalize", optional]: - The following transformations are supported. - - - "identity", (default) the transformed space is the same as the - original space. - - "normalize", the transformed space is scaled to be between - 0 and 1. - """ + Parameters + ---------- + low : float + Lower bound (inclusive). + + high : float + Upper bound (inclusive). + + prior : 'uniform' or 'log-uniform', optional, (default='uniform') + Distribution to use when sampling random points for this dimension. + - If ``uniform``, points are sampled uniformly between the lower + and upper bounds. + - If ``log-uniform``, points are sampled uniformly between + ``log10(lower)`` and ``log10(upper)``. + + transform : 'identity' or 'normalize', optional (default='identity') + The following transformations are supported. + + - 'identity', the transformed space is the same as the + original space. + - 'normalize', the transformed space is scaled to be between + 0 and 1. + """ + def __init__(self, low, high, prior="uniform", transform=None): self.low = low self.high = high self.prior = prior @@ -244,14 +244,14 @@ def transformed_bounds(self): return np.log10(self.low), np.log10(self.high) def distance(self, a, b): - """Compute distance between point `a` and `b`. + """Compute distance between point ``a`` and ``b``. Parameters ---------- - * `a` [float] + a : float First point. - * `b` [float] + b : float Second point. """ if not (a in self and b in self): @@ -261,25 +261,25 @@ def distance(self, a, b): class Integer(Dimension): - def __init__(self, low, high, transform=None): - """Search space dimension that can take on integer values. + """Search space dimension that can take on integer values. - Parameters - ---------- - * `low` [int]: - Lower bound (inclusive). + Parameters + ---------- + low : int + Lower bound (inclusive). - * `high` [int]: - Upper bound (inclusive). + high : int + Upper bound (inclusive). - * `transform` ["identity", "normalize", optional]: - The following transformations are supported. + transform : 'identity' or 'normalize', optional (default='identity') + The following transformations are supported. - - "identity", (default) the transformed space is the same as the - original space. - - "normalize", the transformed space is scaled to be between - 0 and 1. - """ + - "identity", the transformed space is the same as the + original space. + - "normalize", the transformed space is scaled to be between + 0 and 1. + """ + def __init__(self, low, high, transform=None): self.low = low self.high = high @@ -329,14 +329,14 @@ def transformed_bounds(self): return (self.low, self.high) def distance(self, a, b): - """Compute distance between point `a` and `b`. + """Compute distance between point ``a`` and ``b``. Parameters ---------- - * `a` [int] + a : float First point. - * `b` [int] + b : float Second point. """ if not (a in self and b in self): @@ -346,24 +346,24 @@ def distance(self, a, b): class Categorical(Dimension): - def __init__(self, categories, prior=None, transform=None): - """Search space dimension that can take on categorical values. + """Search space dimension that can take on categorical values. - Parameters - ---------- - * `categories` [list, shape=(n_categories,)]: - Sequence of possible categories. - - * `prior` [list, shape=(categories,), default=None]: - Prior probabilities for each category. By default all categories - are equally likely. - - * `transform` ["onehot", "identity", default="onehot"] : - - "identity", the transformed space is the same as the original - space. - - "onehot", the transformed space is a one-hot encoded - representation of the original space. - """ + Parameters + ---------- + categories : list, shape=[n_categories] + Sequence of possible categories. + + prior : list, shape=[categories], optional (default=None) + Prior probabilities for each category. By default all categories + are equally likely. + + transform : 'onehot' or 'identity', optional (default='onehot') + - 'identity', the transformed space is the same as the original + space. + - 'onehot', the transformed space is a one-hot encoded + representation of the original space. + """ + def __init__(self, categories, prior=None, transform=None): self.categories = categories if transform is None: @@ -440,17 +440,17 @@ def transformed_bounds(self): return [(0.0, 1.0) for i in range(self.transformed_size)] def distance(self, a, b): - """Compute distance between category `a` and `b`. + """Compute distance between category ``a`` and ``b``. As categories have no order the distance between two points is one if a != b and zero otherwise. Parameters ---------- - * `a` [category] + a : category First category. - * `b` [category] + b : category Second category. """ if not (a in self and b in self): @@ -460,28 +460,27 @@ def distance(self, a, b): class Space(object): - """Search space.""" + """Search space - def __init__(self, dimensions): - """Initialize a search space from given specifications. + Parameters + ---------- + dimensions : list, shape=[n_dims] + List of search space dimensions. + Each search dimension can be defined either as - Parameters - ---------- - * `dimensions` [list, shape=(n_dims,)]: - List of search space dimensions. - Each search dimension can be defined either as - - - a `(lower_bound, upper_bound)` tuple (for `Real` or `Integer` - dimensions), - - a `(lower_bound, upper_bound, "prior")` tuple (for `Real` - dimensions), - - as a list of categories (for `Categorical` dimensions), or - - an instance of a `Dimension` object (`Real`, `Integer` or - `Categorical`). - - NOTE: The upper and lower bounds are inclusive for `Integer` - dimensions. - """ + - a ``(lower_bound, upper_bound)`` tuple (for ``Real`` or ``Integer`` + dimensions), + - a ``(lower_bound, upper_bound, 'prior')`` tuple (for ``Real`` + dimensions), + - as a list of categories (for ``Categorical`` dimensions), or + - an instance of a ``Dimension`` object (``Real``, ``Integer`` or + ``Categorical``). + + NOTE: The upper and lower bounds are inclusive for ``Integer`` + dimensions. + """ + + def __init__(self, dimensions): self.dimensions = [check_dimension(dim) for dim in dimensions] def __eq__(self, other): @@ -508,20 +507,20 @@ def rvs(self, n_samples=1, random_state=None): """Draw random samples. The samples are in the original space. They need to be transformed - before being passed to a model or minimizer by `space.transform()`. + before being passed to a model or minimizer by ``space.transform()``. Parameters ---------- - * `n_samples` [int, default=1]: + n_samples : int, optional (default=1) Number of samples to be drawn from the space. - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set random state to something other than None for reproducible results. Returns ------- - * `points`: [list of lists, shape=(n_points, n_dims)] + points : list of lists, shape=[n_points, n_dims] Points sampled from the space. """ rng = check_random_state(random_state) @@ -555,12 +554,12 @@ def transform(self, X): Parameters ---------- - * `X` [list of lists, shape=(n_samples, n_dims)]: + X : list of lists, shape=[n_samples, n_dims] The samples to transform. Returns ------- - * `Xt` [array of floats, shape=(n_samples, transformed_n_dims)] + Xt : array of floats, shape=[n_samples, transformed_n_dims] The transformed samples. """ # Pack by dimension @@ -587,12 +586,12 @@ def inverse_transform(self, Xt): Parameters ---------- - * `Xt` [array of floats, shape=(n_samples, transformed_n_dims)]: + Xt : array of floats, shape=[n_samples, transformed_n_dims] The samples to inverse transform. Returns ------- - * `X` [list of lists, shape=(n_samples, n_dims)] + X : list of lists, shape=[n_samples, n_dims] The original samples. """ # Inverse transform @@ -647,7 +646,7 @@ def bounds(self): return b def __contains__(self, point): - """Check that `point` is within the bounds of the space.""" + """Check that ``point`` is within the bounds of the space.""" for component, dim in zip(point, self.dimensions): if component not in dim: return False @@ -675,10 +674,10 @@ def distance(self, point_a, point_b): Parameters ---------- - * `a` [array] + a : array First point. - * `b` [array] + `b : array Second point. """ distance = 0. diff --git a/skopt/utils.py b/skopt/utils.py index fb19476..cadeb61 100644 --- a/skopt/utils.py +++ b/skopt/utils.py @@ -1,3 +1,6 @@ +""" +The :mod:`skopt.utils` module includes various utilities. +""" from copy import deepcopy import numpy as np @@ -19,11 +22,6 @@ from .space import check_dimension from .space import Categorical -__all__ = ( - "load", - "dump", -) - def create_result(Xi, yi, space=None, rng=None, specs=None, models=None): """