diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..e7ae4a3 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,38 @@ +version: 2 + +jobs: + build: + docker: + - image: circleci/python:3.10.0a7 + working_directory: ~/repo + steps: + - checkout + - run: + name: install dependencies + command: | + wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh + chmod +x miniconda.sh && ./miniconda.sh -b -p ~/miniconda + export PATH="~/miniconda/bin:$PATH" + conda update --yes --quiet conda + conda create -n testenv --yes --quiet python=3 + source activate testenv + conda install --yes pip numpy scipy scikit-learn matplotlib sphinx sphinx_rtd_theme numpydoc pillow + pip install sphinx-gallery + pip install . + cd doc + make html + - store_artifacts: + path: doc/_build/html/ + destination: doc + - store_artifacts: + path: ~/log.txt + - run: ls -ltrh doc/_build/html + filters: + branches: + ignore: gh-pages + +workflows: + version: 2 + workflow: + jobs: + - build diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..8b87660 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,21 @@ +# Configuration for coverage.py + +[run] +branch = True +source = bayesclass +include = */bayesclass/* +omit = + */setup.py + +[report] +exclude_lines = + pragma: no cover + def __repr__ + if self.debug: + if settings.DEBUG + raise AssertionError + raise NotImplementedError + if 0: + if __name__ == .__main__.: + if self.verbose: +show_missing = True \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e8b96e7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,67 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# scikit-learn specific +doc/_build/ +doc/auto_examples/ +doc/modules/generated/ +doc/datasets/generated/ + +# Distribution / packaging + +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +doc/_build/ +doc/generated/ + +# PyBuilder +target/ diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..228fc8a --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,8 @@ +formats: + - none +requirements_file: requirements.txt +python: + pip_install: true + extra_requirements: + - tests + - docs diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..91121d4 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,50 @@ +dist: trusty +sudo: false + +language: python + +cache: + directories: + - $HOME/.cache/pip + +matrix: + include: + - env: PYTHON_VERSION="3.5" NUMPY_VERSION="1.13.1" SCIPY_VERSION="0.19.1" + SKLEARN_VERSION="0.19.1" + - env: PYTHON_VERSION="3.6" NUMPY_VERSION="1.13.1" SCIPY_VERSION="0.19.1" + SKLEARN_VERSION="0.20.3" + - env: PYTHON_VERSION="3.7" NUMPY_VERSION="*" SCIPY_VERSION="*" + SKLEARN_VERSION="*" + - env: PYTHON_VERSION="3.7" NUMPY_VERSION="*" SCIPY_VERSION="*" + SKLEARN_VERSION="nightly" + +install: + # install miniconda + - deactivate + - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh + - MINICONDA_PATH=/home/travis/miniconda + - chmod +x miniconda.sh && ./miniconda.sh -b -p $MINICONDA_PATH + - export PATH=$MINICONDA_PATH/bin:$PATH + - conda update --yes conda + # create the testing environment + - conda create -n testenv --yes python=$PYTHON_VERSION pip + - source activate testenv + - | + if [ $SKLEARN_VERSION = "nightly" ]; then + conda install --yes -c conda-forge numpy==$NUMPY_VERSION scipy==$SCIPY_VERSION + # install nightly wheels + pip install --pre -f https://sklearn-nightly.scdn8.secure.raxcdn.com scikit-learn + else + conda install --yes -c conda-forge numpy==$NUMPY_VERSION scipy==$SCIPY_VERSION scikit-learn==$SKLEARN_VERSION + fi + - pip install codecov cython nose pytest pytest-cov + - pip install . + +script: + - pytest -v doc/*rst + - mkdir for_test + - cd for_test + - pytest -v --cov=bayesclass --pyargs bayesclass + +after_success: + - codecov diff --git a/LICENSE b/LICENSE index 9508008..dc81eb4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Doctorado-ML +Copyright (c) 2020-2022, Ricardo Montañana Gómez Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..f9bd145 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include requirements.txt diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..0c104e1 --- /dev/null +++ b/README.rst @@ -0,0 +1,38 @@ +.. -*- mode: rst -*- + +|Travis|_ |AppVeyor|_ |Codecov|_ |CircleCI|_ |ReadTheDocs|_ + +.. |Travis| image:: https://travis-ci.org/scikit-learn-contrib/project-template.svg?branch=master +.. _Travis: https://travis-ci.org/scikit-learn-contrib/project-template + +.. |AppVeyor| image:: https://ci.appveyor.com/api/projects/status/coy2qqaqr1rnnt5y/branch/master?svg=true +.. _AppVeyor: https://ci.appveyor.com/project/glemaitre/project-template + +.. |Codecov| image:: https://codecov.io/gh/scikit-learn-contrib/project-template/branch/master/graph/badge.svg +.. _Codecov: https://codecov.io/gh/scikit-learn-contrib/project-template + +.. |CircleCI| image:: https://circleci.com/gh/scikit-learn-contrib/project-template.svg?style=shield&circle-token=:circle-token +.. _CircleCI: https://circleci.com/gh/scikit-learn-contrib/project-template/tree/master + +.. |ReadTheDocs| image:: https://readthedocs.org/projects/sklearn-template/badge/?version=latest +.. _ReadTheDocs: https://sklearn-template.readthedocs.io/en/latest/?badge=latest + +project-template - A template for scikit-learn contributions +============================================================ + +.. _scikit-learn: https://scikit-learn.org + +**project-template** is a template project for scikit-learn_ compatible +extensions. + +It aids development of estimators that can be used in scikit-learn pipelines +and (hyper)parameter search, while facilitating testing (including some API +compliance), documentation, open source development, packaging, and continuous +integration. + +.. _documentation: https://sklearn-template.readthedocs.io/en/latest/quick_start.html + +Refer to the documentation_ to modify the template for your own scikit-learn +contribution. + +*Thank you for cleanly contributing to the scikit-learn ecosystem!* diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..cd43aaf --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,37 @@ +build: false + +environment: + matrix: + - PYTHON: "C:\\Miniconda3-x64" + PYTHON_VERSION: "3.5.x" + PYTHON_ARCH: "32" + NUMPY_VERSION: "1.13.1" + SCIPY_VERSION: "0.19.1" + SKLEARN_VERSION: "0.19.1" + + - PYTHON: "C:\\Miniconda3-x64" + PYTHON_VERSION: "3.6.x" + PYTHON_ARCH: "64" + NUMPY_VERSION: "*" + SCIPY_VERSION: "*" + SKLEARN_VERSION: "*" + +install: + # Prepend miniconda installed Python to the PATH of this build + # Add Library/bin directory to fix issue + # https://github.com/conda/conda/issues/1753 + - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PYTHON%\\Library\\bin;%PATH%" + # install the dependencies + - "conda install --yes -c conda-forge pip numpy==%NUMPY_VERSION% scipy==%SCIPY_VERSION% scikit-learn==%SKLEARN_VERSION%" + - pip install codecov nose pytest pytest-cov + - pip install . + +test_script: + - mkdir for_test + - cd for_test + - pytest -v --cov=bayesclass --pyargs bayesclass + +after_test: + - cp .coverage %APPVEYOR_BUILD_FOLDER% + - cd %APPVEYOR_BUILD_FOLDER% + - codecov diff --git a/bayesclass/__init__.py b/bayesclass/__init__.py new file mode 100644 index 0000000..ef01882 --- /dev/null +++ b/bayesclass/__init__.py @@ -0,0 +1,5 @@ +from ._estimators import TAN + +from ._version import __version__ + +__all__ = ["TAN", "__version__"] diff --git a/bayesclass/_estimators.py b/bayesclass/_estimators.py new file mode 100644 index 0000000..7bfed44 --- /dev/null +++ b/bayesclass/_estimators.py @@ -0,0 +1,136 @@ +""" +This is a module to be used as a reference for building other modules +""" +import numpy as np +from sklearn.base import ClassifierMixin, BaseEstimator +from sklearn.utils.validation import check_X_y, check_array, check_is_fitted +from sklearn.utils.multiclass import unique_labels + +import networkx as nx +import pandas as pd +import matplotlib.pyplot as plt +from pgmpy.models import BayesianNetwork +from benchmark import Datasets + + +class TAN(ClassifierMixin, BaseEstimator): + """An example classifier which implements a 1-NN algorithm. + For more information regarding how to build your own classifier, read more + in the :ref:`User Guide `. + Parameters + ---------- + demo_param : str, default='demo' + A parameter used for demonstation of how to pass and store paramters. + Attributes + ---------- + X_ : ndarray, shape (n_samples, n_features) + The input passed during :meth:`fit`. + y_ : ndarray, shape (n_samples,) + The labels passed during :meth:`fit`. + classes_ : ndarray, shape (n_classes,) + The classes seen at :meth:`fit`. + """ + + def __init__(self, demo_param="demo"): + self.demo_param = demo_param + + def fit(self, X, y): + """A reference implementation of a fitting function for a classifier. + Parameters + ---------- + X : array-like, shape (n_samples, n_features) + The training input samples. + y : array-like, shape (n_samples,) + The target values. An array of int. + Returns + ------- + self : object + Returns self. + """ + # Check that X and y have correct shape + X, y = check_X_y(X, y) + # Store the classes seen during fit + self.classes_ = unique_labels(y) + + self.X_ = X + self.y_ = y + self.__train() + # Return the classifier + return self + + def __train(self): + dt = Datasets() + data = dt.load("balance-scale", dataframe=True) + features = dt.dataset.features + class_name = dt.dataset.class_name + factorization, class_factors = pd.factorize(data[class_name]) + data[class_name] = factorization + data.head() + net = [(class_name, feature) for feature in features] + model = BayesianNetwork(net) + # 1st feature correlates with other features + first_node = features[0] + edges2 = [ + (first_node, feature) + for feature in features + if feature != first_node + ] + edges = [] + for i in range(len(features)): + for j in range(i + 1, len(features)): + edges.append((features[i], features[j])) + print(edges2) + model.add_edges_from(edges2) + nx.draw_circular( + model, + with_labels=True, + arrowsize=30, + node_size=800, + alpha=0.3, + font_weight="bold", + ) + plt.show() + discretiz = MDLP() + Xdisc = discretiz.fit_transform( + data[features].to_numpy(), data[class_name].to_numpy() + ) + features_discretized = pd.DataFrame(Xdisc, columns=features) + dataset_discretized = features_discretized.copy() + dataset_discretized[class_name] = data[class_name] + dataset_discretized + model.fit(dataset_discretized) + from pgmpy.estimators import TreeSearch + + # learn graph structure + est = TreeSearch(dataset_discretized, root_node=first_node) + dag = est.estimate(estimator_type="tan", class_node=class_name) + nx.draw_circular( + dag, + with_labels=True, + arrowsize=30, + node_size=800, + alpha=0.3, + font_weight="bold", + ) + plt.show() + + def predict(self, X): + """A reference implementation of a prediction for a classifier. + Parameters + ---------- + X : array-like, shape (n_samples, n_features) + The input samples. + Returns + ------- + y : ndarray, shape (n_samples,) + The label for each sample is the label of the closest sample + seen during fit. + """ + # Check is fit had been called + check_is_fitted(self, ["X_", "y_"]) + + # Input validation + X = check_array(X) + + closest = np.argmin(euclidean_distances(X, self.X_), axis=1) + return self.y_[closest] diff --git a/bayesclass/_version.py b/bayesclass/_version.py new file mode 100644 index 0000000..f102a9c --- /dev/null +++ b/bayesclass/_version.py @@ -0,0 +1 @@ +__version__ = "0.0.1" diff --git a/bayesclass/tests/__init__.py b/bayesclass/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bayesclass/tests/test_common.py b/bayesclass/tests/test_common.py new file mode 100644 index 0000000..f4def3e --- /dev/null +++ b/bayesclass/tests/test_common.py @@ -0,0 +1,14 @@ +import pytest + +from sklearn.utils.estimator_checks import check_estimator + +from bayesclass import TemplateEstimator +from bayesclass import TemplateClassifier +from bayesclass import TemplateTransformer + + +@pytest.mark.parametrize( + "estimator", [TemplateEstimator(), TemplateTransformer(), TemplateClassifier()] +) +def test_all_estimators(estimator): + return check_estimator(estimator) diff --git a/bayesclass/tests/test_template.py b/bayesclass/tests/test_template.py new file mode 100644 index 0000000..f701229 --- /dev/null +++ b/bayesclass/tests/test_template.py @@ -0,0 +1,65 @@ +import pytest +import numpy as np + +from sklearn.datasets import load_iris +from numpy.testing import assert_array_equal +from numpy.testing import assert_allclose + +from bayesclass import TemplateEstimator +from bayesclass import TemplateTransformer +from bayesclass import TemplateClassifier + + +@pytest.fixture +def data(): + return load_iris(return_X_y=True) + + +def test_template_estimator(data): + est = TemplateEstimator() + assert est.demo_param == "demo_param" + + est.fit(*data) + assert hasattr(est, "is_fitted_") + + X = data[0] + y_pred = est.predict(X) + assert_array_equal(y_pred, np.ones(X.shape[0], dtype=np.int64)) + + +def test_template_transformer_error(data): + X, y = data + trans = TemplateTransformer() + trans.fit(X) + with pytest.raises(ValueError, match="Shape of input is different"): + X_diff_size = np.ones((10, X.shape[1] + 1)) + trans.transform(X_diff_size) + + +def test_template_transformer(data): + X, y = data + trans = TemplateTransformer() + assert trans.demo_param == "demo" + + trans.fit(X) + assert trans.n_features_ == X.shape[1] + + X_trans = trans.transform(X) + assert_allclose(X_trans, np.sqrt(X)) + + X_trans = trans.fit_transform(X) + assert_allclose(X_trans, np.sqrt(X)) + + +def test_template_classifier(data): + X, y = data + clf = TemplateClassifier() + assert clf.demo_param == "demo" + + clf.fit(X, y) + assert hasattr(clf, "classes_") + assert hasattr(clf, "X_") + assert hasattr(clf, "y_") + + y_pred = clf.predict(X) + assert y_pred.shape == (X.shape[0],) diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..508376e --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,184 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + -rm -rf auto_examples/ + -rm -rf generated/* + -rm -rf modules/generated/* + +html: + # These two lines make the build a bit more lengthy, and the + # the embedding of images more robust + rm -rf $(BUILDDIR)/html/_images + #rm -rf _build/doctrees/ + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/project-template.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/project-template.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/project-template" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/project-template" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/doc/_static/css/project-template.css b/doc/_static/css/project-template.css new file mode 100644 index 0000000..f6caff2 --- /dev/null +++ b/doc/_static/css/project-template.css @@ -0,0 +1,16 @@ +@import url("theme.css"); + +.highlight a { + text-decoration: underline; +} + +.deprecated p { + padding: 10px 7px 10px 10px; + color: #b94a48; + background-color: #F3E5E5; + border: 1px solid #eed3d7; +} + +.deprecated p span.versionmodified { + font-weight: bold; +} diff --git a/doc/_static/js/copybutton.js b/doc/_static/js/copybutton.js new file mode 100644 index 0000000..d87f569 --- /dev/null +++ b/doc/_static/js/copybutton.js @@ -0,0 +1,63 @@ +$(document).ready(function() { + /* Add a [>>>] button on the top-right corner of code samples to hide + * the >>> and ... prompts and the output and thus make the code + * copyable. */ + var div = $('.highlight-python .highlight,' + + '.highlight-python3 .highlight,' + + '.highlight-pycon .highlight,' + + '.highlight-default .highlight') + var pre = div.find('pre'); + + // get the styles from the current theme + pre.parent().parent().css('position', 'relative'); + var hide_text = 'Hide the prompts and output'; + var show_text = 'Show the prompts and output'; + var border_width = pre.css('border-top-width'); + var border_style = pre.css('border-top-style'); + var border_color = pre.css('border-top-color'); + var button_styles = { + 'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0', + 'border-color': border_color, 'border-style': border_style, + 'border-width': border_width, 'color': border_color, 'text-size': '75%', + 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em', + 'border-radius': '0 3px 0 0' + } + + // create and add the button to all the code blocks that contain >>> + div.each(function(index) { + var jthis = $(this); + if (jthis.find('.gp').length > 0) { + var button = $('>>>'); + button.css(button_styles) + button.attr('title', hide_text); + button.data('hidden', 'false'); + jthis.prepend(button); + } + // tracebacks (.gt) contain bare text elements that need to be + // wrapped in a span to work with .nextUntil() (see later) + jthis.find('pre:has(.gt)').contents().filter(function() { + return ((this.nodeType == 3) && (this.data.trim().length > 0)); + }).wrap(''); + }); + + // define the behavior of the button when it's clicked + $('.copybutton').click(function(e){ + e.preventDefault(); + var button = $(this); + if (button.data('hidden') === 'false') { + // hide the code output + button.parent().find('.go, .gp, .gt').hide(); + button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden'); + button.css('text-decoration', 'line-through'); + button.attr('title', show_text); + button.data('hidden', 'true'); + } else { + // show the code output + button.parent().find('.go, .gp, .gt').show(); + button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible'); + button.css('text-decoration', 'none'); + button.attr('title', hide_text); + button.data('hidden', 'false'); + } + }); +}); diff --git a/doc/_templates/class.rst b/doc/_templates/class.rst new file mode 100644 index 0000000..30c38f6 --- /dev/null +++ b/doc/_templates/class.rst @@ -0,0 +1,17 @@ +:mod:`{{module}}`.{{objname}} +{{ underline }}============== + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + :members: + + {% block methods %} + .. automethod:: __init__ + {% endblock %} + +.. include:: {{module}}.{{objname}}.examples + +.. raw:: html + +
diff --git a/doc/_templates/function.rst b/doc/_templates/function.rst new file mode 100644 index 0000000..4ba355d --- /dev/null +++ b/doc/_templates/function.rst @@ -0,0 +1,12 @@ +:mod:`{{module}}`.{{objname}} +{{ underline }}==================== + +.. currentmodule:: {{ module }} + +.. autofunction:: {{ objname }} + +.. include:: {{module}}.{{objname}}.examples + +.. raw:: html + +
diff --git a/doc/_templates/numpydoc_docstring.py b/doc/_templates/numpydoc_docstring.py new file mode 100644 index 0000000..fd6a35f --- /dev/null +++ b/doc/_templates/numpydoc_docstring.py @@ -0,0 +1,16 @@ +{{index}} +{{summary}} +{{extended_summary}} +{{parameters}} +{{returns}} +{{yields}} +{{other_parameters}} +{{attributes}} +{{raises}} +{{warns}} +{{warnings}} +{{see_also}} +{{notes}} +{{references}} +{{examples}} +{{methods}} diff --git a/doc/api.rst b/doc/api.rst new file mode 100644 index 0000000..c8017bc --- /dev/null +++ b/doc/api.rst @@ -0,0 +1,34 @@ +#################### +project-template API +#################### + +This is an example on how to document the API of your own project. + +.. currentmodule:: bayesclass + +Estimator +========= + +.. autosummary:: + :toctree: generated/ + :template: class.rst + + TemplateEstimator + +Transformer +=========== + +.. autosummary:: + :toctree: generated/ + :template: class.rst + + TemplateTransformer + +Predictor +========= + +.. autosummary:: + :toctree: generated/ + :template: class.rst + + TemplateClassifier diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..6af29ef --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,335 @@ +# -*- coding: utf-8 -*- +# +# project-template documentation build configuration file, created by +# sphinx-quickstart on Mon Jan 18 14:44:12 2016. +# +# 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. + +import sys +import os + +import sphinx_gallery +import sphinx_rtd_theme + +# Add to sys.path the top-level directory where the package is located. +sys.path.insert(0, os.path.abspath("..")) + +# 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. +# 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.doctest", + "sphinx.ext.intersphinx", + "sphinx.ext.viewcode", + "numpydoc", + "sphinx_gallery.gen_gallery", +] + +# this is needed for some reason... +# see https://github.com/numpy/numpydoc/issues/69 +numpydoc_show_class_members = False + +# pngmath / imgmath compatibility layer for different sphinx versions +import sphinx +from distutils.version import LooseVersion + +if LooseVersion(sphinx.__version__) < LooseVersion("1.4"): + extensions.append("sphinx.ext.pngmath") +else: + extensions.append("sphinx.ext.imgmath") + +autodoc_default_flags = ["members", "inherited-members"] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# generate autosummary even if no references +autosummary_generate = True + +# The suffix of source filenames. +source_suffix = ".rst" + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# Generate the plots for the gallery +plot_gallery = True + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "sklearn-template" +copyright = "2016, Vighnesh Birodkar" + +# 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. +from bayesclass import __version__ + +version = __version__ +# The full version, including alpha/beta/rc tags. +release = __version__ + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ["_build", "_templates"] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# Custom style +html_style = "css/project-template.css" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = 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 = "sphinx_rtd_theme" + +# 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 = {} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# 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"] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = "project-templatedoc" + + +# -- 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': '', +} + +# 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 = [ + ( + "index", + "project-template.tex", + "project-template Documentation", + "Vighnesh Birodkar", + "manual", + ), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( + "index", + "project-template", + "project-template Documentation", + ["Vighnesh Birodkar"], + 1, + ) +] + +# If true, show URL addresses after external links. +# man_show_urls = False + + +# -- 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 = [ + ( + "index", + "project-template", + "project-template Documentation", + "Vighnesh Birodkar", + "project-template", + "One line description of project.", + "Miscellaneous", + ), +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +# intersphinx configuration +intersphinx_mapping = { + "python": ("https://docs.python.org/{.major}".format(sys.version_info), None), + "numpy": ("https://docs.scipy.org/doc/numpy/", None), + "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), + "matplotlib": ("https://matplotlib.org/", None), + "sklearn": ("http://scikit-learn.org/stable", None), +} + +# sphinx-gallery configuration +sphinx_gallery_conf = { + "doc_module": "bayesclass", + "backreferences_dir": os.path.join("generated"), + "reference_url": {"bayesclass": None}, +} + + +def setup(app): + # a copy button to copy snippet of code from the documentation + app.add_javascript("js/copybutton.js") diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..ba235c8 --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,52 @@ +.. project-template documentation master file, created by + sphinx-quickstart on Mon Jan 18 14:44:12 2016. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to sklearn-template's documentation! +============================================ + +This project is a reference implementation to anyone who wishes to develop +scikit-learn compatible classes. + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Getting Started + + quick_start + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Documentation + + user_guide + api + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Tutorial - Examples + + auto_examples/index + +`Getting started `_ +------------------------------------- + +Information regarding this template and how to modify it for your own project. + +`User Guide `_ +------------------------------- + +An example of narrative documentation. + +`API Documentation `_ +------------------------------- + +An example of API documentation. + +`Examples `_ +-------------------------------------- + +A set of examples. It complements the `User Guide `_. \ No newline at end of file diff --git a/doc/make.bat b/doc/make.bat new file mode 100644 index 0000000..79c1e19 --- /dev/null +++ b/doc/make.bat @@ -0,0 +1,242 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\project-template.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\project-template.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/doc/quick_start.rst b/doc/quick_start.rst new file mode 100644 index 0000000..a1afae5 --- /dev/null +++ b/doc/quick_start.rst @@ -0,0 +1,131 @@ +##################################### +Quick Start with the project-template +##################################### + +This package serves as a skeleton package aiding at developing compatible +scikit-learn contribution. + +Creating your own scikit-learn contribution package +=================================================== + +1. Download and setup your repository +------------------------------------- + +To create your package, you need to clone the ``project-template`` repository:: + + $ git clone https://github.com/scikit-learn-contrib/project-template.git + +Before to reinitialize your git repository, you need to make the following +changes. Replace all occurrences of ``bayesclass`` and ``sklearn-template`` +with the name of you own contribution. You can find all the occurrences using +the following command:: + + $ git grep bayesclass + $ git grep sklearn-template + +To remove the history of the template package, you need to remove the `.git` +directory:: + + $ cd project-template + $ rm -rf .git + +Then, you need to initialize your new git repository:: + + $ git init + $ git add . + $ git commit -m 'Initial commit' + +Finally, you create an online repository on GitHub and push your code online:: + + $ git remote add origin https://github.com/your_remote/your_contribution.git + $ git push origin master + +2. Develop your own scikit-learn estimators +------------------------------------------- + +.. _check_estimator: http://scikit-learn.org/stable/modules/generated/sklearn.utils.estimator_checks.check_estimator.html#sklearn.utils.estimator_checks.check_estimator +.. _`Contributor's Guide`: http://scikit-learn.org/stable/developers/ +.. _PEP8: https://www.python.org/dev/peps/pep-0008/ +.. _PEP257: https://www.python.org/dev/peps/pep-0257/ +.. _NumPyDoc: https://github.com/numpy/numpydoc +.. _doctests: https://docs.python.org/3/library/doctest.html + +You can modify the source files as you want. However, your custom estimators +need to pass the check_estimator_ test to be scikit-learn compatible. You can +refer to the :ref:`User Guide ` to help you create a compatible +scikit-learn estimator. + +In any case, developers should endeavor to adhere to scikit-learn's +`Contributor's Guide`_ which promotes the use of: + +* algorithm-specific unit tests, in addition to ``check_estimator``'s common + tests; +* PEP8_-compliant code; +* a clearly documented API using NumpyDoc_ and PEP257_-compliant docstrings; +* references to relevant scientific literature in standard citation formats; +* doctests_ to provide succinct usage examples; +* standalone examples to illustrate the usage, model visualisation, and + benefits/benchmarks of particular algorithms; +* efficient code when the need for optimization is supported by benchmarks. + +3. Edit the documentation +------------------------- + +.. _Sphinx: http://www.sphinx-doc.org/en/stable/ + +The documentation is created using Sphinx_. In addition, the examples are +created using ``sphinx-gallery``. Therefore, to generate locally the +documentation, you are required to install the following packages:: + + $ pip install sphinx sphinx-gallery sphinx_rtd_theme matplotlib numpydoc pillow + +The documentation is made of: + +* a home page, ``doc/index.rst``; +* an API documentation, ``doc/api.rst`` in which you should add all public + objects for which the docstring should be exposed publicly. +* a User Guide documentation, ``doc/user_guide.rst``, containing the narrative + documentation of your package, to give as much intuition as possible to your + users. +* examples which are created in the `examples/` folder. Each example + illustrates some usage of the package. the example file name should start by + `plot_*.py`. + +The documentation is built with the following commands:: + + $ cd doc + $ make html + +4. Setup the continuous integration +----------------------------------- + +The project template already contains configuration files of the continuous +integration system. Basically, the following systems are set: + +* Travis CI is used to test the package in Linux. You need to activate Travis + CI for your own repository. Refer to the Travis CI documentation. +* AppVeyor is used to test the package in Windows. You need to activate + AppVeyor for your own repository. Refer to the AppVeyor documentation. +* Circle CI is used to check if the documentation is generated properly. You + need to activate Circle CI for your own repository. Refer to the Circle CI + documentation. +* ReadTheDocs is used to build and host the documentation. You need to activate + ReadTheDocs for your own repository. Refer to the ReadTheDocs documentation. +* CodeCov for tracking the code coverage of the package. You need to activate + CodeCov for you own repository. +* PEP8Speaks for automatically checking the PEP8 compliance of your project for + each Pull Request. + +Publish your package +==================== + +.. _PyPi: https://packaging.python.org/tutorials/packaging-projects/ +.. _conda-foge: https://conda-forge.org/ + +You can make your package available through PyPi_ and conda-forge_. Refer to +the associated documentation to be able to upload your packages such that +it will be installable with ``pip`` and ``conda``. Once published, it will +be possible to install your package with the following commands:: + + $ pip install your-scikit-learn-contribution + $ conda install -c conda-forge your-scikit-learn-contribution diff --git a/doc/user_guide.rst b/doc/user_guide.rst new file mode 100644 index 0000000..4cceb7f --- /dev/null +++ b/doc/user_guide.rst @@ -0,0 +1,180 @@ +.. title:: User guide : contents + +.. _user_guide: + +================================================== +User guide: create your own scikit-learn estimator +================================================== + +Estimator +--------- + +The central piece of transformer, regressor, and classifier is +:class:`sklearn.base.BaseEstimator`. All estimators in scikit-learn are derived +from this class. In more details, this base class enables to set and get +parameters of the estimator. It can be imported as:: + + >>> from sklearn.base import BaseEstimator + +Once imported, you can create a class which inherate from this base class:: + + >>> class MyOwnEstimator(BaseEstimator): + ... pass + +Transformer +----------- + +Transformers are scikit-learn estimators which implement a ``transform`` method. +The use case is the following: + +* at ``fit``, some parameters can be learned from ``X`` and ``y``; +* at ``transform``, `X` will be transformed, using the parameters learned + during ``fit``. + +.. _mixin: https://en.wikipedia.org/wiki/Mixin + +In addition, scikit-learn provides a +mixin_, i.e. :class:`sklearn.base.TransformerMixin`, which +implement the combination of ``fit`` and ``transform`` called ``fit_transform``:: + +One can import the mixin class as:: + + >>> from sklearn.base import TransformerMixin + +Therefore, when creating a transformer, you need to create a class which +inherits from both :class:`sklearn.base.BaseEstimator` and +:class:`sklearn.base.TransformerMixin`. The scikit-learn API imposed ``fit`` to +**return ``self``**. The reason is that it allows to pipeline ``fit`` and +``transform`` imposed by the :class:`sklearn.base.TransformerMixin`. The +``fit`` method is expected to have ``X`` and ``y`` as inputs. Note that +``transform`` takes only ``X`` as input and is expected to return the +transformed version of ``X``:: + + >>> class MyOwnTransformer(BaseEstimator, TransformerMixin): + ... def fit(self, X, y=None): + ... return self + ... def transform(self, X): + ... return X + +We build a basic example to show that our :class:`MyOwnTransformer` is working +within a scikit-learn ``pipeline``:: + + >>> from sklearn.datasets import load_iris + >>> from sklearn.pipeline import make_pipeline + >>> from sklearn.linear_model import LogisticRegression + >>> X, y = load_iris(return_X_y=True) + >>> pipe = make_pipeline(MyOwnTransformer(), + ... LogisticRegression(random_state=10, + ... solver='lbfgs')) + >>> pipe.fit(X, y) # doctest: +ELLIPSIS + Pipeline(...) + >>> pipe.predict(X) # doctest: +ELLIPSIS + array([...]) + +Predictor +--------- + +Regressor +~~~~~~~~~ + +Similarly, regressors are scikit-learn estimators which implement a ``predict`` +method. The use case is the following: + +* at ``fit``, some parameters can be learned from ``X`` and ``y``; +* at ``predict``, predictions will be computed using ``X`` using the parameters + learned during ``fit``. + +In addition, scikit-learn provides a mixin_, i.e. +:class:`sklearn.base.RegressorMixin`, which implements the ``score`` method +which computes the :math:`R^2` score of the predictions. + +One can import the mixin as:: + + >>> from sklearn.base import RegressorMixin + +Therefore, we create a regressor, :class:`MyOwnRegressor` which inherits from +both :class:`sklearn.base.BaseEstimator` and +:class:`sklearn.base.RegressorMixin`. The method ``fit`` gets ``X`` and ``y`` +as input and should return ``self``. It should implement the ``predict`` +function which should output the predictions of your regressor:: + + >>> import numpy as np + >>> class MyOwnRegressor(BaseEstimator, RegressorMixin): + ... def fit(self, X, y): + ... return self + ... def predict(self, X): + ... return np.mean(X, axis=1) + +We illustrate that this regressor is working within a scikit-learn pipeline:: + + >>> from sklearn.datasets import load_diabetes + >>> X, y = load_diabetes(return_X_y=True) + >>> pipe = make_pipeline(MyOwnTransformer(), MyOwnRegressor()) + >>> pipe.fit(X, y) # doctest: +ELLIPSIS + Pipeline(...) + >>> pipe.predict(X) # doctest: +ELLIPSIS + array([...]) + +Since we inherit from the :class:`sklearn.base.RegressorMixin`, we can call +the ``score`` method which will return the :math:`R^2` score:: + + >>> pipe.score(X, y) # doctest: +ELLIPSIS + -3.9... + +Classifier +~~~~~~~~~~ + +Similarly to regressors, classifiers implement ``predict``. In addition, they +output the probabilities of the prediction using the ``predict_proba`` method: + +* at ``fit``, some parameters can be learned from ``X`` and ``y``; +* at ``predict``, predictions will be computed using ``X`` using the parameters + learned during ``fit``. The output corresponds to the predicted class for each sample; +* ``predict_proba`` will give a 2D matrix where each column corresponds to the + class and each entry will be the probability of the associated class. + +In addition, scikit-learn provides a mixin, i.e. +:class:`sklearn.base.ClassifierMixin`, which implements the ``score`` method +which computes the accuracy score of the predictions. + +One can import this mixin as:: + + >>> from sklearn.base import ClassifierMixin + +Therefore, we create a classifier, :class:`MyOwnClassifier` which inherits +from both :class:`slearn.base.BaseEstimator` and +:class:`sklearn.base.ClassifierMixin`. The method ``fit`` gets ``X`` and ``y`` +as input and should return ``self``. It should implement the ``predict`` +function which should output the class inferred by the classifier. +``predict_proba`` will output some probabilities instead:: + + >>> class MyOwnClassifier(BaseEstimator, ClassifierMixin): + ... def fit(self, X, y): + ... self.classes_ = np.unique(y) + ... return self + ... def predict(self, X): + ... return np.random.randint(0, self.classes_.size, + ... size=X.shape[0]) + ... def predict_proba(self, X): + ... pred = np.random.rand(X.shape[0], self.classes_.size) + ... return pred / np.sum(pred, axis=1)[:, np.newaxis] + +We illustrate that this regressor is working within a scikit-learn pipeline:: + + >>> X, y = load_iris(return_X_y=True) + >>> pipe = make_pipeline(MyOwnTransformer(), MyOwnClassifier()) + >>> pipe.fit(X, y) # doctest: +ELLIPSIS + Pipeline(...) + +Then, you can call ``predict`` and ``predict_proba``:: + + >>> pipe.predict(X) # doctest: +ELLIPSIS + array([...]) + >>> pipe.predict_proba(X) # doctest: +ELLIPSIS + array([...]) + +Since our classifier inherits from :class:`sklearn.base.ClassifierMixin`, we +can compute the accuracy by calling the ``score`` method:: + + >>> pipe.score(X, y) # doctest: +ELLIPSIS + 0... diff --git a/environment.yml b/environment.yml new file mode 100644 index 0000000..50cfb2b --- /dev/null +++ b/environment.yml @@ -0,0 +1,6 @@ +name: bayesclass +dependencies: + - numpy + - scipy + - scikit-learn + - pgmpy diff --git a/examples/README.txt b/examples/README.txt new file mode 100644 index 0000000..a5d244b --- /dev/null +++ b/examples/README.txt @@ -0,0 +1,6 @@ +.. _general_examples: + +General examples +================ + +Introductory examples. diff --git a/examples/plot_classifier.py b/examples/plot_classifier.py new file mode 100644 index 0000000..9171882 --- /dev/null +++ b/examples/plot_classifier.py @@ -0,0 +1,44 @@ +""" +============================ +Plotting Template Classifier +============================ + +An example plot of :class:`bayesclass.template.TemplateClassifier` +""" +import numpy as np +from matplotlib import pyplot as plt +from bayesclass import TemplateClassifier + +X = [[0, 0], [1, 1]] +y = [0, 1] +clf = TemplateClassifier() +clf.fit(X, y) + +rng = np.random.RandomState(13) +X_test = rng.rand(500, 2) +y_pred = clf.predict(X_test) + +X_0 = X_test[y_pred == 0] +X_1 = X_test[y_pred == 1] + + +p0 = plt.scatter(0, 0, c="red", s=100) +p1 = plt.scatter(1, 1, c="blue", s=100) + +ax0 = plt.scatter(X_0[:, 0], X_0[:, 1], c="crimson", s=50) +ax1 = plt.scatter(X_1[:, 0], X_1[:, 1], c="deepskyblue", s=50) + +leg = plt.legend( + [p0, p1, ax0, ax1], + ["Point 0", "Point 1", "Class 0", "Class 1"], + loc="upper left", + fancybox=True, + scatterpoints=1, +) +leg.get_frame().set_alpha(0.5) + +plt.xlabel("Feature 1") +plt.ylabel("Feature 2") +plt.xlim([-0.5, 1.5]) + +plt.show() diff --git a/examples/plot_template.py b/examples/plot_template.py new file mode 100644 index 0000000..2384ddc --- /dev/null +++ b/examples/plot_template.py @@ -0,0 +1,17 @@ +""" +=========================== +Plotting Template Estimator +=========================== + +An example plot of :class:`bayesclass.template.TemplateEstimator` +""" +import numpy as np +from matplotlib import pyplot as plt +from bayesclass import TemplateEstimator + +X = np.arange(100).reshape(100, 1) +y = np.zeros((100,)) +estimator = TemplateEstimator() +estimator.fit(X, y) +plt.plot(estimator.predict(X)) +plt.show() diff --git a/examples/plot_transformer.py b/examples/plot_transformer.py new file mode 100644 index 0000000..7349bbd --- /dev/null +++ b/examples/plot_transformer.py @@ -0,0 +1,26 @@ +""" +============================= +Plotting Template Transformer +============================= + +An example plot of :class:`bayesclass.template.TemplateTransformer` +""" +import numpy as np +from matplotlib import pyplot as plt +from bayesclass import TemplateTransformer + +X = np.arange(50, dtype=np.float).reshape(-1, 1) +X /= 50 +estimator = TemplateTransformer() +X_transformed = estimator.fit_transform(X) + +plt.plot(X.flatten(), label="Original Data") +plt.plot(X_transformed.flatten(), label="Transformed Data") +plt.title("Plots of original and transformed data") + +plt.legend(loc="best") +plt.grid(True) +plt.xlabel("Index") +plt.ylabel("Value of Data") + +plt.show() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9bd6669 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[tool.black] +line-length = 79 +include = '\.pyi?$' +exclude = ''' +/( + \.git + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist +)/ +''' \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1ac3167 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +numpy +scipy +scikit-learn +pgmpy \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..a199e77 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,8 @@ +[metadata] +description-file = README.rst + +[aliases] +test = pytest + +[tool:pytest] +addopts = --doctest-modules diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..38fe5c8 --- /dev/null +++ b/setup.py @@ -0,0 +1,71 @@ +#! /usr/bin/env python +"""A collection of Bayesian Estimators.""" + +import codecs +import os + +from setuptools import find_packages, setup + +# get __version__ from _version.py +ver_file = os.path.join("bayesclass", "_version.py") +with open(ver_file) as f: + exec(f.read()) + +DISTNAME = "bayesclass" +DESCRIPTION = "A collection of Bayesian Estimators." +with codecs.open("README.rst", encoding="utf-8-sig") as f: + LONG_DESCRIPTION = f.read() +MAINTAINER = "Ricardo Montañana" +MAINTAINER_EMAIL = "rmontanana@gmail.com" +URL = "https://github.com/doctorado-ml/bayesclass" +LICENSE = "MIT" +DOWNLOAD_URL = "https://github.com/doctorado-ml/bayesclass" +VERSION = __version__ +INSTALL_REQUIRES = ["numpy", "scipy", "scikit-learn"] +CLASSIFIERS = [ + "Intended Audience :: Science/Research", + "Intended Audience :: Developers", + "License :: OSI Approved", + "Programming Language :: Python", + "Topic :: Software Development", + "Topic :: Scientific/Engineering", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: Unix", + "Operating System :: MacOS", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +EXTRAS_REQUIRE = { + "tests": ["pytest", "pytest-cov"], + "docs": [ + "sphinx", + "sphinx-gallery", + "sphinx_rtd_theme", + "numpydoc", + "matplotlib", + ], +} + +setup( + name=DISTNAME, + maintainer=MAINTAINER, + maintainer_email=MAINTAINER_EMAIL, + description=DESCRIPTION, + license=LICENSE, + url=URL, + version=VERSION, + download_url=DOWNLOAD_URL, + long_description=LONG_DESCRIPTION, + zip_safe=False, # the package can run out of an .egg file + classifiers=CLASSIFIERS, + packages=find_packages(), + install_requires=INSTALL_REQUIRES, + extras_require=EXTRAS_REQUIRE, +)