Instruction:
Can you write a function in Python 3 where it
explains prediction of a tree classifier.

Response:
def explain_prediction_tree_classifier(
        clf, doc,
        vec=None,
        top=None,
        top_targets=None,
        target_names=None,
        targets=None,
        feature_names=None,
        feature_re=None,
        feature_filter=None,
        vectorized=False):
    """ Explain prediction of a tree classifier.

    See :func:`eli5.explain_prediction` for description of
    ``top``, ``top_targets``, ``target_names``, ``targets``,
    ``feature_names``, ``feature_re`` and ``feature_filter`` parameters.

    ``vec`` is a vectorizer instance used to transform
    raw features to the input of the classifier ``clf``
    (e.g. a fitted CountVectorizer instance); you can pass it
    instead of ``feature_names``.

    ``vectorized`` is a flag which tells eli5 if ``doc`` should be
    passed through ``vec`` or not. By default it is False, meaning that
    if ``vec`` is not None, ``vec.transform([doc])`` is passed to the
    classifier. Set it to True if you're passing ``vec``,
    but ``doc`` is already vectorized.

    Method for determining feature importances follows an idea from
    http://blog.datadive.net/interpreting-random-forests/.
    Feature weights are calculated by following decision paths in trees
    of an ensemble (or a single tree for DecisionTreeClassifier).
    Each node of the tree has an output score, and contribution of a feature
    on the decision path is how much the score changes from parent to child.
    Weights of all features sum to the output score or proba of the estimator.
    """
    vec, feature_names = handle_vec(clf, doc, vec, vectorized, feature_names)
    X = get_X(doc, vec=vec, vectorized=vectorized)
    if feature_names.bias_name is None:
        # Tree estimators do not have an intercept, but here we interpret
        # them as having an intercept
        feature_names.bias_name = '<BIAS>'

    proba = predict_proba(clf, X)
    if hasattr(clf, 'decision_function'):
        score, = clf.decision_function(X)
    else:
        score = None

    is_multiclass = clf.n_classes_ > 2
    feature_weights = _trees_feature_weights(
        clf, X, feature_names, clf.n_classes_)
    x = get_X0(add_intercept(X))
    flt_feature_names, flt_indices = feature_names.handle_filter(
        feature_filter, feature_re, x)

    def _weights(label_id, scale=1.0):
        weights = feature_weights[:, label_id]
        return get_top_features_filtered(x, flt_feature_names, flt_indices,
                                         weights, top, scale)

    res = Explanation(
        estimator=repr(clf),
        method='decision path',
        targets=[],
        description=(DESCRIPTION_TREE_CLF_MULTICLASS if is_multiclass
                     else DESCRIPTION_TREE_CLF_BINARY),
    )
    assert res.targets is not None

    display_names = get_target_display_names(
        clf.classes_, target_names, targets, top_targets,
        score=score if score is not None else proba)

    if is_multiclass:
        for label_id, label in display_names:
            target_expl = TargetExplanation(
                target=label,
                feature_weights=_weights(label_id),
                score=score[label_id] if score is not None else None,
                proba=proba[label_id] if proba is not None else None,
            )
            add_weighted_spans(doc, vec, vectorized, target_expl)
            res.targets.append(target_expl)
    else:
        target, scale, label_id = get_binary_target_scale_label_id(
            score, display_names, proba)
        target_expl = TargetExplanation(
            target=target,
            feature_weights=_weights(label_id, scale=scale),
            score=score if score is not None else None,
            proba=proba[label_id] if proba is not None else None,
        )
        add_weighted_spans(doc, vec, vectorized, target_expl)
        res.targets.append(target_expl)

    return res


Instruction:
Make a summary of the following Python 3 code
def explain_prediction_tree_regressor(
        reg, doc,
        vec=None,
        top=None,
        top_targets=None,
        target_names=None,
        targets=None,
        feature_names=None,
        feature_re=None,
        feature_filter=None,
        vectorized=False):
    """ Explain prediction of a tree regressor.

    See :func:`eli5.explain_prediction` for description of
    ``top``, ``top_targets``, ``target_names``, ``targets``,
    ``feature_names``, ``feature_re`` and ``feature_filter`` parameters.

    ``vec`` is a vectorizer instance used to transform
    raw features to the input of the regressor ``reg``
    (e.g. a fitted CountVectorizer instance); you can pass it
    instead of ``feature_names``.

    ``vectorized`` is a flag which tells eli5 if ``doc`` should be
    passed through ``vec`` or not. By default it is False, meaning that
    if ``vec`` is not None, ``vec.transform([doc])`` is passed to the
    regressor. Set it to True if you're passing ``vec``,
    but ``doc`` is already vectorized.

    Method for determining feature importances follows an idea from
    http://blog.datadive.net/interpreting-random-forests/.
    Feature weights are calculated by following decision paths in trees
    of an ensemble (or a single tree for DecisionTreeRegressor).
    Each node of the tree has an output score, and contribution of a feature
    on the decision path is how much the score changes from parent to child.
    Weights of all features sum to the output score of the estimator.
    """
    vec, feature_names = handle_vec(reg, doc, vec, vectorized, feature_names)
    X = get_X(doc, vec=vec, vectorized=vectorized)
    if feature_names.bias_name is None:
        # Tree estimators do not have an intercept, but here we interpret
        # them as having an intercept
        feature_names.bias_name = '<BIAS>'

    score, = reg.predict(X)
    num_targets = getattr(reg, 'n_outputs_', 1)
    is_multitarget = num_targets > 1
    feature_weights = _trees_feature_weights(reg, X, feature_names, num_targets)
    x = get_X0(add_intercept(X))
    flt_feature_names, flt_indices = feature_names.handle_filter(
        feature_filter, feature_re, x)

    def _weights(label_id, scale=1.0):
        weights = feature_weights[:, label_id]
        return get_top_features_filtered(x, flt_feature_names, flt_indices,
                                         weights, top, scale)

    res = Explanation(
        estimator=repr(reg),
        method='decision path',
        description=(DESCRIPTION_TREE_REG_MULTITARGET if is_multitarget
                     else DESCRIPTION_TREE_REG),
        targets=[],
        is_regression=True,
    )
    assert res.targets is not None

    names = get_default_target_names(reg, num_targets=num_targets)
    display_names = get_target_display_names(names, target_names, targets,
                                             top_targets, score)

    if is_multitarget:
        for label_id, label in display_names:
            target_expl = TargetExplanation(
                target=label,
                feature_weights=_weights(label_id),
                score=score[label_id],
            )
            add_weighted_spans(doc, vec, vectorized, target_expl)
            res.targets.append(target_expl)
    else:
        target_expl = TargetExplanation(
            target=display_names[0][1],
            feature_weights=_weights(0),
            score=score,
        )
        add_weighted_spans(doc, vec, vectorized, target_expl)
        res.targets.append(target_expl)

    return res

Response: Explain prediction of a tree regressor.


Instruction:
How would you explain what the following Python 3 function does
def _trees_feature_weights(clf, X, feature_names, num_targets):
    feature_weights = np.zeros([len(feature_names), num_targets])
    if hasattr(clf, 'tree_'):
        _update_tree_feature_weights(X, feature_names, clf, feature_weights)
    else:
        if isinstance(clf, (
                GradientBoostingClassifier, GradientBoostingRegressor)):
            weight = clf.learning_rate
        else:
            weight = 1. / len(clf.estimators_)
        for _clfs in clf.estimators_:
            _update = partial(_update_tree_feature_weights, X, feature_names)
            if isinstance(_clfs, np.ndarray):
                if len(_clfs) == 1:
                    _update(_clfs[0], feature_weights)
                else:
                    for idx, _clf in enumerate(_clfs):
                        _update(_clf, feature_weights[:, idx])
            else:
                _update(_clfs, feature_weights)
        feature_weights *= weight
        if hasattr(clf, 'init_'):
            feature_weights[feature_names.bias_idx] += clf.init_.predict(X)[0]
    return feature_weights

Response: Return feature weights for a tree or a tree ensemble.


Instruction:
Write a Python 3 script for
updating tree feature weights using decision path method.

Response:
def _update_tree_feature_weights(X, feature_names, clf, feature_weights):
    """ Update tree feature weights using decision path method.
    """
    tree_value = clf.tree_.value
    if tree_value.shape[1] == 1:
        squeeze_axis = 1
    else:
        assert tree_value.shape[2] == 1
        squeeze_axis = 2
    tree_value = np.squeeze(tree_value, axis=squeeze_axis)
    tree_feature = clf.tree_.feature
    _, indices = clf.decision_path(X).nonzero()
    if isinstance(clf, DecisionTreeClassifier):
        norm = lambda x: x / x.sum()
    else:
        norm = lambda x: x
    feature_weights[feature_names.bias_idx] += norm(tree_value[0])
    for parent_idx, child_idx in zip(indices, indices[1:]):
        assert tree_feature[parent_idx] >= 0
        feature_idx = tree_feature[parent_idx]
        diff = norm(tree_value[child_idx]) - norm(tree_value[parent_idx])
        feature_weights[feature_idx] += diff


Instruction:
Can you generate the documentation for the following Python 3 function
def _multiply(X, coef):
    if sp.issparse(X):
        return X.multiply(sp.csr_matrix(coef))
    else:
        return np.multiply(X, coef)

Response: Multiplies X by coef element - wise preserving sparsity.


Instruction:
Can you implement a function in Python 3 that
returns linear weights getter for label_id.

Response:
def _linear_weights(clf, x, top, flt_feature_names, flt_indices):
    """ Return top weights getter for label_id.
    """
    def _weights(label_id, scale=1.0):
        coef = get_coef(clf, label_id)
        scores = _multiply(x, coef)
        return get_top_features_filtered(x, flt_feature_names, flt_indices,
                                         scores, top, scale)
    return _weights


Instruction:
Implement a function in Python 3 to
like attr. s but with slots = True and attributes extracted from the class s __init__ method signature.

Response:
def attrs(class_):
    """ Like attr.s with slots=True,
    but with attributes extracted from __init__ method signature.
    slots=True ensures that signature matches what really happens
    (we can't define different attributes on self).
    It is useful if we still want __init__ for proper type-checking and
    do not want to repeat attribute definitions in the class body.
    """
    attrs_kwargs = {}
    for method, kw_name in [
            ('__repr__', 'repr'),
            ('__eq__', 'cmp'),
            ('__hash__', 'hash'),
            ]:
        if method in class_.__dict__:
            # Allow to redefine a special method (or else attr.s will do it)
            attrs_kwargs[kw_name] = False
    init_args = inspect.getargspec(class_.__init__)
    defaults_shift = len(init_args.args) - len(init_args.defaults or []) - 1
    these = {}
    for idx, arg in enumerate(init_args.args[1:]):
        attrib_kwargs = {}
        if idx >= defaults_shift:
            attrib_kwargs['default'] = init_args.defaults[idx - defaults_shift]
        these[arg] = attr.ib(**attrib_kwargs)
    return attr.s(class_, these=these, init=False, slots=True, **attrs_kwargs)


