Contributing

This project is a community effort, and everyone is welcome to contribute.

The project is hosted on https://github.com/scikit-learn/scikit-learn

The decision making process and governance structure of scikit-learn is laid out in the governance document: Scikit-learn governance and decision-making.

Scikit-learn is somewhat selective when it comes to adding new algorithms, and the best way to contribute and to help the project is to start working on known issues. See Issues for New Contributors to get started.

In case you experience issues using this package, do not hesitate to submit a ticket to the GitHub issue tracker. You are also welcome to post feature requests or pull requests.

Ways to contribute

There are many ways to contribute to scikit-learn, with the most common ones being contribution of code or documentation to the project. Improving the documentation is no less important than improving the library itself. If you find a typo in the documentation, or have made improvements, do not hesitate to send an email to the mailing list or preferably submit a GitHub pull request. Full documentation can be found under the doc/ directory.

But there are many other ways to help. In particular helping to improve, triage, and investigate issues and reviewing other developers’ pull requests are very valuable contributions that decrease the burden on the project maintainers.

Another way to contribute is to report issues you’re facing, and give a “thumbs up” on issues that others reported and that are relevant to you. It also helps us if you spread the word: reference the project from your blog and articles, link to it from your website, or simply star to say “I use it”:

Star

In case a contribution/issue involves changes to the API principles or changes to dependencies or supported versions, it must be backed by a Enhancement proposals (SLEPs), where a SLEP must be submitted as a pull-request to enhancement proposals using the SLEP template and follows the decision-making process outlined in Scikit-learn governance and decision-making.

Submitting a bug report or a feature request

We use GitHub issues to track all bugs and feature requests; feel free to open an issue if you have found a bug or wish to see a feature implemented.

In case you experience issues using this package, do not hesitate to submit a ticket to the Bug Tracker. You are also welcome to post feature requests or pull requests.

It is recommended to check that your issue complies with the following rules before submitting:

How to make a good bug report

When you submit an issue to Github, please do your best to follow these guidelines! This will make it a lot easier to provide you with good feedback:

  • The ideal bug report contains a short reproducible code snippet, this way anyone can try to reproduce the bug easily (see this for more details). If your snippet is longer than around 50 lines, please link to a gist or a github repo.

  • If not feasible to include a reproducible snippet, please be specific about what estimators and/or functions are involved and the shape of the data.

  • If an exception is raised, please provide the full traceback.

  • Please include your operating system type and version number, as well as your Python, scikit-learn, numpy, and scipy versions. This information can be found by running the following code snippet:

    >>> import sklearn
    >>> sklearn.show_versions()  
    
  • Please ensure all code snippets and error messages are formatted in appropriate code blocks. See Creating and highlighting code blocks for more details.

If you want to help curate issues, read the following.

Contributing code

Note

To avoid duplicating work, it is highly advised that you search through the issue tracker and the PR list. If in doubt about duplicated work, or if you want to work on a non-trivial feature, it’s recommended to first open an issue in the issue tracker to get some feedbacks from core developers.

One easy way to find an issue to work on is by applying the “help wanted” label in your search. This lists all the issues that have been unclaimed so far. In order to claim an issue for yourself, please comment exactly /take on it for the CI to automatically assign the issue to you.

Video resources

These videos are step-by-step introductions on how to contribute to scikit-learn, and are a great companion to the following text guidelines. Please make sure to still check our guidelines below, since they describe our latest up-to-date workflow.

Note

In January 2021, the default branch name changed from master to main for the scikit-learn GitHub repository to use more inclusive terms. These videos were created prior to the renaming of the branch. For contributors who are viewing these videos to set up their working environment and submitting a PR, master should be replaced to main.

How to contribute

The preferred way to contribute to scikit-learn is to fork the main repository on GitHub, then submit a “pull request” (PR).

In the first few steps, we explain how to locally install scikit-learn, and how to set up your git repository:

  1. Create an account on GitHub if you do not already have one.

  2. Fork the project repository: click on the ‘Fork’ button near the top of the page. This creates a copy of the code under your account on the GitHub user account. For more details on how to fork a repository see this guide.

  3. Clone your fork of the scikit-learn repo from your GitHub account to your local disk:

    git clone git@github.com:YourLogin/scikit-learn.git  # add --depth 1 if your connection is slow
    cd scikit-learn
    
  4. Follow steps 2-6 in Building from source to build scikit-learn in development mode and return to this document.

  5. Install the development dependencies:

    pip install pytest pytest-cov ruff mypy numpydoc black==23.3.0
    
  1. Add the upstream remote. This saves a reference to the main scikit-learn repository, which you can use to keep your repository synchronized with the latest changes:

    git remote add upstream git@github.com:scikit-learn/scikit-learn.git
    
  2. Check that the upstream and origin remote aliases are configured correctly by running git remote -v which should display:

    origin  git@github.com:YourLogin/scikit-learn.git (fetch)
    origin  git@github.com:YourLogin/scikit-learn.git (push)
    upstream        git@github.com:scikit-learn/scikit-learn.git (fetch)
    upstream        git@github.com:scikit-learn/scikit-learn.git (push)
    

