From 3689852205282644df179b3b27351f508fa9b4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Monta=C3=B1ana?= Date: Fri, 4 Nov 2022 11:53:06 +0100 Subject: [PATCH] Initial commit --- .circleci/config.yml | 38 +++ .coveragerc | 21 ++ .gitignore | 67 ++++++ .readthedocs.yml | 8 + .travis.yml | 50 ++++ LICENSE | 2 +- MANIFEST.in | 1 + README.rst | 38 +++ appveyor.yml | 37 +++ bayesclass/__init__.py | 5 + bayesclass/_estimators.py | 136 +++++++++++ bayesclass/_version.py | 1 + bayesclass/tests/__init__.py | 0 bayesclass/tests/test_common.py | 14 ++ bayesclass/tests/test_template.py | 65 ++++++ doc/Makefile | 184 +++++++++++++++ doc/_static/css/project-template.css | 16 ++ doc/_static/js/copybutton.js | 63 +++++ doc/_templates/class.rst | 17 ++ doc/_templates/function.rst | 12 + doc/_templates/numpydoc_docstring.py | 16 ++ doc/api.rst | 34 +++ doc/conf.py | 335 +++++++++++++++++++++++++++ doc/index.rst | 52 +++++ doc/make.bat | 242 +++++++++++++++++++ doc/quick_start.rst | 131 +++++++++++ doc/user_guide.rst | 180 ++++++++++++++ environment.yml | 6 + examples/README.txt | 6 + examples/plot_classifier.py | 44 ++++ examples/plot_template.py | 17 ++ examples/plot_transformer.py | 26 +++ pyproject.toml | 16 ++ requirements.txt | 4 + setup.cfg | 8 + setup.py | 71 ++++++ 36 files changed, 1962 insertions(+), 1 deletion(-) create mode 100644 .circleci/config.yml create mode 100644 .coveragerc create mode 100644 .gitignore create mode 100644 .readthedocs.yml create mode 100644 .travis.yml create mode 100644 MANIFEST.in create mode 100644 README.rst create mode 100644 appveyor.yml create mode 100644 bayesclass/__init__.py create mode 100644 bayesclass/_estimators.py create mode 100644 bayesclass/_version.py create mode 100644 bayesclass/tests/__init__.py create mode 100644 bayesclass/tests/test_common.py create mode 100644 bayesclass/tests/test_template.py create mode 100644 doc/Makefile create mode 100644 doc/_static/css/project-template.css create mode 100644 doc/_static/js/copybutton.js create mode 100644 doc/_templates/class.rst create mode 100644 doc/_templates/function.rst create mode 100644 doc/_templates/numpydoc_docstring.py create mode 100644 doc/api.rst create mode 100644 doc/conf.py create mode 100644 doc/index.rst create mode 100644 doc/make.bat create mode 100644 doc/quick_start.rst create mode 100644 doc/user_guide.rst create mode 100644 environment.yml create mode 100644 examples/README.txt create mode 100644 examples/plot_classifier.py create mode 100644 examples/plot_template.py create mode 100644 examples/plot_transformer.py create mode 100644 pyproject.toml create mode 100644 requirements.txt create mode 100644 setup.cfg create mode 100644 setup.py 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, +)