docs: def predict(self, user, item):
  		"""
  		Predict count for combinations of users and items
  		
  		Note
  		----
  		You can either pass an individual user and item, or arrays representing
  		tuples (UserId, ItemId) with the combinatinons of users and items for which
  		to predict (one row per prediction).
  
  		Parameters
  		----------
  		user : array-like (npred,) or obj
  			User(s) for which to predict each item.
  		item: array-like (npred,) or obj
  			Item(s) for which to predict for each user.
  		"""
  		assert self.is_fitted
  		if isinstance(user, list) or isinstance(user, tuple):
  			user = np.array(user)
  		if isinstance(item, list) or isinstance(item, tuple):
  			item = np.array(item)
  		if user.__class__.__name__=='Series':
  			user = user.values
  		if item.__class__.__name__=='Series':
  			item = item.values
  			
  		if isinstance(user, np.ndarray):
  			if len(user.shape) > 1:
  				user = user.reshape(-1)
  			assert user.shape[0] > 0
  			if self.reindex:
  				if user.shape[0] > 1:
  					user = pd.Categorical(user, self.user_mapping_).codes
  				else:
  					if self.user_dict_ is not None:
  						try:
  							user = self.user_dict_[user]
  						except:
  							user = -1
  					else:
  						user = pd.Categorical(user, self.user_mapping_).codes[0]
  		else:
  			if self.reindex:
  				if self.user_dict_ is not None:
  					try:
  						user = self.user_dict_[user]
  					except:
  						user = -1
  				else:
  					user = pd.Categorical(np.array([user]), self.user_mapping_).codes[0]
  			user = np.array([user])
  			
  		if isinstance(item, np.ndarray):
  			if len(item.shape) > 1:
  				item = item.reshape(-1)
  			assert item.shape[0] > 0
  			if self.reindex:
  				if item.shape[0] > 1:
  					item = pd.Categorical(item, self.item_mapping_).codes
  				else:
  					if self.item_dict_ is not None:
  						try:
  							item = self.item_dict_[item]
  						except:
  							item = -1
  					else:
  						item = pd.Categorical(item, self.item_mapping_).codes[0]
  		else:
  			if self.reindex:
  				if self.item_dict_ is not None:
  					try:
  						item = self.item_dict_[item]
  					except:
  						item = -1
  				else:
  					item = pd.Categorical(np.array([item]), self.item_mapping_).codes[0]
  			item = np.array([item])
  
  		assert user.shape[0] == item.shape[0]
  		
  		if user.shape[0] == 1:
  			if (user[0] == -1) or (item[0] == -1):
  				return np.nan
  			else:
  				return self.Theta[user].dot(self.Beta[item].T).reshape(-1)[0]
  		else:
  			nan_entries = (user == -1) | (item == -1)
  			if nan_entries.sum() == 0:
  				if user.dtype != cython_loops.obj_ind_type:
  					user = user.astype(cython_loops.obj_ind_type)
  				if item.dtype != cython_loops.obj_ind_type:
  					item = item.astype(cython_loops.obj_ind_type)
  				return cython_loops.predict_arr(self.Theta, self.Beta, user, item, self.ncores)
  			else:
  				non_na_user = user[~nan_entries]
  				non_na_item = item[~nan_entries]
  				out = np.empty(user.shape[0], dtype=self.Theta.dtype)
  				out[~nan_entries] = cython_loops.predict_arr(self.Theta, self.Beta, non_na_user.astype(cython_loops.obj_ind_type), non_na_item.astype(cython_loops.obj_ind_type), self.ncores)
  				out[nan_entries] = np.nan
  				return out