Instruction:
How would you implement a function in Python 3 that
returns True if a classifier can return probabilities.

Response:
def is_probabilistic_classifier(clf):
    # type: (Any) -> bool
    """ Return True if a classifier can return probabilities """
    if not hasattr(clf, 'predict_proba'):
        return False
    if isinstance(clf, OneVsRestClassifier):
        # It currently has a predict_proba method, but does not check if
        # wrapped estimator has a predict_proba method.
        return hasattr(clf.estimator, 'predict_proba')
    return True


Instruction:
Can you write a function in Python 3 where it
predicts the probability of X in the node.

Response:
def predict_proba(estimator, X):
    # type: (Any, Any) -> Optional[np.ndarray]
    """ Return result of predict_proba, if an estimator supports it, or None.
    """
    if is_probabilistic_classifier(estimator):
        try:
            proba, = estimator.predict_proba(X)
            return proba
        except NotImplementedError:
            return None
    else:
        return None


Instruction:
Given the following Python 3 function, write the documentation
def has_intercept(estimator):
    # type: (Any) -> bool
    """ Return True if an estimator has intercept fit. """
    if hasattr(estimator, 'fit_intercept'):
        return estimator.fit_intercept
    if hasattr(estimator, 'intercept_'):
        if estimator.intercept_ is None:
            return False
        # scikit-learn sets intercept to zero vector if it is not fit
        return np.any(estimator.intercept_)
    return False

Response: Return True if an estimator has intercept fit.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_feature_names(clf, vec=None, bias_name='<BIAS>', feature_names=None,
                      num_features=None, estimator_feature_names=None):
    # type: (Any, Any, Optional[str], Any, int, Any) -> FeatureNames
    """
    Return a FeatureNames instance that holds all feature names
    and a bias feature.
    If vec is None or doesn't have get_feature_names() method,
    features are named x0, x1, x2, etc.
    """
    if not has_intercept(clf):
        bias_name = None

    if feature_names is None:
        if vec and hasattr(vec, 'get_feature_names'):
            return FeatureNames(vec.get_feature_names(), bias_name=bias_name)
        else:
            if estimator_feature_names is None:
                num_features = num_features or get_num_features(clf)
                return FeatureNames(
                    n_features=num_features,
                    unkn_template='x%d',
                    bias_name=bias_name
                )
            return FeatureNames(estimator_feature_names, bias_name=bias_name)

    num_features = num_features or get_num_features(clf)
    if isinstance(feature_names, FeatureNames):
        if feature_names.n_features != num_features:
            raise ValueError("feature_names has a wrong n_features: "
                             "expected=%d, got=%d" % (num_features,
                                                      feature_names.n_features))
        # Make a shallow copy setting proper bias_name
        return FeatureNames(
            feature_names.feature_names,
            n_features=num_features,
            bias_name=bias_name,
            unkn_template=feature_names.unkn_template)
    else:
        if len(feature_names) != num_features:
            raise ValueError("feature_names has a wrong length: "
                             "expected=%d, got=%d" % (num_features,
                                                      len(feature_names)))
        return FeatureNames(feature_names, bias_name=bias_name)

Response: Returns a list of feature names for a given class.


Instruction:
Here you have a function in Python 3, explain what it does
def get_default_target_names(estimator, num_targets=None):
    if num_targets is None:
        if len(estimator.coef_.shape) <= 1:
            num_targets = 1
        else:
            num_targets, _ = estimator.coef_.shape
    if num_targets == 1:
        target_names = ['y']
    else:
        target_names = ['y%d' % i for i in range(num_targets)]
    return np.array(target_names)

Response: Return a vector of target names for the default estimator.


Instruction:
Implement a function in Python 3 to
return a vector of coefficients for a given label.

Response:
def get_coef(clf, label_id, scale=None):
    """
    Return a vector of coefficients for a given label,
    including bias feature.

    ``scale`` (optional) is a scaling vector; coef_[i] => coef[i] * scale[i] if
    scale[i] is not nan. Intercept is not scaled.
    """
    if len(clf.coef_.shape) == 2:
        # Most classifiers (even in binary case) and regressors
        coef = _dense_1d(clf.coef_[label_id])
    elif len(clf.coef_.shape) == 1:
        # SGDRegressor stores coefficients in a 1D array
        if label_id != 0:
            raise ValueError(
                'Unexpected label_id %s for 1D coefficient' % label_id)
        coef = _dense_1d(clf.coef_)
    elif len(clf.coef_.shape) == 0:
        # Lasso with one feature: 0D array
        coef = np.array([clf.coef_])
    else:
        raise ValueError('Unexpected clf.coef_ shape: %s' % clf.coef_.shape)

    if scale is not None:
        if coef.shape != scale.shape:
            raise ValueError("scale shape is incorrect: expected %s, got %s" % (
                coef.shape, scale.shape,
            ))
        # print("shape is ok")
        not_nan = ~np.isnan(scale)
        coef = coef.copy()
        coef[not_nan] *= scale[not_nan]

    if not has_intercept(clf):
        return coef
    if label_id == 0 and not isinstance(clf.intercept_, np.ndarray):
        bias = clf.intercept_
    else:
        bias = clf.intercept_[label_id]
    return np.hstack([coef, bias])


Instruction:
Implement a Python 3 function for
returning the size of a feature vector estimator expects as an input.

Response:
def get_num_features(estimator):
    """ Return size of a feature vector estimator expects as an input. """
    if hasattr(estimator, 'coef_'):  # linear models
        if len(estimator.coef_.shape) == 0:
            return 1
        return estimator.coef_.shape[-1]
    elif hasattr(estimator, 'feature_importances_'):  # ensembles
        return estimator.feature_importances_.shape[-1]
    elif hasattr(estimator, 'feature_count_'):  # naive bayes
        return estimator.feature_count_.shape[-1]
    elif hasattr(estimator, 'theta_'):
        return estimator.theta_.shape[-1]
    elif hasattr(estimator, 'estimators_') and len(estimator.estimators_):
        # OvR
        return get_num_features(estimator.estimators_[0])
    else:
        raise ValueError("Can't figure out feature vector size for %s" %
                         estimator)


Instruction:
Explain what the following Python 3 code does
def get_X0(X):
    if pandas_available and isinstance(X, pd.DataFrame):
        assert len(X) == 1
        x = np.array(X.iloc[0])
    else:
        x, = X
    return x

Response: Return zero - th element of a one - element data container.


Instruction:
Implement a Python 3 function for
adding intercept column to X

Response:
def add_intercept(X):
    """ Add intercept column to X """
    intercept = np.ones((X.shape[0], 1))
    if sp.issparse(X):
        return sp.hstack([X, intercept]).tocsr()
    else:
        return np.hstack([X, intercept])


Instruction:
Implement a Python 3 function for
explaining sklearn_crfsuite. CRF weights.

Response:
def explain_weights_sklearn_crfsuite(crf,
                                     top=20,
                                     target_names=None,
                                     targets=None,
                                     feature_re=None,
                                     feature_filter=None):
    """ Explain sklearn_crfsuite.CRF weights.

    See :func:`eli5.explain_weights` for description of
    ``top``, ``target_names``, ``targets``,
    ``feature_re`` and ``feature_filter`` parameters.
    """
    feature_names = np.array(crf.attributes_)
    state_coef = crf_state_coef(crf).todense().A
    transition_coef = crf_transition_coef(crf)

    if feature_filter is not None or feature_re is not None:
        state_feature_names, flt_indices = (
            FeatureNames(feature_names).handle_filter(feature_filter, feature_re))
        state_feature_names = np.array(state_feature_names.feature_names)
        state_coef = state_coef[:, flt_indices]
    else:
        state_feature_names = feature_names

    def _features(label_id):
        return get_top_features(state_feature_names, state_coef[label_id], top)

    if targets is None:
        targets = sorted_for_ner(crf.classes_)

    display_names = get_target_display_names(crf.classes_, target_names,
                                             targets)
    indices, names = zip(*display_names)
    transition_coef = filter_transition_coefs(transition_coef, indices)

    return Explanation(
        targets=[
            TargetExplanation(
                target=label,
                feature_weights=_features(label_id)
            )
            for label_id, label in zip(indices, names)
        ],
        transition_features=TransitionFeatureWeights(
            class_names=names,
            coef=transition_coef,
        ),
        estimator=repr(crf),
        method='CRF',
    )


Instruction:
Can you implement a function in Python 3 that
filters the transition coefficients by indices.

Response:
def filter_transition_coefs(transition_coef, indices):
    """
    >>> coef = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
    >>> filter_transition_coefs(coef, [0])
    array([[0]])
    >>> filter_transition_coefs(coef, [1, 2])
    array([[4, 5],
           [7, 8]])
    >>> filter_transition_coefs(coef, [2, 0])
    array([[8, 6],
           [2, 0]])
    >>> filter_transition_coefs(coef, [0, 1, 2])
    array([[0, 1, 2],
           [3, 4, 5],
           [6, 7, 8]])
    """
    indices = np.array(indices)
    rows = transition_coef[indices]
    return rows[:,indices]


Instruction:
Can you implement a function in Python 3 that
returns a list of crf_classes sorted in a default order suitable for NER tasks.

Response:
def sorted_for_ner(crf_classes):
    """
    Return labels sorted in a default order suitable for NER tasks:

    >>> sorted_for_ner(['B-ORG', 'B-PER', 'O', 'I-PER'])
    ['O', 'B-ORG', 'B-PER', 'I-PER']
    """
    def key(cls):
        if len(cls) > 2 and cls[1] == '-':
            # group names like B-ORG and I-ORG together
            return cls.split('-', 1)[1], cls
        return '', cls
    return sorted(crf_classes, key=key)


Instruction:
How would you code a function in Python 3 to
convert a numpy object to their python equivalents. Return converted object.

Response:
def _numpy_to_python(obj):
    """ Convert an nested dict/list/tuple that might contain numpy objects
    to their python equivalents. Return converted object.
    """
    if isinstance(obj, dict):
        return {k: _numpy_to_python(v) for k, v in obj.items()}
    elif isinstance(obj, (list, tuple, np.ndarray)):
        return [_numpy_to_python(x) for x in obj]
    elif isinstance(obj, FormattedFeatureName):
        return obj.value
    elif isinstance(obj, _numpy_string_types):
        return six.text_type(obj)
    elif hasattr(obj, 'dtype') and np.isscalar(obj):
        if np.issubdtype(obj, np.floating):
            return float(obj)
        elif np.issubdtype(obj, np.integer):
            return int(obj)
        elif np.issubdtype(obj, np.bool_):
            return bool(obj)
    return obj


Instruction:
Explain what the following Python 3 code does
def _sampler_n_samples(self, n_samples):
        sampler_indices = self.rng_.choice(range(len(self.samplers)),
                                           size=n_samples,
                                           replace=True,
                                           p=self.weights)
        return [
            (self.samplers[idx], freq)
            for idx, freq in itemfreq(sampler_indices)
        ]