You should now have a working installation of scikit-learn, and your git repository properly configured. It could be useful to run some test to verify your installation. Please refer to Useful pytest aliases and flags for examples.

The next steps now describe the process of modifying code and submitting a PR:

  1. Synchronize your main branch with the upstream/main branch, more details on GitHub Docs:

    git checkout main
    git fetch upstream
    git merge upstream/main
    
  2. Create a feature branch to hold your development changes:

    git checkout -b my_feature
    

    and start making changes. Always use a feature branch. It’s good practice to never work on the main branch!

  3. (Optional) Install pre-commit to run code style checks before each commit:

    pip install pre-commit
    pre-commit install
    

    pre-commit checks can be disabled for a particular commit with git commit -n.

  4. Develop the feature on your feature branch on your computer, using Git to do the version control. When you’re done editing, add changed files using git add and then git commit:

    git add modified_files
    git commit
    

    to record your changes in Git, then push the changes to your GitHub account with:

    git push -u origin my_feature
    
  5. Follow these instructions to create a pull request from your fork. This will send an email to the committers. You may want to consider sending an email to the mailing list for more visibility.

Note

If you are modifying a Cython module, you have to re-compile after modifications and before testing them:

pip install -v --no-use-pep517 --no-build-isolation -e .

Use the --no-build-isolation flag to avoid compiling the whole project each time, only the files you have modified.

It is often helpful to keep your local feature branch synchronized with the latest changes of the main scikit-learn repository:

git fetch upstream
git merge upstream/main

Subsequently, you might need to solve the conflicts. You can refer to the Git documentation related to resolving merge conflict using the command line.

Pull request checklist

Before a PR can be merged, it needs to be approved by two core developers. Please prefix the title of your pull request with [MRG] if the contribution is complete and should be subjected to a detailed review. An incomplete contribution – where you expect to do more work before receiving a full review – should be prefixed [WIP] (to indicate a work in progress) and changed to [MRG] when it matures. WIPs may be useful to: indicate you are working on something to avoid duplicated work, request broad review of functionality or API, or seek collaborators. WIPs often benefit from the inclusion of a task list in the PR description.

