## File: README.md

## ⚡️ Quickstart

As a quick example, we'll train a logistic regression to classify the [website phishing dataset](http://archive.ics.uci.edu/ml/datasets/Website+Phishing). Here's a look at the first observation in the dataset.

```python
>>> from pprint import pprint
>>> from river import datasets

>>> dataset = datasets.Phishing()

>>> for x, y in dataset:
...     pprint(x)
...     print(y)
...     break
{'age_of_domain': 1,
 'anchor_from_other_domain': 0.0,
 'empty_server_form_handler': 0.0,
 'https': 0.0,
 'ip_in_url': 1,
 'is_popular': 0.5,
 'long_url': 1.0,
 'popup_window': 0.0,
 'request_from_other_domain': 0.0}
True

```

Now let's run the model on the dataset in a streaming fashion. We sequentially interleave predictions and model updates. Meanwhile, we update a performance metric to see how well the model is doing.

```python
>>> from river import compose
>>> from river import linear_model
>>> from river import metrics
>>> from river import preprocessing

>>> model = compose.Pipeline(
...     preprocessing.StandardScaler(),
...     linear_model.LogisticRegression()
... )

>>> metric = metrics.Accuracy()

>>> for x, y in dataset:
...     y_pred = model.predict_one(x)      # make a prediction
...     metric.update(y, y_pred)           # update the metric
...     model.learn_one(x, y)              # make the model learn

>>> metric
Accuracy: 89.28%

```