Response: Return n_samplers sampler tuples


Instruction:
Write a Python 3 script to
sample near the document by replacing some of its features with values sampled from distribution found by KDE.

Response:
def sample_near(self, doc, n_samples=1):
        """
        Sample near the document by replacing some of its features
        with values sampled from distribution found by KDE.
        """
        doc = np.asarray(doc)
        num_features = len(self.kdes_)
        sizes = self.rng_.randint(low=1, high=num_features + 1, size=n_samples)
        samples = []
        for size in sizes:
            to_change = self.rng_.choice(num_features, size, replace=False)
            new_doc = doc.copy()
            for i in to_change:
                kde = self.kdes_[i]
                new_doc[i] = kde.sample(random_state=self.rng_).ravel()
            samples.append(new_doc)
        samples = np.asarray(samples)
        return samples, self._similarity(doc, samples)


Instruction:
How would you implement a function in Python 3 that
returns a list of all feature names for a given feature.

Response:
def _all_feature_names(name):
    # type: (Union[str, bytes, List[Dict]]) -> List[str]
    """ All feature names for a feature: usually just the feature itself,
    but can be several features for unhashed features with collisions.
    """
    if isinstance(name, bytes):
        return [name.decode('utf8')]
    elif isinstance(name, list):
        return [x['name'] for x in name]
    else:
        return [name]


Instruction:
Explain what the following Python 3 code does
def filtered(self, feature_filter, x=None):
        # type: (Callable, Any) -> Tuple[FeatureNames, List[int]]
        """ Return feature names filtered by a regular expression
        ``feature_re``, and indices of filtered elements.
        """
        indices = []
        filtered_feature_names = []
        indexed_names = None  # type: Optional[Iterable[Tuple[int, Any]]]
        if isinstance(self.feature_names, (np.ndarray, list)):
            indexed_names = enumerate(self.feature_names)
        elif isinstance(self.feature_names, dict):
            indexed_names = six.iteritems(self.feature_names)
        elif self.feature_names is None:
            indexed_names = []
        assert indexed_names is not None

        if x is not None:
            if sp.issparse(x) and len(x.shape) == 2:
                assert x.shape[0] == 1
                flt = lambda nm, i: feature_filter(nm, x[0, i])
            else:
                # FIXME: mypy warns about x[i] because it thinks x can be None
                flt = lambda nm, i: feature_filter(nm, x[i])  # type: ignore
        else:
            flt = lambda nm, i: feature_filter(nm)

        for idx, name in indexed_names:
            if any(flt(nm, idx) for nm in _all_feature_names(name)):
                indices.append(idx)
                filtered_feature_names.append(name)
        if self.has_bias and flt(self.bias_name, self.bias_idx):
            assert self.bias_idx is not None  # for mypy
            bias_name = self.bias_name
            indices.append(self.bias_idx)
        else:
            bias_name = None
        return (
            FeatureNames(
                filtered_feature_names,
                bias_name=bias_name,
                unkn_template=self.unkn_template,
            ),
            indices)

Response:
Return a list of feature names filtered by a regular expression
        feature_re and indices of filtered elements.


Instruction:
Explain what the following Python 3 code does
def add_feature(self, feature):
        # type: (Any) -> int
        """ Add a new feature name, return it's index.
        """
        # A copy of self.feature_names is always made, because it might be
        # "owned" by someone else.
        # It's possible to make the copy only at the first call to
        # self.add_feature to improve performance.
        idx = self.n_features
        if isinstance(self.feature_names, (list, np.ndarray)):
            self.feature_names = list(self.feature_names)
            self.feature_names.append(feature)
        elif isinstance(self.feature_names, dict):
            self.feature_names = dict(self.feature_names)
            self.feature_names[idx] = feature
        elif self.feature_names is None:
            self.feature_names = {idx: feature}
        self.n_features += 1
        return idx

Response: Add a new feature name to the internal list of features. Return the index of the new feature name.


Instruction:
Given the following Python 3 function, write the documentation
def format_as_text(expl,  # type: Explanation
                   show=fields.ALL,
                   highlight_spaces=None,  # type: Optional[bool]
                   show_feature_values=False,  # type: bool
                   ):
    # type: (...) -> str
    """ Format explanation as text.

    Parameters
    ----------
    expl : eli5.base.Explanation
        Explanation returned by ``eli5.explain_weights`` or
        ``eli5.explain_prediction`` functions.

    highlight_spaces : bool or None, optional
        Whether to highlight spaces in feature names. This is useful if
        you work with text and have ngram features which may include spaces
        at left or right. Default is None, meaning that the value used
        is set automatically based on vectorizer and feature values.

    show_feature_values : bool
        When True, feature values are shown along with feature contributions.
        Default is False.

    show : List[str], optional
        List of sections to show. Allowed values:

        * 'targets' - per-target feature weights;
        * 'transition_features' - transition features of a CRF model;
        * 'feature_importances' - feature importances of a decision tree or
          an ensemble-based estimator;
        * 'decision_tree' - decision tree in a graphical form;
        * 'method' - a string with explanation method;
        * 'description' - description of explanation method and its caveats.

        ``eli5.formatters.fields`` provides constants that cover common cases:
        ``INFO`` (method and description), ``WEIGHTS`` (all the rest),
        and ``ALL`` (all).
    """
    lines = []  # type: List[str]

    if highlight_spaces is None:
        highlight_spaces = should_highlight_spaces(expl)

    if expl.error:  # always shown
        lines.extend(_error_lines(expl))

    explaining_prediction = has_any_values_for_weights(expl)
    show_feature_values = show_feature_values and explaining_prediction

    for key in show:
        if not getattr(expl, key, None):
            continue

        if key == 'method':
            lines.extend(_method_lines(expl))

        if key == 'description':
            lines.extend(_description_lines(expl))

        if key == 'transition_features':
            lines.extend(_transition_features_lines(expl))

        if key == 'targets':
            lines.extend(_targets_lines(
                expl,
                hl_spaces=highlight_spaces,
                show_feature_values=show_feature_values,
                explaining_prediction=explaining_prediction,
            ))

        if key == 'feature_importances':
            lines.extend(_feature_importances_lines(
                expl, hl_spaces=highlight_spaces))

        if key == 'decision_tree':
            lines.extend(_decision_tree_lines(expl))

    return '\n'.join(lines)

Response: Format an explanation as text.


Instruction:
How would you implement a function in Python 3 that
formats feature name for hashed features.

Response:
def _format_unhashed_feature(name, hl_spaces, sep=' | '):
    # type: (List, bool, str) -> str
    """
    Format feature name for hashed features.
    """
    return sep.join(
        format_signed(n, _format_single_feature, hl_spaces=hl_spaces)
        for n in name)


Instruction:
Write a Python 3 script to
return a ``(pos, neg)`` tuple. ``pos`` and ``neg`` are lists of ``(name, value)`` tuples for features with positive and negative coefficients. Parameters: * ``feature_names`` - a vector of feature names; * ``coef`` - coefficient vector; coef.shape must be equal to feature_names.shape; * ``top`` can be either a number or a ``(num_pos, num_neg)`` tuple. If ``top`` is a number, ``top`` features with largest absolute coefficients are returned. If it is a ``(num_pos, num_neg)`` tuple, the function returns no more than ``num_pos`` positive features and no more than ``num_neg`` negative features. ``None`` value means 'no limit'. * ``x`` is a vector of feature values, passed to FeatureWeight.value.

Response:
def _get_top_features(feature_names, coef, top, x):
    """
    Return a ``(pos, neg)`` tuple. ``pos`` and ``neg`` are lists of
    ``(name, value)`` tuples for features with positive and negative
    coefficients.

    Parameters:

    * ``feature_names`` - a vector of feature names;
    * ``coef`` - coefficient vector; coef.shape must be equal to
      feature_names.shape;
    * ``top`` can be either a number or a ``(num_pos, num_neg)`` tuple.
      If ``top`` is a number, ``top`` features with largest absolute
      coefficients are returned. If it is a ``(num_pos, num_neg)`` tuple,
      the function returns no more than ``num_pos`` positive features and
      no more than ``num_neg`` negative features. ``None`` value means
      'no limit'.
    * ``x`` is a vector of feature values, passed to FeatureWeight.value.
    """
    if isinstance(top, (list, tuple)):
        num_pos, num_neg = list(top)  # "list" is just for mypy
        pos = _get_top_positive_features(feature_names, coef, num_pos, x)
        neg = _get_top_negative_features(feature_names, coef, num_neg, x)
    else:
        pos, neg = _get_top_abs_features(feature_names, coef, top, x)
    return pos, neg


Instruction:
Can you generate the documentation for the following Python 3 function
def get_char_weights(doc_weighted_spans, preserve_density=None):
    # type: (DocWeightedSpans, Optional[bool]) -> np.ndarray
    """ Return character weights for a text document with highlighted features.
    If preserve_density is True, then color for longer fragments will be
    less intensive than for shorter fragments, so that "sum" of intensities
    will correspond to feature weight.
    If preserve_density is None, then it's value is taken from
    the corresponding attribute of doc_weighted_spans.
    """
    if preserve_density is None:
        preserve_density = doc_weighted_spans.preserve_density
    char_weights = np.zeros(len(doc_weighted_spans.document))
    feature_counts = Counter(f for f, _, __ in doc_weighted_spans.spans)
    for feature, spans, weight in doc_weighted_spans.spans:
        for start, end in spans:
            # start can be -1 for char_wb at the start of the document.
            start = max(0, start)
            if preserve_density:
                weight /= (end - start)
            weight /= feature_counts[feature]
            char_weights[start:end] += weight
    return char_weights

Response: Return the character weights for a text document with highlighted features.


Instruction:
How would you code a function in Python 3 to
prepare weighted spans for rendering.

Response:
def prepare_weighted_spans(targets,  # type: List[TargetExplanation]
                           preserve_density=None,  # type: Optional[bool]
                           ):
    # type: (...) -> List[Optional[List[PreparedWeightedSpans]]]
    """ Return weighted spans prepared for rendering.
    Calculate a separate weight range for each different weighted
    span (for each different index): each target has the same number
    of weighted spans.
    """
    targets_char_weights = [
        [get_char_weights(ws, preserve_density=preserve_density)
         for ws in t.weighted_spans.docs_weighted_spans]
         if t.weighted_spans else None
         for t in targets]  # type: List[Optional[List[np.ndarray]]]
    max_idx = max_or_0(len(ch_w or []) for ch_w in targets_char_weights)

    targets_char_weights_not_None = [
        cw for cw in targets_char_weights
        if cw is not None]  # type: List[List[np.ndarray]]

    spans_weight_ranges = [
        max_or_0(
            abs(x) for char_weights in targets_char_weights_not_None
            for x in char_weights[idx])
        for idx in range(max_idx)]
    return [
        [PreparedWeightedSpans(ws, char_weights, weight_range)
         for ws, char_weights, weight_range in zip(
            t.weighted_spans.docs_weighted_spans,  # type: ignore
            t_char_weights,
            spans_weight_ranges)]
        if t_char_weights is not None else None
        for t, t_char_weights in zip(targets, targets_char_weights)]


