docs: def explain(self, userid, user_items, itemid, user_weights=None, N=10):
          """ Provides explanations for why the item is liked by the user.
  
          Parameters
          ---------
          userid : int
              The userid to explain recommendations for
          user_items : csr_matrix
              Sparse matrix containing the liked items for the user
          itemid : int
              The itemid to explain recommendations for
          user_weights : ndarray, optional
              Precomputed Cholesky decomposition of the weighted user liked items.
              Useful for speeding up repeated calls to this function, this value
              is returned
          N : int, optional
              The number of liked items to show the contribution for
  
          Returns
          -------
          total_score : float
              The total predicted score for this user/item pair
          top_contributions : list
              A list of the top N (itemid, score) contributions for this user/item pair
          user_weights : ndarray
              A factorized representation of the user. Passing this in to
              future 'explain' calls will lead to noticeable speedups
          """
          # user_weights = Cholesky decomposition of Wu^-1
          # from section 5 of the paper CF for Implicit Feedback Datasets
          user_items = user_items.tocsr()
          if user_weights is None:
              A, _ = user_linear_equation(self.item_factors, self.YtY,
                                          user_items, userid,
                                          self.regularization, self.factors)
              user_weights = scipy.linalg.cho_factor(A)
          seed_item = self.item_factors[itemid]
  
          # weighted_item = y_i^t W_u
          weighted_item = scipy.linalg.cho_solve(user_weights, seed_item)
  
          total_score = 0.0
          h = []
          for i, (itemid, confidence) in enumerate(nonzeros(user_items, userid)):
              if confidence < 0:
                  continue
  
              factor = self.item_factors[itemid]
              # s_u^ij = (y_i^t W^u) y_j
              score = weighted_item.dot(factor) * confidence
              total_score += score
              contribution = (score, itemid)
              if i < N:
                  heapq.heappush(h, contribution)
              else:
                  heapq.heappushpop(h, contribution)
  
          items = (heapq.heappop(h) for i in range(len(h)))
          top_contributions = list((i, s) for s, i in items)[::-1]
          return total_score, top_contributions, user_weights