Unreleased¶
- Add
ppc64learchitecture to Linux wheel builds. - Publish
abi3(stable-ABI,cp311-abi3) wheels alongside the per-version native wheels. pip/uv keep using the faster native wheel whenever one matches your interpreter; theabi3wheel is a fallback so River still installs as a wheel on CPython versions that don't yet have native builds (e.g. a brand-new release). - Moved
altairfrom the runtime dependencies to thedocs/devgroups; it was only used to draw plots in the docs, so installing River no longer pulls it in. - Publish Pyodide/WebAssembly wheels (CPython 3.13 and 3.14) so River can run in the browser, e.g. via JupyterLite or
micropip. The minimumnumpyandscipyversions were lowered to2.2.5and1.14.1to match Pyodide. - Display
compose.TransformerUnionelements vertically in HTML representations.
base¶
base.Transformerandbase.SupervisedTransformerare now properly abstract: theirtransform_oneabstract method is registered withabc, so a subclass that forgets to implement it raisesTypeErrorat instantiation instead of failing later. This also restores estimator-check coverage for all concrete transformers, which were unintentionally excluded from the automated test suite.
anomaly¶
-
Added
api.anomaly.LODA, an online implementation of Pevný's Lightweight on-line detector of anomalies. It maintains an ensemble of one-dimensionalsketch.Histograms over sparse random projections and scores samples by their average negative log-likelihood. -
Made
anomaly.OneClassSVM.learn_manydataframe-agnostic via narwhals: it now accepts any narwhals-supported eager backend (pandas, polars, pyarrow, ...) instead of only pandas. Outputs are unchanged.
cluster¶
- Gave the
CluStream,DenStream, andDBSTREAMmicro-cluster objects__slots__. These are created in large numbers on long streams, so dropping their per-instance__dict__trims memory (~40 bytes per micro-cluster). Behavior is unchanged. CluStreamMicroClusterno longer inherits frombase.Base; it is an internal data structure, not an estimator, so the estimator machinery (cloning, parameter introspection,repr) never applied to it. This matches theDenStream/DBSTREAMmicro-clusters and is what lets it use__slots__.
compose¶
compose.Pipelinenow forwards extra keyword arguments (such as the timestamptused byutils.TimeRolling, or a sample weightw) to each step whose method declares them, and drops them for steps that don't. This makesfeature_extraction.Agg/TargetAggbacked byutils.TimeRollingwork inside a pipeline viamodel.learn_one(x, y, t=t). Routing applies tolearn_oneand to the predict-time methods (predict_one,predict_proba_one,score_one,transform_one), so it also works undercompose.learn_during_predictwhere unsupervised steps learn duringpredict_one(x, t=t). Fixes #1600. The accepted arguments are determined once when the pipeline plan is built, so pipelines with no extra arguments keep their previous speed.
covariance¶
- Added weighted sample support to
EmpiricalCovariance.updateandEmpiricalCovariance.revertby accepting an optionalwparameter and propagating it to the underlyingstats.Covandstats.Varstatistics. - Sped up
EmpiricalCovariance.update/revert(~40% faster at 30 features) by caching the sorted feature list and pair iteration in the hot path. No semantic change. - Restructured
EmpiricalPrecisionaround NumPy-backed dense state, removing the per-update dict ↔ numpy marshalling. ~7× faster on 2000 × 20 sample streams. - Fixed an
EmpiricalPrecisionasymmetry where features introduced at different times left the stored matrix skewed (e.g.prec[a, b]≠prec[b, a]).
datasets¶
- Added
datasets.CriteoAds, a 100,000-row sample of the Criteo Display Advertising Challenge (binary click prediction with 13 integer and 26 high-cardinality categorical features). A natural fit for one-hot models such aslinear_model.AdPredictor. - Added
datasets.Shuttle, the UCI Statlog (Shuttle) dataset cast as a binary anomaly-detection task following the ODDS benchmark (49,097 observations, 9 numerical features, ~7% anomalies). Ships bundled with River.
facto¶
- Sped up
learn_onefor all factorization-machine models by vectorizing the per-factor latent updates with NumPy instead of looping in Python. On MovieLens 100K: ~1.4× faster forFFMRegressor/FFMClassifier, ~1.8× forFwFMRegressor/FwFMClassifierandHOFMRegressor/HOFMClassifier. Outputs are unchanged. - The factorization-machine models are now covered by the automated estimator checks (
utils.check_estimator).
feature_extraction¶
- Added proper mini-batch support to
feature_extraction.TFIDF:learn_manynow updates document frequencies, andtransform_manyreturns TF-IDF weights. Bothfeature_extraction.BagOfWords.transform_manyandTFIDF.transform_manynow accept any narwhals-supported dataframe backend (pandas, polars, pyarrow, ...), as either a series of documents or a dataframe with theonparameter, and return the same backend (a sparse dataframe for pandas).
linear_model¶
- Added
linear_model.AdPredictor, the Bayesian online probit-regression classifier Microsoft used for click-through-rate prediction in Bing's sponsored search (Graepel et al., 2010). It keeps a Gaussian belief over each feature weight and yields well-calibrated probabilities. - Restructured
BayesianLinearRegressionaround NumPy-backed storage. ~11× fasterlearn_oneat 20 features, ~24× at 50 features. Speeds upbandit.LinUCBtoo. BayesianLinearRegressionnow handles features arriving and disappearing after training begins (it passescheck_emerging_featuresandcheck_shuffle_features_no_impact, previously skipped).- Fixed
BayesianLinearRegressioncoefficients diverging toinf/nanunder emerging/disappearing features;learn_onenow updates the full state with a zero-paddedx. Behavior change: features absent fromxare treated as observed 0s (matching the other linear models) rather than skipped — identical to before when every call sees the same features. - Sped up the
LinearRegression/LogisticRegression.learn_manymini-batch gradient (~2-3×) by contracting the sample axis inside thenp.einsum. No semantic change. - Sped up
learn_onefor the linear models (LinearRegression,LogisticRegression,Perceptron, ...): updates now scale with the number of active features instead of the total number of features ever seen. Outputs are unchanged. - Stabilised
BayesianLinearRegressionacross BLAS implementations and sped it up (~10-20%) by accumulating an exact natural mean and recovering the posterior mean lazily, instead of propagating it through compounding rank-1 updates (which drifted ~0.6% between macOS Accelerate and Linux OpenBLAS). linear_model.LinearRegressionandlinear_model.LogisticRegressionmini-batch methods (learn_many,predict_many,predict_proba_many) now accept and return any narwhals-supported eager backend (pandas, polars, pyarrow, ...) instead of being pandas-only. The input backend is preserved on output, including the pandas index. These methods no longer requirepandasto be installed.linear_model.BayesianLinearRegressionis now aMiniBatchRegressor: it gained alearn_manymethod, equivalent to loopinglearn_oneover the rows (exact without smoothing, and the matching closed-form geometric weighting with smoothing). Itslearn_many/predict_manyaccept and return any narwhals-supported eager backend (pandas, polars, pyarrow, ...), preserving the input backend and pandas index, and no longer requirepandas.
multiclass¶
multiclass.OneVsRestClassifiermini-batch methods (learn_many,predict_many,predict_proba_many) now accept and return any narwhals-supported eager backend (pandas, polars, pyarrow, ...) instead of being pandas-only. The input backend is preserved on output, including the pandas index, and these methods no longer requirepandasto be installed. Outputs are unchanged on the pandas path.
multioutput¶
- Added
multioutput.PerOutputClassifier, the streaming equivalent of scikit-learn'sMultiOutputClassifier. Trains one independent classifier per target output. - Added
multioutput.PerOutputRegressor, the streaming equivalent of scikit-learn'sMultiOutputRegressor. Trains one independent regressor per target output, with no inter-output dependencies.
naive_bayes¶
- Added mini-batch support to
GaussianNBvialearn_many,predict_many, andpredict_proba_many.
neighbors¶
- Gave the SWINN graph
Vertex__slots__and dropped itsbase.Baseinheritance (it is an internal graph node, not an estimator). One vertex is created per buffered sample, so this trims memory on largeneighbors.SWINNindexes; behavior is unchanged.
neural_net¶
- Removed the deprecated
river.neural_netmodule (and itsMLPRegressor), which had emitted aDeprecationWarningsince 0.25.0. Usedeep-riveror a dedicated deep-learning library such as PyTorch for neural networks.
optim¶
- Exposed
optim.Newton(Online Newton Step), which was implemented but never exported, and fixed an initialisation bug (the inverse Hessian started ateps * Iinstead of(1 / eps) * I) that crippled learning. Reworked around NumPy-backed dense state. - Fixed
optim.AdaBoundraisingTypeErrorafter being cloned (its base learning rate was captured as a scheduler instead of a number), which broke it insideevaluate, ensembles, model selection, and anywhere else estimators are cloned. - Fixed
optim.NesterovMomentumandoptim.FTRLProximalraising when used to optimise estimators whose weights are stored as NumPy arrays, such as the factorization machines (facto). - Added a test covering every optimizer against every estimator that accepts one, so optimizer/estimator incompatibilities are caught going forward.
- Fixed
optim.losses.Hinge.gradientreturning different values for single samples and numpy batches at the exact margin (y * p == threshold): the batch path used a strict<while the single-sample path used<=. Both now use<=(matching scikit-learn), so a point on the margin is treated as a violation andlearn_one/learn_manyagree. This only affects samples lying exactly on the margin.
preprocessing¶
- Added a
window_sizeparameter topreprocessing.StandardScaler,preprocessing.MinMaxScaler, andpreprocessing.MaxAbsScaler. When set, the scaler tracks its statistics over the lastwindow_sizeobservations instead of the whole stream. - Added a
_from_stateclassmethod topreprocessing.MinMaxScaler,preprocessing.MaxAbsScaler, andpreprocessing.StandardScalerso a scaler can be warm-started from precomputed statistics without replaying past observations. preprocessing.FeatureHashernow hashes with MurmurHash3 in Rust, making it much faster. It gains analternate_signparameter (defaultTrue, matching scikit-learn) and returns a plaindict. Hashed feature indices differ from previous versions.preprocessing.OneHotEncodermini-batch methods (learn_many,transform_many) now accept and return any narwhals-supported eager backend (pandas, polars, pyarrow, ...) instead of being pandas-only, preserving the input backend (including the pandas index) on output. The pandas path keeps returningSparse[uint8]columns; other backends return dense integer columns, as they have no sparse-array equivalent.transform_manyonly requirespandaswhen the input is a pandas frame.preprocessing.OrdinalEncodermini-batch methods (learn_many,predict_many,predict_proba_many) now accept and return any narwhals-supported eager backend (pandas, polars, pyarrow, ...) instead of being pandas-only. The input backend is preserved on output, including the pandas index. These methods no longer requirepandasto be installed.
proba¶
- Added weighted sample support to
MultivariateGaussian.updateandMultivariateGaussian.revertby accepting an optionalwparameter and propagating it to the underlyingEmpiricalCovarianceinstance.
reco¶
- Corrected the type annotations of the weight/latent
defaultdicts inBiasedMF,Baseline, andFunkMF, and dropped the bespokereco.base.IDalias in favour oftyping.Hashable. Typing-only; no behavioral change.
utils¶
- Added
utils.math.norm_cdfandutils.math.norm_pdf, the CDF and PDF of the standard normal distribution (used bylinear_model.AdPredictor). utils.Rollingandutils.TimeRollingnow accept a class plus constructor keyword arguments, e.g.utils.Rolling(stats.Mean, window_size=3). This avoids silently sharing state when they are used ascollections.defaultdict` factories. Passing a pre-built instance still works but is deprecated and will be removed in a future release.
sketch¶
- Sped up
sketch.Histogram.updateby roughly 2× on typical data by operating on the underlying list directly and inlining the bin search, instead of going throughcollections.UserList. Outputs are unchanged. - Fixed
sketch.Histogram.__add__: merging two histograms now conserves the total count (point bins were previously double-counted) and setsnon the result, socdfno longer raises on merged histograms. Merging with an empty histogram also works now. sketch.Histogram.cdfanditer_cdfnow return0.0on an empty histogram instead of raising.
rules¶
- Fixed
RecursionErrorinAMRuleson long streams: theEBSTSplitter,TEBSTSplitter, andExhaustiveSplitternow traverse and deep-copy their search trees iteratively, so deeply-skewed trees no longer blow Python's recursion limit. - Fixed an
AMRulesmemory leak whereHoeffdingRule.expandappended a redundantNumericLiteralwhen a new split shared a feature and direction with an existing literal without tightening the threshold. Literal(and itsNumericLiteral/NominalLiteralsubclasses) no longer inherits frombase.Base, so its existing__slots__now actually takes effect — previously every literal still carried a__dict__becausebase.Basedefines no slots. Literals are internal rule components, not estimators, so the estimator machinery never applied. Trims memory on rule sets with many literals; behavior is unchanged.
stats¶
- Added
stats.ChiSquared, a streaming Chi-squared statistic between two categorical variables. Wrap it withutils.Rollingfor a rolling version.
tree¶
- Gave the binary-search-tree nodes of the numeric splitters (
EBSTSplitter/TEBSTSplitter,ExhaustiveSplitter,QOSplitter)__slots__. One node is created per distinct observed feature value, so on high-cardinality numeric streams these can number in the millions; dropping their per-instance__dict__trims memory (~40 bytes per node) with no change in behavior or throughput. - Slotted the
GradHessMeritsplit-candidate record used by the Stochastic Gradient Trees (tree.SGTClassifier/SGTRegressor) via@dataclass(slots=True), trimming its per-instance memory. Behavior is unchanged.
stream¶
- Added
stream.iter_frame, a dataframe-agnostic row iterator powered by Narwhals that works with any eager dataframe (pandas, polars, PyArrow, Modin, cuDF, ...). - Deprecated
stream.iter_pandasandstream.iter_polarsin favour ofstream.iter_frame. They now emit aDeprecationWarningand will be removed in a future release.