Instruction:
Explain what the following Python 3 code does
def build_span_analyzer(document, vec):
    preprocessed_doc = vec.build_preprocessor()(vec.decode(document))
    analyzer = None
    if vec.analyzer == 'word' and vec.tokenizer is None:
        stop_words = vec.get_stop_words()
        tokenize = _build_tokenizer(vec)
        analyzer = lambda doc: _word_ngrams(vec, tokenize(doc), stop_words)
    elif vec.analyzer == 'char':
        preprocessed_doc = vec._white_spaces.sub(' ', preprocessed_doc)
        analyzer = lambda doc: _char_ngrams(vec, doc)
    elif vec.analyzer == 'char_wb':
        preprocessed_doc = vec._white_spaces.sub(' ', preprocessed_doc)
        analyzer = lambda doc: _char_wb_ngrams(vec, doc)
    return analyzer, preprocessed_doc

Response: Build an analyzer and preprocessed doc.


Instruction:
How would you implement a function in Python 3 that
returns an explanation of an XGBoost estimator or XGBRegressor or XGBClassifier or XGBClassifier or XGBRegressor.

Response:
def explain_weights_xgboost(xgb,
                            vec=None,
                            top=20,
                            target_names=None,  # ignored
                            targets=None,  # ignored
                            feature_names=None,
                            feature_re=None,  # type: Pattern[str]
                            feature_filter=None,
                            importance_type='gain',
                            ):
    """
    Return an explanation of an XGBoost estimator (via scikit-learn wrapper
    XGBClassifier or XGBRegressor, or via xgboost.Booster)
    as feature importances.

    See :func:`eli5.explain_weights` for description of
    ``top``, ``feature_names``,
    ``feature_re`` and ``feature_filter`` parameters.

    ``target_names`` and ``targets`` parameters are ignored.

    Parameters
    ----------
    importance_type : str, optional
        A way to get feature importance. Possible values are:

        - 'gain' - the average gain of the feature when it is used in trees
          (default)
        - 'weight' - the number of times a feature is used to split the data
          across all trees
        - 'cover' - the average coverage of the feature when it is used in trees
    """
    booster, is_regression = _check_booster_args(xgb)
    xgb_feature_names = booster.feature_names
    coef = _xgb_feature_importances(booster, importance_type=importance_type)
    return get_feature_importance_explanation(
        xgb, vec, coef,
        feature_names=feature_names,
        estimator_feature_names=xgb_feature_names,
        feature_filter=feature_filter,
        feature_re=feature_re,
        top=top,
        description=DESCRIPTION_XGBOOST,
        is_regression=is_regression,
        num_features=coef.shape[-1],
    )


Instruction:
Implement a Python 3 function for
returning an explanation of XGBoost prediction for a given document.

Response:
def explain_prediction_xgboost(
        xgb, doc,
        vec=None,
        top=None,
        top_targets=None,
        target_names=None,
        targets=None,
        feature_names=None,
        feature_re=None,  # type: Pattern[str]
        feature_filter=None,
        vectorized=False,  # type: bool
        is_regression=None,  # type: bool
        missing=None,  # type: bool
        ):
    """ Return an explanation of XGBoost prediction (via scikit-learn wrapper
    XGBClassifier or XGBRegressor, or via xgboost.Booster) as feature weights.

    See :func:`eli5.explain_prediction` for description of
    ``top``, ``top_targets``, ``target_names``, ``targets``,
    ``feature_names``, ``feature_re`` and ``feature_filter`` parameters.

    Parameters
    ----------
    vec : vectorizer, optional
        A vectorizer instance used to transform
        raw features to the input of the estimator ``xgb``
        (e.g. a fitted CountVectorizer instance); you can pass it
        instead of ``feature_names``.

    vectorized : bool, optional
        A flag which tells eli5 if ``doc`` should be
        passed through ``vec`` or not. By default it is False, meaning that
        if ``vec`` is not None, ``vec.transform([doc])`` is passed to the
        estimator. Set it to True if you're passing ``vec``,
        but ``doc`` is already vectorized.

    is_regression : bool, optional
        Pass if an ``xgboost.Booster`` is passed as the first argument.
        True if solving a regression problem ("objective" starts with "reg")
        and False for a classification problem.
        If not set, regression is assumed for a single target estimator
        and proba will not be shown.

    missing : optional
        Pass if an ``xgboost.Booster`` is passed as the first argument.
        Set it to the same value as the ``missing`` argument to
        ``xgboost.DMatrix``.
        Matters only if sparse values are used. Default is ``np.nan``.

    Method for determining feature importances follows an idea from
    http://blog.datadive.net/interpreting-random-forests/.
    Feature weights are calculated by following decision paths in trees
    of an ensemble.
    Each leaf has an output score, and expected scores can also be assigned
    to parent nodes.
    Contribution of one feature on the decision path is how much expected score
    changes from parent to child.
    Weights of all features sum to the output score of the estimator.
    """
    booster, is_regression = _check_booster_args(xgb, is_regression)
    xgb_feature_names = booster.feature_names
    vec, feature_names = handle_vec(
        xgb, doc, vec, vectorized, feature_names,
        num_features=len(xgb_feature_names))
    if feature_names.bias_name is None:
        # XGBoost estimators do not have an intercept, but here we interpret
        # them as having an intercept
        feature_names.bias_name = '<BIAS>'

    X = get_X(doc, vec, vectorized=vectorized)
    if sp.issparse(X):
        # Work around XGBoost issue:
        # https://github.com/dmlc/xgboost/issues/1238#issuecomment-243872543
        X = X.tocsc()

    if missing is None:
        missing = np.nan if isinstance(xgb, Booster) else xgb.missing
    dmatrix = DMatrix(X, missing=missing)

    if isinstance(xgb, Booster):
        prediction = xgb.predict(dmatrix)
        n_targets = prediction.shape[-1]  # type: int
        if is_regression is None:
            # When n_targets is 1, this can be classification too,
            # but it's safer to assume regression.
            # If n_targets > 1, it must be classification.
            is_regression = n_targets == 1
        if is_regression:
            proba = None
        else:
            if n_targets == 1:
                p, = prediction
                proba = np.array([1 - p, p])
            else:
                proba, = prediction
    else:
        proba = predict_proba(xgb, X)
        n_targets = _xgb_n_targets(xgb)

    if is_regression:
        names = ['y']
    elif isinstance(xgb, Booster):
        names = np.arange(max(2, n_targets))
    else:
        names = xgb.classes_

    scores_weights = _prediction_feature_weights(
        booster, dmatrix, n_targets, feature_names, xgb_feature_names)

    x = get_X0(add_intercept(X))
    x = _missing_values_set_to_nan(x, missing, sparse_missing=True)

    return get_decision_path_explanation(
        xgb, doc, vec,
        x=x,
        feature_names=feature_names,
        feature_filter=feature_filter,
        feature_re=feature_re,
        top=top,
        vectorized=vectorized,
        original_display_names=names,
        target_names=target_names,
        targets=targets,
        top_targets=top_targets,
        is_regression=is_regression,
        is_multiclass=n_targets > 1,
        proba=proba,
        get_score_weights=lambda label_id: scores_weights[label_id],
     )


Instruction:
Can you generate the documentation for the following Python 3 function
def _prediction_feature_weights(booster, dmatrix, n_targets,
                                feature_names, xgb_feature_names):
    """ For each target, return score and numpy array with feature weights
    on this prediction, following an idea from
    http://blog.datadive.net/interpreting-random-forests/
    """
    # XGBClassifier does not have pred_leaf argument, so use booster
    leaf_ids, = booster.predict(dmatrix, pred_leaf=True)
    xgb_feature_names = {f: i for i, f in enumerate(xgb_feature_names)}
    tree_dumps = booster.get_dump(with_stats=True)
    assert len(tree_dumps) == len(leaf_ids)

    target_feature_weights = partial(
        _target_feature_weights,
        feature_names=feature_names, xgb_feature_names=xgb_feature_names)
    if n_targets > 1:
        # For multiclass, XGBoost stores dumps and leaf_ids in a 1d array,
        # so we need to split them.
        scores_weights = [
            target_feature_weights(
                leaf_ids[target_idx::n_targets],
                tree_dumps[target_idx::n_targets],
            ) for target_idx in range(n_targets)]
    else:
        scores_weights = [target_feature_weights(leaf_ids, tree_dumps)]
    return scores_weights

Response: Predicts the feature weights on the given tree.


Instruction:
Implement a function in Python 3 to
return a dictionary with the leaf nodeid and leaf value added to all nodes.

Response:
def _indexed_leafs(parent):
    """ Return a leaf nodeid -> node dictionary with
    "parent" and "leaf" (average child "leaf" value) added to all nodes.
    """
    if not parent.get('children'):
        return {parent['nodeid']: parent}
    indexed = {}
    for child in parent['children']:
        child['parent'] = parent
        if 'leaf' in child:
            indexed[child['nodeid']] = child
        else:
            indexed.update(_indexed_leafs(child))
    parent['leaf'] = _parent_value(parent['children'])
    return indexed


Instruction:
Write a Python 3 function for
returning the value of the parent node.

Response:
def _parent_value(children):
    # type: (...) -> int
    """ Value of the parent node: a weighted sum of child values.
    """
    covers = np.array([child['cover'] for child in children])
    covers /= np.sum(covers)
    leafs = np.array([child['leaf'] for child in children])
    return np.sum(leafs * covers)


Instruction:
Create a Python 3 function for
parsing the text tree dump into a dict that will be used by next XGBoost release release.

Response:
def _parse_tree_dump(text_dump):
    # type: (str) -> Optional[Dict[str, Any]]
    """ Parse text tree dump (one item of a list returned by Booster.get_dump())
    into json format that will be used by next XGBoost release.
    """
    result = None
    stack = []  # type: List[Dict]
    for line in text_dump.split('\n'):
        if line:
            depth, node = _parse_dump_line(line)
            if depth == 0:
                assert not stack
                result = node
                stack.append(node)
            elif depth > len(stack):
                raise ValueError('Unexpected dump structure')
            else:
                if depth < len(stack):
                    stack = stack[:depth]
                stack[-1].setdefault('children', []).append(node)
                stack.append(node)
    return result


Instruction:
Write a Python 3 script for
returning a copy of values where missing values are replaced to nan according.

Response:
def _missing_values_set_to_nan(values, missing_value, sparse_missing):
    """ Return a copy of values where missing values (equal to missing_value)
    are replaced to nan according. If sparse_missing is True,
    entries missing in a sparse matrix will also be set to nan.
    Sparse matrices will be converted to dense format.
    """
    if sp.issparse(values):
        assert values.shape[0] == 1
    if sparse_missing and sp.issparse(values) and missing_value != 0:
        # Nothing special needs to be done for missing.value == 0 because
        # missing values are assumed to be zero in sparse matrices.
        values_coo = values.tocoo()
        values = values.toarray()[0]
        missing_mask = values == 0
        # fix for possible zero values
        missing_mask[values_coo.col] = False
        values[missing_mask] = np.nan
    elif is_sparse_vector(values):
        values = values.toarray()[0]
    else:
        values = values.copy()
    if not np.isnan(missing_value):
        values[values == missing_value] = np.nan
    return values


