Identify the subset of desired `features` that are valid for the Kmeans
    model. A warning is emitted for each feature that is excluded.

    Parameters
    ----------
    features : list[str]
        Desired feature names.

    column_type_map : dict[str, type]
        Dictionary mapping each column name to the type of values in the
        column.

    valid_types : list[type]
        Exclude features whose type is not in this list.

    label : str
        Name of the row label column.

    Returns
    -------
    valid_features : list[str]
        Names of features to include in the model.

def _validate_features(features, column_type_map, valid_types, label):
    """
    Identify the subset of desired `features` that are valid for the Kmeans
    model. A warning is emitted for each feature that is excluded.

    Parameters
    ----------
    features : list[str]
        Desired feature names.

    column_type_map : dict[str, type]
        Dictionary mapping each column name to the type of values in the
        column.

    valid_types : list[type]
        Exclude features whose type is not in this list.

    label : str
        Name of the row label column.

    Returns
    -------
    valid_features : list[str]
        Names of features to include in the model.
    """
    if not isinstance(features, list):
        raise TypeError("Input 'features' must be a list, if specified.")

    if len(features) == 0:
        raise ValueError("If specified, input 'features' must contain " +
                         "at least one column name.")

    ## Remove duplicates
    num_original_features = len(features)
    features = set(features)

    if len(features) < num_original_features:
        _logging.warning("Duplicates have been removed from the list of features")

    ## Remove the row label
    if label in features:
        features.remove(label)
        _logging.warning("The row label has been removed from the list of features.")

    ## Check the type of each feature against the list of valid types
    valid_features = []

    for ftr in features:
        if not isinstance(ftr, str):
            _logging.warning("Feature '{}' excluded. ".format(ftr) +
                           "Features must be specified as strings " +
                           "corresponding to column names in the input dataset.")

        elif ftr not in column_type_map.keys():
            _logging.warning("Feature '{}' excluded because ".format(ftr) +
                           "it is not in the input dataset.")

        elif column_type_map[ftr] not in valid_types:
            _logging.warning("Feature '{}' excluded because of its type. ".format(ftr) +
                           "Kmeans features must be int, float, dict, or array.array type.")

        else:
            valid_features.append(ftr)

    if len(valid_features) == 0:
        raise _ToolkitError("All specified features have been excluded. " +
                            "Please specify valid features.")

    return valid_features