diff --git a/src/lenskit/knn/item.py b/src/lenskit/knn/item.py index 60ad66de2..647140290 100644 --- a/src/lenskit/knn/item.py +++ b/src/lenskit/knn/item.py @@ -243,12 +243,14 @@ def __call__(self, query: QueryInput, items: ItemList) -> ItemList: assert isinstance(model, csr_array) model = model[:, ti_valid_nums] assert isinstance(model, csr_array) - # convert to CSC so we can count neighbors per target item. - model = model.tocsc() - # count neighborhood sizes - sizes = np.diff(model.indptr) # which neighborhoods are usable? (at least min neighbors) + m_ind = csr_array( + (np.ones(model.nnz, np.int32), model.indices, model.indptr), shape=model.shape + ) + sizes = m_ind.sum(0) + del m_ind + assert isinstance(sizes, np.ndarray) and len(sizes) == model.shape[1] scorable = sizes >= self.config.min_nbrs # fast-path neighborhoods that fit within max neighbors @@ -268,7 +270,7 @@ def __call__(self, query: QueryInput, items: ItemList) -> ItemList: # PyTorch, make a dense matrix (this is usually small enough to be # usable), and use the Torch topk function. slow_mat = model.T[~fast, :] - assert isinstance(slow_mat, csr_array) + # assert isinstance(slow_mat, csr_array) n_slow, _ = slow_mat.shape if n_slow: # mask for the slow items. diff --git a/tests/models/test_knn_item_item.py b/tests/models/test_knn_item_item.py index c22f1a826..8c6f9e46d 100644 --- a/tests/models/test_knn_item_item.py +++ b/tests/models/test_knn_item_item.py @@ -376,7 +376,7 @@ def test_ii_implicit_large(rng, ml_ratings): for user in users: recs = pipe.run("recommender", query=user, n=NRECS) - _log.info("user %s recs\n%s", user, recs) + _log.info("user %s recs\n%r", user, recs) assert isinstance(recs, ItemList) assert len(recs) == NRECS urates = ml_ratings[ml_ratings["user_id"] == user]