'A preference is estimated by computing the dot-product
of the user and item feature vectors.
Parameters
user_id: int or string
User for which recommendations are to be computed.
item_id:  int or string
ID of item for which wants to find the estimated preference.
Returns
Return an estimated preference if the user has not expressed a
preference for the item, or else the user\'s actual preference for the
item. If a preference cannot be estimated, returns None.'

def estimate_preference(self, user_id, item_id, **params):

    preference = self.model.preference_value(user_id, item_id)
    if (not np.isnan(preference)):
        return preference
    user_features = self.user_factors[np.where((self.model.user_ids() == user_id))]
    item_features = self.item_factors[np.where((self.model.item_ids() == item_id))]
    estimated = (self._global_bias + np.sum((user_features * item_features)))
    if self.capper:
        max_p = self.model.maximum_preference_value()
        min_p = self.model.minimum_preference_value()
        estimated = (max_p if (estimated > max_p) else (min_p if (estimated < min_p) else estimated))
    return estimated