Instruction:
Can you create a Python 3 function that
returns no more than k indices of smallest values.

Response:
def argsort_k_smallest(x, k):
    """ Return no more than ``k`` indices of smallest values. """
    if k == 0:
        return np.array([], dtype=np.intp)
    if k is None or k >= len(x):
        return np.argsort(x)
    indices = np.argpartition(x, k)[:k]
    values = x[indices]
    return indices[np.argsort(values)]


Instruction:
Here you have a function in Python 3, explain what it does
def is_sparse_vector(x):
    return sp.issparse(x) and len(x.shape) == 2 and x.shape[0] == 1

Response: Check if x is a 2D sparse matrix with first shape equal to 1.


Instruction:
Can you write a function in Python 3 where it
converts indices to a boolean mask.

Response:
def indices_to_bool_mask(indices, size):
    """ Convert indices to a boolean (integer) mask.

    >>> list(indices_to_bool_mask(np.array([2, 3]), 4))
    [False, False, True, True]

    >>> list(indices_to_bool_mask([2, 3], 4))
    [False, False, True, True]

    >>> indices_to_bool_mask(np.array([5]), 2)
    Traceback (most recent call last):
    ...
    IndexError: index 5 is out of bounds ...
    """
    mask = np.zeros(size, dtype=bool)
    mask[indices] = 1
    return mask


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_target_display_names(original_names=None, target_names=None,
                             targets=None, top_targets=None, score=None):
    """
    Return a list of (target_id, display_name) tuples.

    By default original names are passed as-is, only indices are added:
    >>> get_target_display_names(['x', 'y'])
    [(0, 'x'), (1, 'y')]

    ``targets`` can be written using both names from ``target_names` and
    from ``original_names``:
    >>> get_target_display_names(['x', 'y'], targets=['y', 'X'],
    ...                   target_names={'x': 'X'})
    [(1, 'y'), (0, 'X')]

    Provide display names:
    >>> get_target_display_names([0, 2], target_names=['foo', 'bar'])
    [(0, 'foo'), (1, 'bar')]

    Change order of labels:
    >>> get_target_display_names(['x', 'y'], targets=['y', 'x'])
    [(1, 'y'), (0, 'x')]

    Provide display names, choose only a subset of labels:
    >>> get_target_display_names([0, 2], target_names=['foo', 'bar'], targets=[2])
    [(1, 'bar')]

    >>> get_target_display_names([False, True], targets=[True])
    [(1, True)]

    >>> get_target_display_names([False, True], targets=[False])
    [(0, False)]

    target_names can be a dictionary with {old_name: new_name} labels:
    >>> get_target_display_names(['x', 'y'], targets=['y', 'x'],
    ...                   target_names={'x': 'X'})
    [(1, 'y'), (0, 'X')]

    Error is raised when target_names format is invalid:
    >>> get_target_display_names(['x', 'y'], target_names=['foo'])
    Traceback (most recent call last):
    ...
    ValueError: target_names must have the same length as original names (expected 2, got 1)

    Top target selection by score:
    >>> get_target_display_names(['x', 'y', 'z'], score=[1, 2, 1.5], top_targets=2)
    [(1, 'y'), (2, 'z')]

    Top target selection by score, negative:
    >>> get_target_display_names(['x', 'y', 'z'], score=[1, 2, 1.5], top_targets=-3)
    [(0, 'x'), (2, 'z'), (1, 'y')]

    Error is raised if both top_targets and targets are passed:
    >>> get_target_display_names(['x', 'y'], targets=['x'], score=[1, 2], top_targets=1)
    Traceback (most recent call last):
    ...
    ValueError: Pass either "targets" or "top_targets", not both
    """
    if isinstance(target_names, (list, tuple, np.ndarray)):
        if original_names is not None:
            if len(target_names) != len(original_names):
                raise ValueError("target_names must have the same length as "
                                 "original names (expected {}, got {})".format(
                                     len(original_names), len(target_names)
                                 ))
        display_names = target_names
    elif isinstance(target_names, dict):
        display_names = [target_names.get(name, name)
                         for name in original_names]
    else:
        display_names = original_names

    if targets is None:
        if top_targets is not None:
            assert len(score) == len(original_names)
            if top_targets < 0:
                reverse = False
                top_targets = -top_targets
            else:
                reverse = True
            targets = [
                target for _, target in sorted(
                    enumerate(original_names),
                    key=lambda x: score[x[0]],
                    reverse=reverse,
                )][:top_targets]
        else:
            targets = original_names
    elif top_targets is not None:
        raise ValueError('Pass either "targets" or "top_targets", not both')

    target_indices = _get_value_indices(original_names, display_names, targets)
    names = [display_names[i] for i in target_indices]
    return list(zip(target_indices, names))

Response: Get a list of target_id and display_name tuples.


Instruction:
Can you generate the documentation for the following Python 3 function
def get_binary_target_scale_label_id(score, display_names, proba=None):
    if score is not None:
        label_id = 1 if score >= 0 else 0
        scale = -1 if label_id == 0 else 1
    else:
        # Only probability is available - this is the case for
        # DecisionTreeClassifier. As contributions sum to the probability
        # (not to the score), they shouldn't be inverted.
        label_id = 1 if proba[1] >= 0.5 else 0
        scale = 1

    if len(display_names) == 1:  # target is passed explicitly
        predicted_label_id = label_id
        label_id, target = display_names[0]
        scale *= -1 if label_id != predicted_label_id else 1
    else:
        target = display_names[label_id][1]

    return target, scale, label_id

Response: Return the target scale and label_id tuple for a binary classifier.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _get_value_indices(names1, names2, lookups):
    positions = {name: idx for idx, name in enumerate(names2)}
    positions.update({name: idx for idx, name in enumerate(names1)})
    return [positions[name] for name in lookups]

Response: Get the indices of the values in the sequence names1 and names2.


Instruction:
Write a Python 3 script to
render Graphviz data to SVG

Response:
def dot2svg(dot):
    # type: (str) -> str
    """ Render Graphviz data to SVG """
    svg = graphviz.Source(dot).pipe(format='svg').decode('utf8')  # type: str
    # strip doctype and xml declaration
    svg = svg[svg.index('<svg'):]
    return svg


Instruction:
Write a Python 3 function for
returning an explanation of an estimator

Response:
def explain_weights_sklearn(estimator, vec=None, top=_TOP,
                            target_names=None,
                            targets=None,
                            feature_names=None, coef_scale=None,
                            feature_re=None, feature_filter=None):
    """ Return an explanation of an estimator """
    return explain_weights_sklearn_not_supported(estimator)


Instruction:
Explain what the following Python 3 code does
def explain_linear_classifier_weights(clf,
                                      vec=None,
                                      top=_TOP,
                                      target_names=None,
                                      targets=None,
                                      feature_names=None,
                                      coef_scale=None,
                                      feature_re=None,
                                      feature_filter=None,
                                      ):
    """
    Return an explanation of a linear classifier weights.

    See :func:`eli5.explain_weights` for description of
    ``top``, ``target_names``, ``targets``, ``feature_names``,
    ``feature_re`` and ``feature_filter`` parameters.

    ``vec`` is a vectorizer instance used to transform
    raw features to the input of the classifier ``clf``
    (e.g. a fitted CountVectorizer instance); you can pass it
    instead of ``feature_names``.

    ``coef_scale`` is a 1D np.ndarray with a scaling coefficient
    for each feature; coef[i] = coef[i] * coef_scale[i] if
    coef_scale[i] is not nan. Use it if you want to scale coefficients
    before displaying them, to take input feature sign or scale in account.
    """
    feature_names, coef_scale = handle_hashing_vec(vec, feature_names,
                                                   coef_scale)
    feature_names, flt_indices = get_feature_names_filtered(
        clf, vec,
        feature_names=feature_names,
        feature_filter=feature_filter,
        feature_re=feature_re,
    )

    _extra_caveats = "\n" + HASHING_CAVEATS if is_invhashing(vec) else ''

    def _features(label_id):
        coef = get_coef(clf, label_id, scale=coef_scale)
        if flt_indices is not None:
            coef = coef[flt_indices]
        return get_top_features(feature_names, coef, top)

    classes = getattr(clf, "classes_", ["-1", "1"])  # OneClassSVM support
    display_names = get_target_display_names(classes, target_names, targets)
    if is_multiclass_classifier(clf):
        return Explanation(
            targets=[
                TargetExplanation(
                    target=label,
                    feature_weights=_features(label_id)
                )
                for label_id, label in display_names
                ],
            description=DESCRIPTION_CLF_MULTICLASS + _extra_caveats,
            estimator=repr(clf),
            method='linear model',
        )
    else:
        # for binary classifiers scikit-learn stores a single coefficient
        # vector, which corresponds to clf.classes_[1].
        return Explanation(
            targets=[
                TargetExplanation(
                    target=display_names[1][1],
                    feature_weights=_features(0),
                )
            ],
            description=DESCRIPTION_CLF_BINARY + _extra_caveats,
            estimator=repr(clf),
            method='linear model',
        )

Response: Return an explanation of a linear classifier weights.


Instruction:
Implement a function in Python 3 to
return an explanation of an RF feature importance estimator.

Response:
def explain_rf_feature_importance(estimator,
                                  vec=None,
                                  top=_TOP,
                                  target_names=None,  # ignored
                                  targets=None,  # ignored
                                  feature_names=None,
                                  feature_re=None,
                                  feature_filter=None,
                                  ):
    """
    Return an explanation of a tree-based ensemble estimator.

    See :func:`eli5.explain_weights` for description of
    ``top``, ``feature_names``, ``feature_re`` and ``feature_filter``
    parameters.

    ``target_names`` and ``targets`` parameters are ignored.

    ``vec`` is a vectorizer instance used to transform
    raw features to the input of the estimator (e.g. a fitted
    CountVectorizer instance); you can pass it instead of ``feature_names``.
    """
    coef = estimator.feature_importances_
    trees = np.array(estimator.estimators_).ravel()
    coef_std = np.std([tree.feature_importances_ for tree in trees], axis=0)
    return get_feature_importance_explanation(estimator, vec, coef,
        coef_std=coef_std,
        feature_names=feature_names,
        feature_filter=feature_filter,
        feature_re=feature_re,
        top=top,
        description=DESCRIPTION_RANDOM_FOREST,
        is_regression=isinstance(estimator, RegressorMixin),
    )


