'Returns the items that were most influential in recommending a
given item to a given user. In most implementations, this
method will return items that the user prefers and that
are similar to the given item.
Parameters
user_id : int or string
ID of the user who was recommended the item
item_id: int or string
ID of item that was recommended
how_many: int
Maximum number of items to return (default=None ALL)
Returns
The list of items ordered from most influential in
recommended the given item to least'

def recommended_because(self, user_id, item_id, how_many=None, **params):

    preferences = self.model.preferences_from_user(user_id)
    if self.model.has_preference_values():
        similarities = np.array([self.similarity.get_similarity(item_id, to_item_id) for (to_item_id, pref) in preferences if (to_item_id != item_id)]).flatten()
        prefs = np.array([pref for (it, pref) in preferences])
        item_ids = np.array([it for (it, pref) in preferences])
    else:
        similarities = np.array([self.similarity.get_similarity(item_id, to_item_id) for to_item_id in preferences if (to_item_id != item_id)]).flatten()
        prefs = np.array([1.0 for it in preferences])
        item_ids = np.array(preferences)
    scores = (prefs[(~ np.isnan(similarities))] * (1.0 + similarities[(~ np.isnan(similarities))]))
    sorted_preferences = np.lexsort((scores,))[::(-1)]
    sorted_preferences = (sorted_preferences[0:how_many] if (how_many and (sorted_preferences.size > how_many)) else sorted_preferences)
    if self.with_preference:
        top_n_recs = [(item_ids[ind], prefs[ind]) for ind in sorted_preferences]
    else:
        top_n_recs = [item_ids[ind] for ind in sorted_preferences]
    return top_n_recs
