ALSolver implements alternating least squares for matrix factorization to be used for building a recommender system
pip install pyalsolverALSolver is managed by uv. So to start clone this repo and run:
$ uv venv --python 3.12
$ uv syncAfter any edits or updates, run ruff to fix any formatting or lining issues:
$ uv run ruff format
$ uv run ruff checkfrom pyalsolver.utils import MovieLens, download_dataset,
# This will download the dataset if it doesn't exist
# or return its path if it exists
data_path = download_dataset('ml-32m')
print(data_path)
ml_dataset = MovieLens(
data_path
)from pyalsolver import ALSMF, ENGINE
from pyalsolver.utils import plot_rmse_history
model = ALSMF(0.2, 0.01, 0.01, k=20)
train_rmse_history, valid_rmse_history, loss_history = model.fit(
ml_dataset.Rui_train, ml_dataset.Riu_train, ml_dataset.Rui_valid,
n_epochs=10, engine=ENGINE.NUMBA
)
# to plot rmse history
plot_rmse_history(20, train_rmse_history, valid_rmse_history)uid = 10
pred_ratings, pred_item_indices = model.recommend(uid, topk=30)
pred_item_ids = [ml_dataset.idx_to_item_id[i] for i in pred_item_indices]
pred_item_titles = [ml_dataset.item_id_to_title[i] for i in pred_item_ids]
print(pred_ratings)
print(pred_item_titles)import numpy as np
pred_ratings, pred_item_indices = model.coldstart(
np.array([5]),
np.array([628]),
topk=40,
min_popularity=50 # Only consider items with at least 50 ratings
)
pred_item_ids = [ml_dataset.idx_to_item_id[i] for i in pred_item_indices]
pred_item_titles = [ml_dataset.item_id_to_title[i] for i in pred_item_ids]
print(pred_ratings)
print(pred_item_titles)The packages provide three engines for computation:
ENGINE.NUMPY: uses NumPy and is recommended for small datasetsENGINE_NUMBA: uses jitted numba code with not python objects and is recommended for large datasets.ENGINE_PARALLEL: uses Python process parallelization for spinning up multiple processes that work to update different portions of the latent. It is only recommended if the overhead of spinning up a new process doesn't exceed the time of computing one iteration