Instruction:
Here you have a function in Python 3, explain what it does
def explain_decision_tree(estimator,
                          vec=None,
                          top=_TOP,
                          target_names=None,
                          targets=None,  # ignored
                          feature_names=None,
                          feature_re=None,
                          feature_filter=None,
                          **export_graphviz_kwargs):
    """
    Return an explanation of a decision tree.

    See :func:`eli5.explain_weights` for description of
    ``top``, ``target_names``, ``feature_names``,
    ``feature_re`` and ``feature_filter`` parameters.

    ``targets`` parameter is ignored.

    ``vec`` is a vectorizer instance used to transform
    raw features to the input of the estimator (e.g. a fitted
    CountVectorizer instance); you can pass it instead of ``feature_names``.

    All other keyword arguments are passed to
    `sklearn.tree.export_graphviz`_ function.

    .. _sklearn.tree.export_graphviz: http://scikit-learn.org/stable/modules/generated/sklearn.tree.export_graphviz.html
    """
    feature_names = get_feature_names(estimator, vec,
                                      feature_names=feature_names)
    tree_feature_names = feature_names
    feature_names, flt_indices = feature_names.handle_filter(
        feature_filter, feature_re)
    feature_importances = get_feature_importances_filtered(
        estimator.feature_importances_, feature_names, flt_indices, top)

    export_graphviz_kwargs.setdefault("proportion", True)
    tree_info = get_tree_info(
        estimator,
        feature_names=tree_feature_names,
        class_names=target_names,
        **export_graphviz_kwargs)

    return Explanation(
        feature_importances=feature_importances,
        decision_tree=tree_info,
        description=DESCRIPTION_DECISION_TREE,
        estimator=repr(estimator),
        method='decision tree',
    )

Response: Return an explanation of a decision tree.


Instruction:
Can you tell what is the following Python 3 function doing
def explain_linear_regressor_weights(reg,
                                     vec=None,
                                     top=_TOP,
                                     target_names=None,
                                     targets=None,
                                     feature_names=None,
                                     coef_scale=None,
                                     feature_re=None,
                                     feature_filter=None,
                                     ):
    """
    Return an explanation of a linear regressor weights.

    See :func:`eli5.explain_weights` for description of
    ``top``, ``target_names``, ``targets``, ``feature_names``,
    ``feature_re`` and ``feature_filter`` parameters.

    ``vec`` is a vectorizer instance used to transform
    raw features to the input of the regressor ``reg``; you can
    pass it instead of ``feature_names``.

    ``coef_scale`` is a 1D np.ndarray with a scaling coefficient
    for each feature; coef[i] = coef[i] * coef_scale[i] if
    coef_scale[i] is not nan. Use it if you want to scale coefficients
    before displaying them, to take input feature sign or scale in account.
    """
    if isinstance(reg, (SVR, NuSVR)) and reg.kernel != 'linear':
        return explain_weights_sklearn_not_supported(reg)

    feature_names, coef_scale = handle_hashing_vec(vec, feature_names,
                                                   coef_scale)
    feature_names, flt_indices = get_feature_names_filtered(
        reg, vec,
        feature_names=feature_names,
        feature_filter=feature_filter,
        feature_re=feature_re,
    )
    _extra_caveats = "\n" + HASHING_CAVEATS if is_invhashing(vec) else ''

    def _features(target_id):
        coef = get_coef(reg, target_id, scale=coef_scale)
        if flt_indices is not None:
            coef = coef[flt_indices]
        return get_top_features(feature_names, coef, top)

    display_names = get_target_display_names(get_default_target_names(reg),
                                             target_names, targets)
    if is_multitarget_regressor(reg):
        return Explanation(
            targets=[
                TargetExplanation(
                    target=target_name,
                    feature_weights=_features(target_id)
                )
                for target_id, target_name in display_names
                ],
            description=DESCRIPTION_REGRESSION_MULTITARGET + _extra_caveats,
            estimator=repr(reg),
            method='linear model',
            is_regression=True,
        )
    else:
        return Explanation(
            targets=[TargetExplanation(
                target=display_names[0][1],
                feature_weights=_features(0),
            )],
            description=DESCRIPTION_REGRESSION + _extra_caveats,
            estimator=repr(reg),
            method='linear model',
            is_regression=True,
        )

Response: Return an explanation of a linear regressor weights.


Instruction:
Can you implement a function in Python 3 that
returns an explanation of PermutationImportance.

Response:
def explain_permutation_importance(estimator,
                                   vec=None,
                                   top=_TOP,
                                   target_names=None,  # ignored
                                   targets=None,  # ignored
                                   feature_names=None,
                                   feature_re=None,
                                   feature_filter=None,
                                   ):
    """
    Return an explanation of PermutationImportance.

    See :func:`eli5.explain_weights` for description of
    ``top``, ``feature_names``, ``feature_re`` and ``feature_filter``
    parameters.

    ``target_names`` and ``targets`` parameters are ignored.

    ``vec`` is a vectorizer instance used to transform
    raw features to the input of the estimator (e.g. a fitted
    CountVectorizer instance); you can pass it instead of ``feature_names``.
    """
    coef = estimator.feature_importances_
    coef_std = estimator.feature_importances_std_
    return get_feature_importance_explanation(estimator, vec, coef,
        coef_std=coef_std,
        feature_names=feature_names,
        feature_filter=feature_filter,
        feature_re=feature_re,
        top=top,
        description=DESCRIPTION_SCORE_DECREASE + estimator.caveats_,
        is_regression=isinstance(estimator.wrapped_estimator_, RegressorMixin),
    )


Instruction:
Make a summary of the following Python 3 code
def _get_collisions(indices):
    # type: (...) -> Dict[int, List[int]]
    """
    Return a dict ``{column_id: [possible term ids]}``
    with collision information.
    """
    collisions = defaultdict(list)  # type: Dict[int, List[int]]
    for term_id, hash_id in enumerate(indices):
        collisions[hash_id].append(term_id)
    return dict(collisions)

Response: Returns a dict of column_id = > list of possible term ids.


Instruction:
Write a Python 3 script for
getting the column index and sign of each term in terms.

Response:
def _get_indices_and_signs(hasher, terms):
    """
    For each term from ``terms`` return its column index and sign,
    as assigned by FeatureHasher ``hasher``.
    """
    X = _transform_terms(hasher, terms)
    indices = X.nonzero()[1]
    signs = X.sum(axis=1).A.ravel()
    return indices, signs


Instruction:
How would you implement a function in Python 3 that
returns feature_names and coef_scale for invhashing vectorizers.

Response:
def handle_hashing_vec(vec, feature_names, coef_scale, with_coef_scale=True):
    """ Return feature_names and coef_scale (if with_coef_scale is True),
    calling .get_feature_names for invhashing vectorizers.
    """
    needs_coef_scale = with_coef_scale and coef_scale is None
    if is_invhashing(vec):
        if feature_names is None:
            feature_names = vec.get_feature_names(always_signed=False)
        if needs_coef_scale:
            coef_scale = vec.column_signs_
    elif (isinstance(vec, FeatureUnion) and
              any(is_invhashing(v) for _, v in vec.transformer_list) and
              (needs_coef_scale or feature_names is None)):
        _feature_names, _coef_scale = _invhashing_union_feature_names_scale(vec)
        if feature_names is None:
            feature_names = _feature_names
        if needs_coef_scale:
            coef_scale = _coef_scale
    return (feature_names, coef_scale) if with_coef_scale else feature_names


Instruction:
How would you code a function in Python 3 to
invert the given vectorizer vec on the given docs.

Response:
def invert_hashing_and_fit(
        vec,  # type: Union[FeatureUnion, HashingVectorizer]
        docs
    ):
    # type: (...) -> Union[FeatureUnion, InvertableHashingVectorizer]
    """ Create an :class:`~.InvertableHashingVectorizer` from hashing
    vectorizer vec and fit it on docs. If vec is a FeatureUnion, do it for all
    hashing vectorizers in the union.
    Return an :class:`~.InvertableHashingVectorizer`, or a FeatureUnion,
    or an unchanged vectorizer.
    """
    if isinstance(vec, HashingVectorizer):
        vec = InvertableHashingVectorizer(vec)
        vec.fit(docs)
    elif (isinstance(vec, FeatureUnion) and
              any(isinstance(v, HashingVectorizer)
                  for _, v in vec.transformer_list)):
        vec = _fit_invhashing_union(vec, docs)
    return vec


Instruction:
Write a Python 3 function that can
fit InvertableHashingVectorizer on a list of docs inside a FeatureUnion.

Response:
def _fit_invhashing_union(vec_union, docs):
    # type: (FeatureUnion, Any) -> FeatureUnion
    """ Fit InvertableHashingVectorizer on doc inside a FeatureUnion.
    """
    return FeatureUnion(
        [(name, invert_hashing_and_fit(v, docs))
         for name, v in vec_union.transformer_list],
        transformer_weights=vec_union.transformer_weights,
        n_jobs=vec_union.n_jobs)


Instruction:
Write a Python 3 function for
fitting the unhasher to the set of possible terms.

Response:
def fit(self, X, y=None):
        """ Extract possible terms from documents """
        self.unhasher.fit(self._get_terms_iter(X))
        return self


Instruction:
Can you implement a function in Python 3 that
returns a list of feature names for the current class entry.

Response:
def get_feature_names(self, always_signed=True):
        # type: (bool) -> FeatureNames
        """
        Return feature names.
        This is a best-effort function which tries to reconstruct feature
        names based on what it has seen so far.

        HashingVectorizer uses a signed hash function. If always_signed is True,
        each term in feature names is prepended with its sign. If it is False,
        signs are only shown in case of possible collisions of different sign.

        You probably want always_signed=True if you're checking
        unprocessed classifier coefficients, and always_signed=False
        if you've taken care of :attr:`column_signs_`.
        """
        return self.unhasher.get_feature_names(
            always_signed=always_signed,
            always_positive=self._always_positive(),
        )


Instruction:
How would you code a function in Python 3 to
return a numpy array with expected signs of features.

Response:
def column_signs_(self):
        """
        Return a numpy array with expected signs of features.
        Values are

        * +1 when all known terms which map to the column have positive sign;
        * -1 when all known terms which map to the column have negative sign;
        * ``nan`` when there are both positive and negative known terms
          for this column, or when there is no known term which maps to this
          column.
        """
        if self._always_positive():
            return np.ones(self.n_features)
        self.unhasher.recalculate_attributes()
        return self.unhasher.column_signs_


Instruction:
Can you tell what is the following Python 3 function doing
def recalculate_attributes(self, force=False):
        # type: (bool) -> None
        """
        Update all computed attributes. It is only needed if you need to access
        computed attributes after :meth:`patrial_fit` was called.
        """
        if not self._attributes_dirty and not force:
            return
        terms = [term for term, _ in self._term_counts.most_common()]
        if six.PY2:
            terms = np.array(terms, dtype=np.object)
        else:
            terms = np.array(terms)
        if len(terms):
            indices, signs = _get_indices_and_signs(self.hasher, terms)
        else:
            indices, signs = np.array([]), np.array([])
        self.terms_ = terms  # type: np.ndarray
        self.term_columns_ = indices
        self.term_signs_ = signs
        self.collisions_ = _get_collisions(indices)
        self.column_signs_ = self._get_column_signs()
        self._attributes_dirty = False