Of course, this is just a contrived example. We welcome you to check the [introduction](https://riverml.xyz/dev/introduction/installation/) section of the documentation for a more thorough tutorial.

## 🛠 Installation

River is intended to work with **Python 3.11 and above**. Installation can be done with `pip`:

```sh
pip install river
```

There are [wheels available](https://pypi.org/project/river/#files) for Linux, MacOS, and Windows. This means you most probably won't have to build River from source.

River's core online interface (`learn_one` / `predict_one`) has no `pandas` dependency. The mini-batch interface (`learn_many`, `predict_many`, `predict_proba_many`, `transform_many`) is built on `pandas` and is opt-in:

```sh
pip install "river[pandas]"
```

You can install the latest development version from GitHub as so:

```sh
pip install git+https://github.com/online-ml/river --upgrade
pip install git+ssh://git@github.com/online-ml/river.git --upgrade  # using SSH
```

This method requires having Cython and Rust installed on your machine.

## 🔮 Features

River provides online implementations of the following family of algorithms:

- Linear models, with a wide array of optimizers
- Decision trees and random forests
- (Approximate) nearest neighbors
- Anomaly detection
- Drift detection
- Recommender systems
- Time series forecasting
- Bandits
- Factorization machines
- Imbalanced learning
- Clustering
- Bagging/boosting/stacking
- Active learning

River also provides other online utilities:

- Feature extraction and selection
- Online statistics and metrics
- Preprocessing
- Built-in datasets
- Progressive model validation
- Model pipelines

Check out [the API](https://riverml.xyz/latest/api/overview/) for a comprehensive overview

## 🤔 Should I be using River?

You should ask yourself if you need online machine learning. The answer is likely no. Most of the time batch learning does the job just fine. An online approach might fit the bill if:

- You want a model that can learn from new data without having to revisit past data.
- You want a model which is robust to [concept drift](https://www.wikiwand.com/en/Concept_drift).
- You want to develop your model in a way that is closer to what occurs in a production context, which is usually event-based.

Some specificities of River are that:

- It focuses on clarity and user experience, more so than performance.
- It's very fast at processing one sample at a time. Try it, you'll see.
- It plays nicely with the rest of Python's ecosystem.

## 🔗 Useful links

- [Documentation](https://riverml.xyz)
- [Package releases](https://pypi.org/project/river/#history)
- [awesome-online-machine-learning](https://github.com/online-ml/awesome-online-machine-learning)
- [2022 presentation at GAIA](https://www.youtube.com/watch?v=nzFTmJnIakk&list=PLIU25-FciwNaz5PqWPiHmPCMOFYoEsJ8c&index=5)
- [Online Clustering: Algorithms, Evaluation, Metrics, Applications and Benchmarking](https://dl.acm.org/doi/10.1145/3534678.3542600) from [KDD'22](https://kdd.org/kdd2022/).

## 👐 Contributing

Feel free to contribute in any way you like, we're always open to new ideas and approaches.

- [Open a discussion](https://github.com/online-ml/river/discussions/new) if you have any question or enquiry whatsoever. It's more useful to ask your question in public rather than sending us a private email. It's also encouraged to open a discussion before contributing, so that everyone is aligned and unnecessary work is avoided.
- Feel welcome to [open an issue](https://github.com/online-ml/river/issues/new/choose) if you think you've spotted a bug or a performance issue.
- Our [roadmap](https://github.com/orgs/online-ml/projects/3?query=is%3Aopen+sort%3Aupdated-desc) is public. Feel free to work on anything that catches your eye, or to make suggestions.

Please check out the [contribution guidelines](https://github.com/online-ml/river/blob/main/CONTRIBUTING.md) if you want to bring modifications to the code base.

## 🤝 Affiliations



## 💬 Citation

If River has been useful to you, and you would like to cite it in a scientific publication, please refer to the [paper](https://www.jmlr.org/papers/volume22/20-1380/20-1380.pdf) published at JMLR:

```bibtex
@article{montiel2021river,
  title={River: machine learning for streaming data in Python},
  author={Montiel, Jacob and Halford, Max and Mastelini, Saulo Martiello
          and Bolmier, Geoffrey and Sourty, Raphael and Vaysse, Robin and Zouitine, Adil
          and Gomes, Heitor Murilo and Read, Jesse and Abdessalem, Talel and others},
  year={2021}
}
```

## 📝 License

River is free and open-source software licensed under the [3-clause BSD license](https://github.com/online-ml/river/blob/main/LICENSE).

---

## File: benchmarks/README.md

# River Benchmarks

River benchmarks use [airspeed velocity (asv)](https://asv.readthedocs.io/) to track the timing performance of models across git history.

Each benchmark runs progressive validation (`evaluate.iter_progressive_val_score`) for a model on a dataset, measuring wall-clock time. Results are tracked per commit so that performance regressions can be detected automatically.

## Prerequisites

```bash
pip install asv virtualenv
```

## Running benchmarks locally

All commands should be run from the `benchmarks/` directory.

### Quick run (current Python, no environment setup)

```bash
asv run --python=same --quick --show-stderr
```

### Run a specific benchmark class

```bash
asv run --python=same --quick --bench BinaryClassification
asv run --python=same --quick --bench Regression
```

### Run a specific model/dataset combination

```bash
asv run --python=same --quick --bench "BinaryClassification.*Logistic.*Bananas"
```

### Compare two branches

```bash
asv continuous main my-feature-branch --bench BinaryClassification
```

This runs benchmarks on both branches and highlights significant timing changes.

### Find which commit caused a regression

```bash
asv find v0.22.0..main --bench "Regression.time_progressive_val_score\(Linear Regression, ChickWeights\)"
```

## Viewing results

```bash
asv publish
asv preview
```

This generates a static website and serves it locally. Open the printed URL in your browser.

## Adding a new model

1. Edit `benchmarks/common.py`
2. Add the model name to the appropriate `*_MODELS` list (e.g., `BINARY_CLF_MODELS`)
3. Add a factory lambda to the corresponding `_*_MODEL_REGISTRY` dict
4. Run `asv check` to verify discovery

## Adding a new track

1. Create `benchmarks/bench_.py` following the pattern in existing files
2. Add the model/dataset lists and registries to `benchmarks/common.py`
3. Run `asv check` to verify discovery

## CI

Benchmarks run automatically on push to `main` via GitHub Actions. Results are stored on the `asv` branch and published to GitHub Pages.

## CodSpeed

CodSpeed runs the small pytest benchmark suite in `benchmarks/codspeed/python/` and the
Rust criterion benchmarks in `benchmarks/codspeed/rust/` on every pull request and every
push to `main`. Both jobs use CodSpeed's CPU simulation mode, which produces deterministic
instruction-count measurements and flamegraphs. Pull requests get a CodSpeed comment plus
status checks for the Python benchmarks, Rust benchmarks, and the aggregate performance
analysis.

To keep CI fast, the Python job is split into two parallel shards (see the matrix in
`.github/workflows/codspeed.yml`): a "heavy" shard listing the most expensive files
explicitly, and a "rest" shard running everything else. New benchmark files land in the
"rest" shard automatically; if the two shards drift far apart in duration, move files
between them. Sharding does not affect benchmark identity or the CodSpeed report — all
uploads for a commit are aggregated. Keep each benchmark body around 100 ms of real time
or less: the CPU simulator runs it once at roughly 30–100× overhead, so oversized
workloads slow every PR without adding signal.

### Run CodSpeed benchmarks locally

```sh
make benchmark                      # all Python benchmarks, local walltime table
make benchmark K=logistic           # filter by pytest -k expression
make benchmark-rust                 # all Rust criterion benches
make benchmark-rust BENCH=stats_bench
```

Local Python runs are smoke tests, not the merge-gating measurement. Outside CodSpeed CI,
`pytest-codspeed` falls back to a normal walltime table, so results depend on your
machine. The PR comment is the source of truth for comparisons. On Linux, power users can
run simulation locally with the CodSpeed CLI:

```sh
curl -fsSL https://codspeed.io/install.sh | bash
codspeed auth login
codspeed run -m simulation -- uv run --no-sync pytest benchmarks/codspeed --codspeed -o addopts=""
```

### Add a CodSpeed benchmark

Copy this template into `benchmarks/codspeed/python/test_<module>.py` and keep the benchmark
name stable after it lands; renaming a benchmark loses its CodSpeed history.

```python
from __future__ import annotations

import pytest

from river import <module>

from workloads import binary_stream  # or regression_stream, scalar_series, ...

pytestmark = pytest.mark.benchmark(group="<module>")


def test_<estimator>_learn(benchmark) -> None:
    stream = binary_stream()

    def run() -> None:
        model = <module>.<Estimator>(seed=42)
        for x, y in stream:
            model.learn_one(x, y)

    benchmark(run)
```

Rust benchmarks live in `benchmarks/codspeed/rust/`. Add each new Rust bench target to
`Cargo.toml` explicitly:

```toml
[[bench]]
name = "<module>_bench"
path = "benchmarks/codspeed/rust/<module>_bench.rs"
harness = false
```

Use deterministic workloads only:

- Seed every generator and every stochastic estimator.
- Do not use network access or read the clock inside a benchmark.
- Materialize data in `workloads.py`, outside the measured callable.
- Treat cached workload lists as frozen; do not mutate shared data.
- Build a fresh estimator inside each measured learning callable.

### Reading CodSpeed results

The PR comment links to each benchmark, its comparison against `main`, and the
differential flamegraph. A red CodSpeed performance status means at least one benchmark
regressed beyond the configured threshold. The default threshold is 10%; noisy benchmarks
can get a per-benchmark threshold in CodSpeed instead of loosening the global one.

Intentional regressions should be explained in the PR description and acknowledged by an
admin in the CodSpeed UI. Do not bypass GitHub branch protection for performance
regressions; acknowledgement keeps the dashboard and branch status consistent.

---

## File: docs/faq/index.md

---
hide:
  - navigation
---

# Frequently Asked Questions

## Do all classifiers support multi-class classification?

No, they don't. Although binary classification can be seen as a special case of multi-class classification, there are many optimizations that can be performed if we know that there are only two classes. It would be annoying to have to check whether this is the case in an online setting. All in all we find that separating both cases leads to much cleaner code. Note that the `multiclass` module contains wrapper models that enable you to perform multi-class classification with binary classifiers.

## How do I know if a classifier supports multi-class classification?

Each classifier in River inherits from the `base.Classifier` class. Each classifier therefore has a `_multiclass` property which indicates whether or not it can process a non-boolean target value.

```python
>>> from river import linear_model

>>> classifier = linear_model.LogisticRegression()
>>> classifier._multiclass
False
```

## Why doesn't river do any input validation?

Python encourages a coding style called [EAFP](https://docs.python.org/2/glossary.html?highlight=EAFP#term-eafp), which stands for "Easier to Ask for Forgiveness than Permission". The idea is to assume that runtime errors don't occur, and instead use try/expects to catch errors. The great benefit is that we don't have to drown our code with `if` statements, which is symptomatic of the [LBYL style](https://docs.python.org/2/glossary.html?highlight=EAFP#term-lbyl), which stands for "look before you leap". This makes our implementations much more readable than, say, scikit-learn, which does a lot of input validation. The catch is that users have to be careful to use sane inputs. As always, [there is no free lunch](https://www.wikiwand.com/en/No_free_lunch_theorem)!

## What about reinforcement learning?

Reinforcement learning works in an online manner because of the nature of the task. Reinforcement learning can be therefore be seen as a subcase of online machine learning. However, we prefer not to support it because there are already many existing opensource libraries dedicated to it.

## What are the differences between scikit-learn's online learning algorithm which have a partial_fit method and their equivalents in River?

The algorithms from `sklearn` that support incremental learning are mostly meant for mini-batch learning. In a pure streaming context where the observations arrive one by one, then River is much faster than `sklearn`. This is mostly because `sklearn` incurs a lot of overhead by performing data checks. Also, sklearn assumes that you're always using the same number of features. This is not the case with River because it use dictionaries which allows you to drop and add features as you wish.

## How do I save and load models?

```python
>>> from river import ensemble
>>> import pickle

>>> model = ensemble.ARFClassifier()

# save
>>> with open('model.pkl', 'wb') as f:
...     pickle.dump(model, f)

# load
>>> with open('model.pkl', 'rb') as f:
...     model = pickle.load(f)
```

We also encourage you to try out [dill](https://dill.readthedocs.io/en/latest/dill.html) and [cloudpickle](https://github.com/cloudpipe/cloudpickle).

## What about neural networks?

There are many great open-source libraries for building neural network models. We don't feel that we can bring anything of value to the existing Python ecosystem. However, we are open to implementing compatibility wrappers for popular libraries such as PyTorch and Keras.

## Who are the authors of this library?

We are research engineers, graduate students, PhDs and machine learning researchers. The members of the development team are mainly located in France, Brazil and New Zealand.

---

## File: docs/introduction/basic-concepts.md

---
---

# Basic concepts

Here are some concepts to give you a feel for what problems River addresses.

## Data streams

River is a library to build online machine learning models. Such models operate on data streams. But a data stream is a bit of a vague concept.

In general, a data stream is a sequence of individual elements. In the case of machine learning, each element is a bunch of features. We call these samples, or observations. Each sample might follow a fixed structure and always contain the same features. But features can also appear and disappear over time. That depends on the use case.

## Reactive and proactive data streams

The origin of a data stream can vary, and usually it doesn't matter. You should be able to use River regardless of where your data comes from. It is however important to keep in mind the difference between reactive and proactive data streams.

Reactive data streams are ones where the data comes to you. For instance, when a user visits your website, that's out of your control. You have no influence on the event. It just happens and you have to react to it.

Proactive data streams are ones where you have control on the data stream. For example, you might be reading the data from a file. You decide at which speed you want to read the data, in what order, etc.

If you consider data analysis as a whole, you realize that the general approach is to turn reactive streams into proactive datasets. Events are usually logged into a database and are processed offline. Be it for building KPIs or training models.

The challenge for machine learning is to ensure models you train offline on proactive datasets will perform correctly in production on reactive data streams.

## Online processing

Online processing is the act of processing a data stream one element at a time. In the case of machine learning, that means training a model by teaching it one sample at a time. This is completely opposite to the traditional way of doing machine learning, which is to train a model on whole batches of data at a time.

An online model is therefore a stateful, dynamic object. It keeps learning and doesn't have to revisit past data. It's a different way of doing things, and therefore has its own set of pros and cons.

## Tasks

Machine learning encompasses many different tasks: classification, regression, anomaly detection, time series forecasting, etc. The ideology behind River is to be a generic machine learning approach which allows these tasks to be performed in a streaming manner. Indeed, many batch machine learning algorithms have online equivalents.

Note that River also supports some more basic tasks. For instance, you might just want to calculate a running average of a data stream. These are usually smaller parts of a whole stream processing pipeline.

## Dictionaries everywhere

River is a Python library. It is composed of a bunch of classes which implement various online processing algorithms. Most of these classes are machine learning models which can process a single sample, be it for learning or for inference.

We made the choice to use dictionaries as the basic building block. First of all, online processing is different to batch processing, in that vectorization doesn't bring any speed-up. Therefore numeric processing libraries such as NumPy and PyTorch actually bring too much overhead. Using native Python data structures is faster.

Dictionaries are therefore a perfect fit. They're native to Python and have excellent support in the standard library. They allow the naming of each feature. They can hold any kind of data type. They allow transparent support of JSON payloads, allowing seamless integration with web apps.

## Datasets

In production, you're almost always going to face data streams which you have to react to, such as users visiting your website. The advantage of online machine learning is that you can design models that make predictions as well as learn from this data stream as it flows.

But of course, when you're developing a model, you don't usually have access to a real-time feed on which to evaluate your model. You usually have an offline dataset which you want to evaluate your model on. River provides some datasets which can be read in online manner, one sample at a time. It is however crucial to keep in mind that the goal is to reproduce a production scenario as closely as possible, in order to ensure your model will perform just as well in production.

## Model evaluation

Online model evaluation differs from its traditional batch counterpart. In the latter, you usually perform cross-validation, whereby your training dataset is split into a learning and an evaluation dataset. This is fine, but it doesn't exactly reflect the data generation process that occurs in production.

Online model evaluation involves learning and inference in the same order as what would happen in production. Indeed, if you know the order in which your data arrives, then you can process it the exact same order. This allows you to replay a production scenario and evaluate your model with higher fidelity than cross-validation.

This is what makes online machine learning powerful. By replaying datasets in the correct order, you ensure you are designing models which will perform as expected in production.

## Concept drift

The main reason why an offline model might not perform as expected in production is because of concept drift. But this is true for all machine learning models, be they offline or online.

The advantage of online models over offline models is that they can cope with drift. Indeed, because they can keep learning, they usually adapt to concept drift in a seamless manner. As opposed to batch models which have to be retrained from scratch.

---

## File: docs/introduction/installation.md

---
---

# Installation

River is meant to work with Python 3.11 and above. Installation can be done via `pip`:

```sh
pip install river
```

And of course with uv:

```sh
uv add river
```

You can install the latest development version from GitHub, as so:

```sh
pip install git+https://github.com/online-ml/river --upgrade
pip install git+ssh://git@github.com/online-ml/river.git --upgrade  # using SSH
```

This method requires having Cython and Rust installed on your machine.

## Mini-batch support (optional `pandas` extra)

River's core online interface (`learn_one` / `predict_one`) does **not** require `pandas`. The mini-batch interface (`learn_many`, `predict_many`, `predict_proba_many`, `transform_many`) is built on top of `pandas.DataFrame` and `pandas.Series`, so `pandas` is an opt-in dependency.

To install River together with `pandas`:

```sh
pip install "river[pandas]"
# or
uv add "river[pandas]"
```

If you call a mini-batch method without `pandas` installed, River raises an `ImportError` pointing you to this extra.

Feel welcome to [open an issue on GitHub](https://github.com/online-ml/river/issues/new) if you are having any trouble.

---

## File: docs/introduction/next-steps.md

# Next steps

The [Recipes](/latest/recipes/reading-data) section is made up of small tutorials. Each one explains how to perform mundane tasks, such as measuring the performance of a model, selecting hyperparameters, etc.

The [Examples](/latest/examples/batch-to-online) section contains more involved notebooks with less explanations. Each notebook addresses a particular machine learning problem.

The [API](/latest/api) section references all the modules, classes, and functions in River. It is automatically generated from the codebase's Python docstrings.

Feel welcome to [open a discussion](https://github.com/online-ml/river/discussions) if you have a question. Before that you can check out the [FAQ](/latest/faq), which has answers to recurring questions.

The released versions are listed in the [Releases](/latest/releases) section. Changes that will be part of the next release are listed in the unreleased section of the documentation's development version, which you may find [here](https://riverml.xyz/latest/releases/unreleased/).

We recommend checking out [Awesome Online Machine Learning](https://github.com/online-ml/awesome-online-machine-learning) if you want to go deeper. There you will find online machine learning related content: research papers, alternative and complementary software, blog posts, etc.

---

## File: docs/introduction/related-projects.md

# Related projects

Here is a list of projects which are more or less coupled with River:

- [deep-river](https://github.com/online-ml/deep-river) interfaces PyTorch models with River.
- [river-extra](https://github.com/online-ml/river-extra) regroups experimental features which have yet to prove themselves to make it into the main River repository. Between us we call this "the arena".