Incremental fitting

Every recommender here also takes its interactions in batches. partial_fit(X, y=None) is SGDClassifier's protocol with one deliberate difference: a batch may name users and items the model has never seen, and the fitted vocabularies grow to admit them. The first call is equivalent to fit.

from skrecsys.recommendation import ItemKNNRecommender

rec = ItemKNNRecommender().partial_fit(monday)
rec.partial_fit(tuesday)  # new users, new items, new interactions
rec.recommend(["u1"], n_recommendations=10)

What it saves is the model fit, not every pass over the data: accumulating interactions_ costs one pass over everything stored so far whenever a new identifier renumbers the codes, and an index is rebuilt from scratch at the end of every call. What each estimator does with the batch differs, and its docstring says which of these it is.

Estimator partial_fit reproduces fit on the concatenated batches What it does
MostPopularRecommender yes adds the batch to the counts
ItemKNNRecommender yes recomputes the neighbour rows the batch reaches in two hops
BM25Recommender yes the same, but its corpus-wide statistics usually widen that to the whole catalog
RP3Beta yes the same, keeping walk_ so the column-wise pruning pass can be redone
EASE yes a Sherman-Morrison-Woodbury update of inverse_gram_, O(n_items² · users touched) instead of O(n_items³)
SLIMElasticNet no warm-started coordinate descent on the reachable columns over an updated gram_
AlternatingLeastSquares no resumes the ALS sweeps from the fitted parameters
BayesianPersonalizedRanking no resumes the descent, drawing every positive from the batch
skrecsys.nn models no resume training, rebuilding the module around the grown data and carrying the parameters and Adam's moments across

The four that say "no" are warm starts, and say so rather than hiding it: a model that resumes from where it stopped does not forget where that was. EASE and SLIMElasticNet keep a second matrix quadratic in the catalog once partial_fit is used.

The neural models work the same way, and need no torch to be installed for any of it. A fit keeps its trained parameters and Adam's moments as numpy arrays rather than as a live module, so the usual sequence just works — including across a pickle, which is the point of streaming:

import pickle

from skrecsys.nn import SimpleX

rec = SimpleX(n_factors=64, max_iter=20).fit(monday)
rec.partial_fit(tuesday)  # resumes where the fit stopped
rec = pickle.loads(pickle.dumps(rec))  # store it, reload it tomorrow
rec.partial_fit(wednesday)  # and carry on

The module itself is rebuilt from the grown interaction matrix on every call, because the padded histories, normalized adjacency and windowed sequences it holds are functions of that matrix and change meaning the moment the catalog grows. A sequential model (HSTU, Mamba4Rec) additionally keeps ordered_history_, the identifiers in the order they arrived, because a CSR row is a set and the order within a user is the whole of what those models read — one identifier pair per stored interaction, roughly what interactions_ already costs.