Response: Recalculate all computed attributes.


Instruction:
Given the following Python 3 function, write the documentation
def tree2text(tree_obj, indent=4):
    # type: (TreeInfo, int) -> str
    """
    Return text representation of a decision tree.
    """
    parts = []

    def _format_node(node, depth=0):
        # type: (NodeInfo, int) -> None
        def p(*args):
            # type: (*str) -> None
            parts.append(" " * depth * indent)
            parts.extend(args)

        if node.is_leaf:
            value_repr = _format_leaf_value(tree_obj, node)
            parts.append("  ---> {}".format(value_repr))
        else:
            assert node.left is not None
            assert node.right is not None
            feat_name = node.feature_name

            if depth > 0:
                parts.append("\n")
            left_samples = node.left.sample_ratio
            p("{feat_name} <= {threshold:0.3f}  ({left_samples:0.1%})".format(
                left_samples=left_samples,
                feat_name=feat_name,
                threshold=node.threshold,
            ))
            _format_node(node.left, depth=depth + 1)

            parts.append("\n")
            right_samples = node.right.sample_ratio
            p("{feat_name} > {threshold:0.3f}  ({right_samples:0.1%})".format(
                right_samples=right_samples,
                feat_name=feat_name,
                threshold=node.threshold,
                ))
            _format_node(node.right, depth=depth + 1)

    _format_node(tree_obj.tree)
    return "".join(parts)

Response: Return text representation of a decision tree.


Instruction:
Write a Python 3 function for
formatting an array of values.

Response:
def _format_array(x, fmt):
    # type: (Any, str) -> str
    """
    >>> _format_array([0, 1.0], "{:0.3f}")
    '[0.000, 1.000]'
    """
    value_repr = ", ".join(fmt.format(v) for v in x)
    return "[{}]".format(value_repr)


Instruction:
Can you tell what is the following Python 3 function doing
def explain_weights_df(estimator, **kwargs):
    # type: (...) -> pd.DataFrame
    """ Explain weights and export them to ``pandas.DataFrame``.
    All keyword arguments are passed to :func:`eli5.explain_weights`.
    Weights of all features are exported by default.
    """
    kwargs = _set_defaults(kwargs)
    return format_as_dataframe(
        eli5.explain_weights(estimator, **kwargs))

Response: Explain weights and export them to pandas. DataFrame.


Instruction:
Make a summary of the following Python 3 code
def explain_weights_dfs(estimator, **kwargs):
    # type: (...) -> Dict[str, pd.DataFrame]
    """ Explain weights and export them to a dict with ``pandas.DataFrame``
    values (as :func:`eli5.formatters.as_dataframe.format_as_dataframes` does).
    All keyword arguments are passed to :func:`eli5.explain_weights`.
    Weights of all features are exported by default.
    """
    kwargs = _set_defaults(kwargs)
    return format_as_dataframes(
        eli5.explain_weights(estimator, **kwargs))

Response: Explain weights and export them to a dict with pandas. DataFrame.


Instruction:
Explain what the following Python 3 code does
def explain_prediction_df(estimator, doc, **kwargs):
    # type: (...) -> pd.DataFrame
    """ Explain prediction and export explanation to ``pandas.DataFrame``
    All keyword arguments are passed to :func:`eli5.explain_prediction`.
    Weights of all features are exported by default.
    """
    kwargs = _set_defaults(kwargs)
    return format_as_dataframe(
        eli5.explain_prediction(estimator, doc, **kwargs))

Response: Explain prediction and export explanation to pandas. DataFrame


Instruction:
Create a Python 3 function for
explaining prediction and export explanation to a dict with pandas. DataFrame values.

Response:
def explain_prediction_dfs(estimator, doc, **kwargs):
    # type: (...) -> Dict[str, pd.DataFrame]
    """ Explain prediction and export explanation
    to a dict with ``pandas.DataFrame`` values
    (as :func:`eli5.formatters.as_dataframe.format_as_dataframes` does).
    All keyword arguments are passed to :func:`eli5.explain_prediction`.
    Weights of all features are exported by default.
    """
    kwargs = _set_defaults(kwargs)
    return format_as_dataframes(
        eli5.explain_prediction(estimator, doc, **kwargs))


Instruction:
How would you explain what the following Python 3 function does
def format_as_dataframes(explanation):
    # type: (Explanation) -> Dict[str, pd.DataFrame]
    """ Export an explanation to a dictionary with ``pandas.DataFrame`` values
    and string keys that correspond to explanation attributes.
    Use this method if several dataframes can be exported from a single
    explanation (e.g. for CRF explanation with has both feature weights
    and transition matrix).
    Note that :func:`eli5.explain_weights` limits number of features
    by default. If you need all features, pass ``top=None`` to
    :func:`eli5.explain_weights`, or use
    :func:`explain_weights_dfs`.
    """
    result = {}
    for attr in _EXPORTED_ATTRIBUTES:
        value = getattr(explanation, attr)
        if value:
            result[attr] = format_as_dataframe(value)
    return result

Response: Export an explanation to a dictionary with pandas. DataFrame values that correspond to the attributes of the explanation.


Instruction:
Implement a function in Python 3 to
export an explanation to a single pandas. DataFrame.

Response:
def format_as_dataframe(explanation):
    # type: (Explanation) -> Optional[pd.DataFrame]
    """ Export an explanation to a single ``pandas.DataFrame``.
    In case several dataframes could be exported by
    :func:`eli5.formatters.as_dataframe.format_as_dataframes`,
    a warning is raised. If no dataframe can be exported, ``None`` is returned.
    This function also accepts some components of the explanation as arguments:
    feature importances, targets, transition features.
    Note that :func:`eli5.explain_weights` limits number of features
    by default. If you need all features, pass ``top=None`` to
    :func:`eli5.explain_weights`, or use
    :func:`explain_weights_df`.
    """
    for attr in _EXPORTED_ATTRIBUTES:
        value = getattr(explanation, attr)
        if value:
            other_attrs = [a for a in _EXPORTED_ATTRIBUTES
                           if getattr(explanation, a) and a != attr]
            if other_attrs:
                warnings.warn('Exporting {} to DataFrame, but also {} could be '
                              'exported. Consider using eli5.format_as_dataframes.'
                              .format(attr, ', '.join(other_attrs)))
            return format_as_dataframe(value)
    return None


Instruction:
Can you implement a function in Python 3 that
yields the matrix X with one or more columns shuffled.

Response:
def iter_shuffled(X, columns_to_shuffle=None, pre_shuffle=False,
                  random_state=None):
    """
    Return an iterator of X matrices which have one or more columns shuffled.
    After each iteration yielded matrix is mutated inplace, so
    if you want to use multiple of them at the same time, make copies.

    ``columns_to_shuffle`` is a sequence of column numbers to shuffle.
    By default, all columns are shuffled once, i.e. columns_to_shuffle
    is ``range(X.shape[1])``.

    If ``pre_shuffle`` is True, a copy of ``X`` is shuffled once, and then
    result takes shuffled columns from this copy. If it is False,
    columns are shuffled on fly. ``pre_shuffle = True`` can be faster
    if there is a lot of columns, or if columns are used multiple times.
    """
    rng = check_random_state(random_state)

    if columns_to_shuffle is None:
        columns_to_shuffle = range(X.shape[1])

    if pre_shuffle:
        X_shuffled = X.copy()
        rng.shuffle(X_shuffled)

    X_res = X.copy()
    for columns in columns_to_shuffle:
        if pre_shuffle:
            X_res[:, columns] = X_shuffled[:, columns]
        else:
            rng.shuffle(X_res[:, columns])
        yield X_res
        X_res[:, columns] = X[:, columns]


Instruction:
Here you have a function in Python 3, explain what it does
def get_score_importances(
        score_func,  # type: Callable[[Any, Any], float]
        X,
        y,
        n_iter=5,  # type: int
        columns_to_shuffle=None,
        random_state=None
    ):
    # type: (...) -> Tuple[float, List[np.ndarray]]
    """
    Return ``(base_score, score_decreases)`` tuple with the base score and
    score decreases when a feature is not available.

    ``base_score`` is ``score_func(X, y)``; ``score_decreases``
    is a list of length ``n_iter`` with feature importance arrays
    (each array is of shape ``n_features``); feature importances are computed
    as score decrease when a feature is not available.

    ``n_iter`` iterations of the basic algorithm is done, each iteration
    starting from a different random seed.

    If you just want feature importances, you can take a mean of the result::

        import numpy as np
        from eli5.permutation_importance import get_score_importances

        base_score, score_decreases = get_score_importances(score_func, X, y)
        feature_importances = np.mean(score_decreases, axis=0)

    """
    rng = check_random_state(random_state)
    base_score = score_func(X, y)
    scores_decreases = []
    for i in range(n_iter):
        scores_shuffled = _get_scores_shufled(
            score_func, X, y, columns_to_shuffle=columns_to_shuffle,
            random_state=rng
        )
        scores_decreases.append(-scores_shuffled + base_score)
    return base_score, scores_decreases

Response: Basic algorithm for calculating the score of the set of features in the current language.


Instruction:
Implement a Python 3 function for
returning an explanation of the classifier weights in an IPython. display. HTML object.

