def recommend(self, users=None, k=10, exclude=None, items=None,
                  new_observation_data=None, new_user_data=None, new_item_data=None,
                  exclude_known=True, diversity=0, random_seed=None,
                  verbose=True):
        """
        Recommend the ``k`` highest scored items for each user.

        Parameters
        ----------
        users :  SArray, SFrame, or list, optional
            Users or observation queries for which to make recommendations.
            For list, SArray, and single-column inputs, this is simply a set
            of user IDs. By default, recommendations are returned for all
            users present when the model was trained. However, if the
            recommender model was created with additional features in the
            ``observation_data`` SFrame, then a corresponding SFrame of
            observation queries -- observation data without item or target
            columns -- can be passed to this method. For example, a model
            trained with user ID, item ID, time, and rating columns may be
            queried using an SFrame with user ID and time columns.  In this
            case, the user ID column must be present, and all column names
            should match those in the ``observation_data`` SFrame passed to
            ``create.``

        k : int, optional
            The number of recommendations to generate for each user.

        items : SArray, SFrame, or list, optional
            Restricts the items from which recommendations can be made. If
            ``items`` is an SArray, list, or SFrame with a single column,
            only items from the given set will be recommended. This can be
            used, for example, to restrict the recommendations to items
            within a particular category or genre. If ``items`` is an
            SFrame with user ID and item ID columns, then the item
            restriction is specialized to each user. For example, if
            ``items`` contains 3 rows with user U1 -- (U1, I1), (U1, I2),
            and (U1, I3) -- then the recommendations for user U1 are
            chosen from items I1, I2, and I3. By default, recommendations
            are made from all items present when the model was trained.

        new_observation_data : SFrame, optional
            ``new_observation_data`` gives additional observation data
            to the model, which may be used by the models to improve
            score and recommendation accuracy.  Must be in the same
            format as the observation data passed to ``create``.  How
            this data is used varies by model.

        new_user_data : SFrame, optional
            ``new_user_data`` may give additional user data to the
            model.  If present, scoring is done with reference to this
            new information.  If there is any overlap with the side
            information present at training time, then this new side
            data is preferred.  Must be in the same format as the user
            data passed to ``create``.

        new_item_data : SFrame, optional
            ``new_item_data`` may give additional item data to the
            model.  If present, scoring is done with reference to this
            new information.  If there is any overlap with the side
            information present at training time, then this new side
            data is preferred.  Must be in the same format as the item
            data passed to ``create``.

        exclude : SFrame, optional
            An :class:`~turicreate.SFrame` of user / item pairs.  The
            column names must be equal to the user and item columns of
            the main data, and it provides the model with user/item
            pairs to exclude from the recommendations.  These
            user-item-pairs are always excluded from the predictions,
            even if exclude_known is False.

        exclude_known : bool, optional
            By default, all user-item interactions previously seen in
            the training data, or in any new data provided using
            new_observation_data.., are excluded from the
            recommendations.  Passing in ``exclude_known = False``
            overrides this behavior.

        diversity : non-negative float, optional
            If given, then the recommend function attempts chooses a set
            of `k` items that are both highly scored and different from
            other items in that set. It does this by first retrieving
            ``k*(1+diversity)`` recommended items, then randomly
            choosing a diverse set from these items.  Suggested values
            for diversity are between 1 and 3.

        random_seed : int, optional
            If diversity is larger than 0, then some randomness is used;
            this controls the random seed to use for randomization.  If
            None, will be different each time.

        verbose : bool, optional
            If True, print the progress of generating recommendation.

        Returns
        -------
        out : SFrame
            A SFrame with the top ranked items for each user. The
            columns are: ``user_id``, ``item_id``, *score*,
            and *rank*, where ``user_id`` and ``item_id``
            match the user and item column names specified at training
            time.  The rank column is between 1 and ``k`` and gives
            the relative score of that item.  The value of score
            depends on the method used for recommendations.

        See Also
        --------
        recommend_from_interactions
        predict
        evaluate
        """
        from turicreate._cython.cy_server import QuietProgress

        assert type(k) == int

        column_types = self._get_data_schema()
        user_id = self.user_id
        item_id = self.item_id
        user_type = column_types[user_id]
        item_type = column_types[item_id]

        __null_sframe = _SFrame()

        if users is None:
            users = __null_sframe
        if exclude is None:
            exclude = __null_sframe
        if items is None:
            items = __null_sframe
        if new_observation_data is None:
            new_observation_data = __null_sframe
        if new_user_data is None:
            new_user_data = __null_sframe
        if new_item_data is None:
            new_item_data = __null_sframe

        if isinstance(users, list) or (_HAS_NUMPY and isinstance(users, _numpy.ndarray)):
            users = _SArray(users)

            # allow to take a list of dictionaries of the form [{'user_id':1,'time':10}] etc.
            if users.dtype == dict:
                users = users.unpack(column_name_prefix='')

        if isinstance(users, _SArray):
            users = _SFrame({user_id: users})

        if isinstance(items, list) or (_HAS_NUMPY and isinstance(items, _numpy.ndarray)):
            items = _SArray(items, dtype = item_type)

        if isinstance(items, _SArray):
            items = _SFrame({item_id: items})

        # Check type of incoming data.
        def check_type(arg, arg_name, required_type, allowed_types):
            if not isinstance(arg, required_type):
                raise TypeError("Parameter " + arg_name + " must be of type(s) "
                                + (", ".join(allowed_types))
                                + "; Type '" + str(type(arg)) + "' not recognized.")

        check_type(users, "users", _SFrame, ["SArray", "list", "SFrame", "numpy.ndarray"])
        check_type(exclude, "exclude", _SFrame, ["SFrame"])
        check_type(items, "items", _SFrame, ["SFrame", "SArray", "list", "numpy.ndarray"])
        check_type(new_observation_data, "new_observation_data", _SFrame, ["SFrame"])
        check_type(new_user_data, "new_user_data", _SFrame, ["SFrame"])
        check_type(new_item_data, "new_item_data", _SFrame, ["SFrame"])

        # See if we are in the situation where there are no users
        # originally.  In this case, the default type of the user
        # column is string, so we have to be mindful of that when
        # making recommendations and possibly cast it to string if
        # needed.

        # The only case where we need to deal with the user id is when
        # it's used to link with rated items in new_observation_data,
        # thus handle that case explicitly and error out in others.

        cast_user_to_string_type = False

        if self.num_users == 0:
            cast_user_to_string_type = True

            if users.num_rows() != 0:
                # In this case, the user column has actually been set to a
                # string type, so we need to make sure that we cast
                # everything back and forth to that to preserve type.

                if new_observation_data.num_rows() == 0:
                    raise ValueError("When users are not specified with the model, "
                                     "new_observation_data must be set in order to make recommendations.")

                new_observation_data[user_id] = new_observation_data[user_id].astype(user_type)

            else:
                print("WARNING: No users specified to model at creation time, so "
                      "calling recommend() for all users returns empty SFrame.")

        # Cast to the appropriate type if necessary.
        if users.num_rows() != 0:
            try:
                user_column = users[user_id]
            except RuntimeError:
                raise _ToolkitError("User column '%s' not present in input user data." % user_id)

            if cast_user_to_string_type:
                assert new_observation_data.num_rows() != 0
                original_user_type = user_column.dtype
                users[user_id] = user_column.astype(str)
                user_type=str

            elif user_column.dtype != user_type:
                users[user_id] = user_column.astype(user_type)

        # Cast user specified in exclude to the appropriate type if necessary.
        if user_id in exclude.column_names() and exclude[user_id].dtype!=user_type:
                exclude[user_id] = exclude[user_id].astype(user_type)

        try:
            diversity = float(diversity)
        except Exception:
            raise TypeError("Parameter diversity must be a floating point value equal to or larger than 0.")

        if diversity < 0:
            raise TypeError("Parameter diversity must be a floating point value equal to or larger than 0.")

        if random_seed is None:
            random_seed = hash("%.20f" % _time.time())
        else:
            try:
                random_seed = int(random_seed)
            except TypeError:
                raise TypeError("random_seed must be integer.")

        opt = {'model': self.__proxy__,
               'query': users,
               'top_k': k,
               'exclude': exclude,
               'restrictions': items,
               'new_data': new_observation_data,
               'new_user_data': new_user_data,
               'new_item_data': new_item_data,
               'exclude_known': exclude_known,
               'diversity' : diversity,
               'random_seed' : random_seed
               }

        with QuietProgress(verbose):
            recs = self.__proxy__.recommend(users, exclude, items, new_observation_data, new_user_data, 
                new_item_data, exclude_known, k, diversity, random_seed)

        if cast_user_to_string_type:
            recs[user_id] = recs[user_id].astype(original_user_type)

        return recs