| 130 | self.similar_items_index = index |
| 131 | |
| 132 | def similar_items( |
| 133 | self, itemid, N=10, recalculate_item=False, item_users=None, filter_items=None, items=None |
| 134 | ): |
| 135 | if items is not None and self.approximate_similar_items: |
| 136 | raise NotImplementedError("using an items filter isn't supported with ANN lookup") |
| 137 | |
| 138 | count = N |
| 139 | if filter_items is not None: |
| 140 | count += len(filter_items) |
| 141 | |
| 142 | if not self.approximate_similar_items or (self.use_gpu and count >= 1024): |
| 143 | return self.model.similar_items( |
| 144 | itemid, |
| 145 | N, |
| 146 | recalculate_item=recalculate_item, |
| 147 | item_users=item_users, |
| 148 | filter_items=filter_items, |
| 149 | items=items, |
| 150 | ) |
| 151 | |
| 152 | # support recalculate_item if possible. TODO: refactor this |
| 153 | if hasattr(self.model, "_item_factor"): |
| 154 | factors = self.model._item_factor(itemid, item_users, recalculate_item) # pylint: disable=protected-access |
| 155 | elif recalculate_item: |
| 156 | raise NotImplementedError(f"recalculate_item isn't supported with {self.model}") |
| 157 | else: |
| 158 | factors = self.model.item_factors[itemid] |
| 159 | if implicit.gpu.HAS_CUDA and isinstance(factors, implicit.gpu.Matrix): |
| 160 | factors = factors.to_numpy() |
| 161 | |
| 162 | if np.isscalar(itemid): |
| 163 | factors /= np.linalg.norm(factors) |
| 164 | factors = factors.reshape(1, -1) |
| 165 | else: |
| 166 | factors /= np.linalg.norm(factors, axis=1)[:, None] |
| 167 | |
| 168 | scores, ids = self.similar_items_index.search(factors.astype("float32"), count) |
| 169 | |
| 170 | if np.isscalar(itemid): |
| 171 | ids, scores = ids[0], scores[0] |
| 172 | |
| 173 | if filter_items is not None: |
| 174 | ids, scores = _filter_items_from_results(itemid, ids, scores, filter_items, N) |
| 175 | |
| 176 | return ids, scores |
| 177 | |
| 178 | def recommend( |
| 179 | self, |