Response:
def show_weights(estimator, **kwargs):
    """ Return an explanation of estimator parameters (weights)
    as an IPython.display.HTML object. Use this function
    to show classifier weights in IPython.

    :func:`show_weights` accepts all
    :func:`eli5.explain_weights` arguments and all
    :func:`eli5.formatters.html.format_as_html`
    keyword arguments, so it is possible to get explanation and
    customize formatting in a single call.

    Parameters
    ----------
    estimator : object
        Estimator instance. This argument must be positional.

    top : int or (int, int) tuple, optional
        Number of features to show. When ``top`` is int, ``top`` features with
        a highest absolute values are shown. When it is (pos, neg) tuple,
        no more than ``pos`` positive features and no more than ``neg``
        negative features is shown. ``None`` value means no limit.

        This argument may be supported or not, depending on estimator type.

    target_names : list[str] or {'old_name': 'new_name'} dict, optional
        Names of targets or classes. This argument can be used to provide
        human-readable class/target names for estimators which don't expose
        clss names themselves. It can be also used to rename estimator-provided
        classes before displaying them.

        This argument may be supported or not, depending on estimator type.

    targets : list, optional
        Order of class/target names to show. This argument can be also used
        to show information only for a subset of classes. It should be a list
        of class / target names which match either names provided by
        an estimator or names defined in ``target_names`` parameter.

        This argument may be supported or not, depending on estimator type.

    feature_names : list, optional
        A list of feature names. It allows to specify feature
        names when they are not provided by an estimator object.

        This argument may be supported or not, depending on estimator type.

    feature_re : str, optional
        Only feature names which match ``feature_re`` regex are shown
        (more precisely, ``re.search(feature_re, x)`` is checked).

    feature_filter : Callable[[str], bool], optional
        Only feature names for which ``feature_filter`` function returns True
        are shown.

    show : List[str], optional
        List of sections to show. Allowed values:

        * 'targets' - per-target feature weights;
        * 'transition_features' - transition features of a CRF model;
        * 'feature_importances' - feature importances of a decision tree or
          an ensemble-based estimator;
        * 'decision_tree' - decision tree in a graphical form;
        * 'method' - a string with explanation method;
        * 'description' - description of explanation method and its caveats.

        ``eli5.formatters.fields`` provides constants that cover common cases:
        ``INFO`` (method and description), ``WEIGHTS`` (all the rest),
        and ``ALL`` (all).

    horizontal_layout : bool
        When True, feature weight tables are printed horizontally
        (left to right); when False, feature weight tables are printed
        vertically (top to down). Default is True.

    highlight_spaces : bool or None, optional
        Whether to highlight spaces in feature names. This is useful if
        you work with text and have ngram features which may include spaces
        at left or right. Default is None, meaning that the value used
        is set automatically based on vectorizer and feature values.

    include_styles : bool
        Most styles are inline, but some are included separately in <style> tag;
        you can omit them by passing ``include_styles=False``. Default is True.

    **kwargs: dict
        Keyword arguments. All keyword arguments are passed to
        concrete explain_weights... implementations.

    Returns
    -------
    IPython.display.HTML
        The result is printed in IPython notebook as an HTML widget.
        If you need to display several explanations as an output of a single
        cell, or if you want to display it from a function then use
        IPython.display.display::

            from IPython.display import display
            display(eli5.show_weights(clf1))
            display(eli5.show_weights(clf2))

    """
    format_kwargs, explain_kwargs = _split_kwargs(kwargs)
    expl = explain_weights(estimator, **explain_kwargs)
    html = format_as_html(expl, **format_kwargs)
    return HTML(html)


Instruction:
Make a summary of the following Python 3 code
def show_prediction(estimator, doc, **kwargs):
    format_kwargs, explain_kwargs = _split_kwargs(kwargs)
    expl = explain_prediction(estimator, doc, **explain_kwargs)
    html = format_as_html(expl, **format_kwargs)
    return HTML(html)

Response: Return an explanation of estimator prediction as an IPython. display. HTML object.


Instruction:
Write a Python 3 function that can
convert DecisionTreeClassifier or DecisionTreeRegressor to an inspectable object.

Response:
def get_tree_info(decision_tree,
                  feature_names=None,
                  **export_graphviz_kwargs):
    # type: (...) -> TreeInfo
    """
    Convert DecisionTreeClassifier or DecisionTreeRegressor
    to an inspectable object.
    """
    return TreeInfo(
        criterion=decision_tree.criterion,
        tree=_get_root_node_info(decision_tree, feature_names),
        graphviz=tree2dot(decision_tree,
                          feature_names=feature_names,
                          **export_graphviz_kwargs),
        is_classification=isinstance(decision_tree, ClassifierMixin),
    )


Instruction:
Make a summary of the following Python 3 code
def generate_samples(text,                # type: TokenizedText
                     n_samples=500,       # type: int
                     bow=True,            # type: bool
                     random_state=None,
                     replacement='',      # type: str
                     min_replace=1,       # type: Union[int, float]
                     max_replace=1.0,     # type: Union[int, float]
                     group_size=1,        # type: int
                     ):
    # type: (...) -> Tuple[List[str], np.ndarray, np.ndarray]
    """
    Return ``n_samples`` changed versions of text (with some words removed),
    along with distances between the original text and a generated
    examples. If ``bow=False``, all tokens are considered unique
    (i.e. token position matters).
    """
    kwargs = dict(
        n_samples=n_samples,
        replacement=replacement,
        random_state=random_state,
        min_replace=min_replace,
        max_replace=max_replace,
    )
    if bow:
        num_tokens = len(text.vocab)
        res = text.replace_random_tokens_bow(**kwargs)
    else:
        num_tokens = len(text.tokens)
        res = text.replace_random_tokens(group_size=group_size, **kwargs)

    texts, num_removed_vec, masks = zip(*res)
    similarity = cosine_similarity_vec(num_tokens, num_removed_vec)
    return texts, similarity, vstack(masks)

Response:
Generates n_samples changed versions of text and a generated
   .


Instruction:
How would you code a function in Python 3 to
return cosine similarity between a binary vector with all ones of length num_tokens and vectors of the same length with num_removed_vec elements set to zero.

Response:
def cosine_similarity_vec(num_tokens, num_removed_vec):
    """
    Return cosine similarity between a binary vector with all ones
    of length ``num_tokens`` and vectors of the same length with
    ``num_removed_vec`` elements set to zero.
    """
    remaining = -np.array(num_removed_vec) + num_tokens
    return remaining / (np.sqrt(num_tokens + 1e-6) * np.sqrt(remaining + 1e-6))


Instruction:
Can you implement a function in Python 3 that
returns a list of tuples with n_samples versions of text with some words replaced with a random number of replacement words.

Response:
def replace_random_tokens(self,
                              n_samples,  # type: int
                              replacement='',  # type: str
                              random_state=None,
                              min_replace=1,  # type: Union[int, float]
                              max_replace=1.0,  # type: Union[int, float]
                              group_size=1  # type: int
                              ):
        # type: (...) -> List[Tuple[str, int, np.ndarray]]
        """
        Return a list of ``(text, replaced_count, mask)``
        tuples with n_samples versions of text with some words replaced.
        By default words are replaced with '', i.e. removed.
        """
        n_tokens = len(self.tokens)
        indices = np.arange(n_tokens)
        if not n_tokens:
            nomask = np.array([], dtype=int)
            return [('', 0, nomask)] * n_samples

        min_replace, max_replace = self._get_min_max(min_replace, max_replace,
                                                     n_tokens)
        rng = check_random_state(random_state)
        replace_sizes = rng.randint(low=min_replace, high=max_replace + 1,
                                    size=n_samples)
        res = []
        for num_to_replace in replace_sizes:
            idx_to_replace = rng.choice(indices, num_to_replace, replace=False)
            idx_to_replace = np.array([idx_to_replace] + [
                idx_to_replace + shift for shift in range(1, group_size)
            ]).ravel()
            padded_size = n_tokens + group_size - 1
            mask = indices_to_bool_mask(idx_to_replace, padded_size)[:n_tokens]
            s = self.split.masked(mask, replacement)
            res.append((s.text, num_to_replace, mask))
        return res


Instruction:
Can you tell what is the following Python 3 function doing
def replace_random_tokens_bow(self,
                                  n_samples,  # type: int
                                  replacement='',  # type: str
                                  random_state=None,
                                  min_replace=1,  # type: Union[int, float]
                                  max_replace=1.0, # type: Union[int, float]
                                  ):
        # type: (...) -> List[Tuple[str, int, np.ndarray]]
        """
        Return a list of ``(text, replaced_words_count, mask)`` tuples with
        n_samples versions of text with some words replaced.
        If a word is replaced, all duplicate words are also replaced
        from the text. By default words are replaced with '', i.e. removed.
        """
        if not self.vocab:
            nomask = np.array([], dtype=int)
            return [('', 0, nomask)] * n_samples

        min_replace, max_replace = self._get_min_max(min_replace, max_replace,
                                                     len(self.vocab))
        rng = check_random_state(random_state)
        replace_sizes = rng.randint(low=min_replace, high=max_replace + 1,
                                    size=n_samples)
        res = []
        for num_to_replace in replace_sizes:
            tokens_to_replace = set(rng.choice(self.vocab, num_to_replace,
                                               replace=False))
            idx_to_replace = [idx for idx, token in enumerate(self.tokens)
                              if token in tokens_to_replace]
            mask = indices_to_bool_mask(idx_to_replace, len(self.tokens))
            s = self.split.masked(idx_to_replace, replacement)
            res.append((s.text, num_to_replace, mask))
        return res

Response: Replaces random tokens in the vocabulary with some words replaced.


Instruction:
How would you implement a function in Python 3 that
fits the local classification pipeline to get the explanation of the given doc.

Response:
def fit(self,
            doc,             # type: str
            predict_proba,   # type: Callable[[Any], Any]
            ):
        # type: (...) -> TextExplainer
        """
        Explain ``predict_proba`` probabilistic classification function
        for the ``doc`` example. This method fits a local classification
        pipeline following LIME approach.

        To get the explanation use :meth:`show_prediction`,
        :meth:`show_weights`, :meth:`explain_prediction` or
        :meth:`explain_weights`.

        Parameters
        ----------
        doc : str
            Text to explain
        predict_proba : callable
            Black-box classification pipeline. ``predict_proba``
            should be a function which takes a list of strings (documents)
            and return a matrix of shape ``(n_samples, n_classes)`` with
            probability values - a row per document and a column per output
            label.
        """
        self.doc_ = doc

        if self.position_dependent:
            samples, sims, mask, text = self.sampler.sample_near_with_mask(
                doc=doc,
                n_samples=self.n_samples
            )
            self.vec_ = SingleDocumentVectorizer(
                token_pattern=self.token_pattern
            ).fit([doc])
            X = ~mask
        else:
            self.vec_ = clone(self.vec).fit([doc])
            samples, sims = self.sampler.sample_near(
                doc=doc,
                n_samples=self.n_samples
            )
            X = self.vec_.transform(samples)

        if self.rbf_sigma is not None:
            sims = rbf(1-sims, sigma=self.rbf_sigma)

        self.samples_ = samples
        self.similarity_ = sims
        self.X_ = X
        self.y_proba_ = predict_proba(samples)
        self.clf_ = clone(self.clf)

        self.metrics_ = _train_local_classifier(
            estimator=self.clf_,
            samples=X,
            similarity=sims,
            y_proba=self.y_proba_,
            expand_factor=self.expand_factor,
            random_state=self.rng_
        )
        return self


Instruction:
Can you generate a brief explanation for the following Python 3 code
def show_prediction(self, **kwargs):
        self._fix_target_names(kwargs)
        return eli5.show_prediction(self.clf_, self.doc_, vec=self.vec_,
                                    **kwargs)

Response:
Call eli5. show_prediction for the locally - fit
        classification pipeline.


Instruction:
Can you tell what is the following Python 3 function doing
def show_weights(self, **kwargs):
        self._fix_target_names(kwargs)
        return eli5.show_weights(self.clf_, vec=self.vec_, **kwargs)

Response:
Call eli5. show_weights for the locally - fit
        classification pipeline.


Instruction:
Write a Python 3 script to
return the classification weights for the locally - fit .

Response:
def explain_weights(self, **kwargs):
        """
        Call :func:`eli5.show_weights` for the locally-fit
        classification pipeline. Keyword arguments are passed
        to :func:`eli5.show_weights`.

        :func:`fit` must be called before using this method.
        """
        self._fix_target_names(kwargs)
        return eli5.explain_weights(self.clf_, vec=self.vec_, **kwargs)