In order to ease the reviewing process, we recommend that your contribution complies with the following rules before marking a PR as [MRG]. The bolded ones are especially important:

  1. Give your pull request a helpful title that summarizes what your contribution does. This title will often become the commit message once merged so it should summarize your contribution for posterity. In some cases “Fix <ISSUE TITLE>” is enough. “Fix #<ISSUE NUMBER>” is never a good title.

  2. Make sure your code passes the tests. The whole test suite can be run with pytest, but it is usually not recommended since it takes a long time. It is often enough to only run the test related to your changes: for example, if you changed something in sklearn/linear_model/_logistic.py, running the following commands will usually be enough:

    • pytest sklearn/linear_model/_logistic.py to make sure the doctest examples are correct

    • pytest sklearn/linear_model/tests/test_logistic.py to run the tests specific to the file

    • pytest sklearn/linear_model to test the whole linear_model module

    • pytest doc/modules/linear_model.rst to make sure the user guide examples are correct.

    • pytest sklearn/tests/test_common.py -k LogisticRegression to run all our estimator checks (specifically for LogisticRegression, if that’s the estimator you changed).

    There may be other failing tests, but they will be caught by the CI so you don’t need to run the whole test suite locally. For guidelines on how to use pytest efficiently, see the Useful pytest aliases and flags.

  3. Make sure your code is properly commented and documented, and make sure the documentation renders properly. To build the documentation, please refer to our Documentation guidelines. The CI will also build the docs: please refer to Generated documentation on GitHub Actions.

  4. Tests are necessary for enhancements to be accepted. Bug-fixes or new features should be provided with non-regression tests. These tests verify the correct behavior of the fix or feature. In this manner, further modifications on the code base are granted to be consistent with the desired behavior. In the case of bug fixes, at the time of the PR, the non-regression tests should fail for the code base in the main branch and pass for the PR code.

  5. Follow the Coding guidelines.

  6. When applicable, use the validation tools and scripts in the sklearn.utils submodule. A list of utility routines available for developers can be found in the Utilities for Developers page.

  7. Often pull requests resolve one or more other issues (or pull requests). If merging your pull request means that some other issues/PRs should be closed, you should use keywords to create link to them (e.g., Fixes #1234; multiple issues/PRs are allowed as long as each one is preceded by a keyword). Upon merging, those issues/PRs will automatically be closed by GitHub. If your pull request is simply related to some other issues/PRs, create a link to them without using the keywords (e.g., See also #1234).

  8. PRs should often substantiate the change, through benchmarks of

    performance and efficiency (see Monitoring performance) or through examples of usage. Examples also illustrate the features and intricacies of the library to users. Have a look at other examples in the examples/ directory for reference. Examples should demonstrate why the new functionality is useful in practice and, if possible, compare it to other methods available in scikit-learn.

  9. New features have some maintenance overhead. We expect PR authors

    to take part in the maintenance for the code they submit, at least initially. New features need to be illustrated with narrative documentation in the user guide, with small code snippets. If relevant, please also add references in the literature, with PDF links when possible.

  10. The user guide should also include expected time and space complexity of the algorithm and scalability, e.g. “this algorithm can scale to a large number of samples > 100000, but does not scale in dimensionality: n_features is expected to be lower than 100”.

You can also check our Code Review Guidelines to get an idea of what reviewers will expect.

You can check for common programming errors with the following tools:

  • Code with a good unittest coverage (at least 80%, better 100%), check with:

    pip install pytest pytest-cov
    pytest --cov sklearn path/to/tests_for_package
    

    see also Testing and improving test coverage

    Run static analysis with mypy:

    mypy sklearn
    

    must not produce new errors in your pull request. Using # type: ignore annotation can be a workaround for a few cases that are not supported by mypy, in particular,

    • when importing C or Cython modules

    • on properties with decorators

Bonus points for contributions that include a performance analysis with a benchmark script and profiling output (see Monitoring performance).

Also check out the How to optimize for speed guide for more details on profiling and Cython optimizations.

Note

The current state of the scikit-learn code base is not compliant with all of those guidelines, but we expect that enforcing those constraints on all new contributions will get the overall code base quality in the right direction.

Note

For two very well documented and more detailed guides on development workflow, please pay a visit to the Scipy Development Workflow - and the Astropy Workflow for Developers sections.

Continuous Integration (CI)

  • Azure pipelines are used for testing scikit-learn on Linux, Mac and Windows, with different dependencies and settings.

  • CircleCI is used to build the docs for viewing.

  • Github Actions are used for various tasks, including building wheels and source distributions.

  • Cirrus CI is used to build on ARM.

Please note that if one of the following markers appear in the latest commit message, the following actions are taken.

Commit Message Marker

Action Taken by CI

[ci skip]

CI is skipped completely

[cd build]

CD is run (wheels and source distribution are built)

[cd build gh]

CD is run only for GitHub Actions

[cd build cirrus]

CD is run only for Cirrus CI

[lint skip]

Azure pipeline skips linting

[scipy-dev]

Build & test with our dependencies (numpy, scipy, etc.) development builds

[nogil]

Build & test with the nogil experimental branches of CPython, Cython, NumPy, SciPy, …

[pypy]

Build & test with PyPy

[pyodide]

Build & test with Pyodide

[azure parallel]

Run Azure CI jobs in parallel

[cirrus arm]

Run Cirrus CI ARM test

[float32]

Run float32 tests by setting SKLEARN_RUN_FLOAT32_TESTS=1. See Environment variables for more details

[doc skip]

Docs are not built

[doc quick]

Docs built, but excludes example gallery plots

[doc build]

Docs built including example gallery plots (very long)

Note that, by default, the documentation is built but only the examples that are directly modified by the pull request are executed.

Stalled pull requests

As contributing a feature can be a lengthy process, some pull requests appear inactive but unfinished. In such a case, taking them over is a great service for the project.

A good etiquette to take over is:

  • Determine if a PR is stalled

    • A pull request may have the label “stalled” or “help wanted” if we have already identified it as a candidate for other contributors.

    • To decide whether an inactive PR is stalled, ask the contributor if she/he plans to continue working on the PR in the near future. Failure to respond within 2 weeks with an activity that moves the PR forward suggests that the PR is stalled and will result in tagging that PR with “help wanted”.

      Note that if a PR has received earlier comments on the contribution that have had no reply in a month, it is safe to assume that the PR is stalled and to shorten the wait time to one day.

      After a sprint, follow-up for un-merged PRs opened during sprint will be communicated to participants at the sprint, and those PRs will be tagged “sprint”. PRs tagged with “sprint” can be reassigned or declared stalled by sprint leaders.

  • Taking over a stalled PR: To take over a PR, it is important to comment on the stalled PR that you are taking over and to link from the new PR to the old one. The new PR should be created by pulling from the old one.

Stalled and Unclaimed Issues

Generally speaking, issues which are up for grabs will have a “help wanted”. tag. However, not all issues which need contributors will have this tag, as the “help wanted” tag is not always up-to-date with the state of the issue. Contributors can find issues which are still up for grabs using the following guidelines:

  • First, to determine if an issue is claimed:

    • Check for linked pull requests

    • Check the conversation to see if anyone has said that they’re working on creating a pull request

  • If a contributor comments on an issue to say they are working on it, a pull request is expected within 2 weeks (new contributor) or 4 weeks (contributor or core dev), unless an larger time frame is explicitly given. Beyond that time, another contributor can take the issue and make a pull request for it. We encourage contributors to comment directly on the stalled or unclaimed issue to let community members know that they will be working on it.

  • If the issue is linked to a stalled pull request, we recommend that contributors follow the procedure described in the Stalled pull requests section rather than working directly on the issue.

Issues for New Contributors

New contributors should look for the following tags when looking for issues. We strongly recommend that new contributors tackle “easy” issues first: this helps the contributor become familiar with the contribution workflow, and for the core devs to become acquainted with the contributor; besides which, we frequently underestimate how easy an issue is to solve!

Documentation

We are glad to accept any sort of documentation:

  • function/method/class docstrings (also known as “API documentation”) - these describe what the object does and details any parameters, attributes and methods. Docstrings live alongside the code in sklearn/.

  • user guide - these provide more detailed information about the algorithms implemented in scikit-learn and generally live in the root doc/ directory and doc/modules/.

  • tutorials - these introduce various statistical learning and machine learning concepts and are located in doc/tutorial.

  • examples - these provide full code examples that may demonstrate the use of scikit-learn modules, compare different algorithms or discuss their interpretation etc. Examples live in examples/

  • other reStructuredText documents - provide various other useful information (e.g., the Contributing guide) and live in doc/.

Guidelines for writing docstrings Click for more details

  • When documenting the parameters and attributes, here is a list of some well-formatted examples:

    n_clusters : int, default=3
        The number of clusters detected by the algorithm.
    
    some_param : {'hello', 'goodbye'}, bool or int, default=True
        The parameter description goes here, which can be either a string
        literal (either `hello` or `goodbye`), a bool, or an int. The default
        value is True.
    
    array_parameter : {array-like, sparse matrix} of shape (n_samples, n_features) or (n_samples,)
        This parameter accepts data in either of the mentioned forms, with one
        of the mentioned shapes. The default value is
        `np.ones(shape=(n_samples,))`.
    
    list_param : list of int
    
    typed_ndarray : ndarray of shape (n_samples,), dtype=np.int32
    
    sample_weight : array-like of shape (n_samples,), default=None
    
    multioutput_array : ndarray of shape (n_samples, n_classes) or list of such arrays
    

    In general have the following in mind:

    • Use Python basic types. (bool instead of boolean)

    • Use parenthesis for defining shapes: array-like of shape (n_samples,) or array-like of shape (n_samples, n_features)

    • For strings with multiple options, use brackets: input: {'log', 'squared', 'multinomial'}

    • 1D or 2D data can be a subset of {array-like, ndarray, sparse matrix, dataframe}. Note that array-like can also be a list, while ndarray is explicitly only a numpy.ndarray.

    • Specify dataframe when “frame-like” features are being used, such as the column names.

    • When specifying the data type of a list, use of as a delimiter: list of int. When the parameter supports arrays giving details about the shape and/or data type and a list of such arrays, you can use one of array-like of shape (n_samples,) or list of such arrays.

    • When specifying the dtype of an ndarray, use e.g. dtype=np.int32 after defining the shape: ndarray of shape (n_samples,), dtype=np.int32. You can specify multiple dtype as a set: array-like of shape (n_samples,), dtype={np.float64, np.float32}. If one wants to mention arbitrary precision, use integral and floating rather than the Python dtype int and float. When both int and floating are supported, there is no need to specify the dtype.

    • When the default is None, None only needs to be specified at the end with default=None. Be sure to include in the docstring, what it means for the parameter or attribute to be None.

  • Add “See Also” in docstrings for related classes/functions.

  • “See Also” in docstrings should be one line per reference, with a colon and an explanation, for example:

    See Also
    --------
    SelectKBest : Select features based on the k highest scores.
    SelectFpr : Select features based on a false positive rate test.
    
  • Add one or two snippets of code in “Example” section to show how it can be used.