classification/tree_explainer.py
def report_foils(self, sample: DataFrame, parents: Dict[int, List[int]] = None,
                     value_leaves: Dict[int, List[int]] = None) -> None:
        """
        Report for each class to which the sample wasn't assigned, what the difference is between
        its node and the closest node with a different class.

        TODO: make it so that rules of the same feature are compared between the
        foil and the sample.
        """
        if (parents is None) or (value_leaves is None):
            parents, value_leaves = self._inspect_tree()
        sample_class = self.model.predict(sample)[0]
        sample_leaf = self.model.apply(sample)[0]
        sample_parents = parents[sample_leaf]

        for value, leaves in value_leaves.items():
            if value == sample_class:
                continue

            close_leaf = None
            close_dist = float('inf')
            close_parent = None
            for leaf in leaves:
                leaf_parents = parents[leaf]
                overlap = set(sample_parents).intersection(leaf_parents)
                if not overlap:
                    continue

                closest_overlap = (None, float('inf'))
                for shared_p in overlap:
                    distance = sample_parents.index(shared_p) + leaf_parents.index(shared_p)
                    if distance < closest_overlap[1]:
                        closest_overlap = (shared_p, distance)
                if closest_overlap[1] < close_dist:
                    close_leaf = leaf
                    close_dist = closest_overlap[1]
                    close_parent = closest_overlap[0]

            print("Closest leaf resulting in a {}: {}, distance = {}.".
                  format(self.target_names[value], close_leaf, close_dist + 1))

            sample_cut_index = sample_parents.index(close_parent)
            sample_lowers = [*sample_parents[:sample_cut_index], close_parent]
            leaf_cut_index = parents[close_leaf].index(close_parent)
            leaf_lowers = [*parents[close_leaf][:leaf_cut_index], close_parent]

            decisions_sample = self._aggregate_features(sample_lowers, sample_leaf, sample)
            decisions_foil = self._aggregate_features(leaf_lowers, close_leaf)
            decisions_sample = [x for x in decisions_sample if x not in decisions_foil]

            self._print_comparison(decisions_sample, decisions_foil, sample)

        Report for each class to which the sample wasn't assigned, what the difference is between
        its node and the closest node with a different class.

        TODO: make it so that rules of the same feature are compared between the
        foil and the sample.
        
Report for each class to which the sample wasn't assigned, what the difference is between
its node and the closest node with a different class.

make it so that rules of the same feature are compared between the
foil and the sample.
Report for each class to which the sample wasn ' t assigned what the difference is between its node and the closest node with a different class . make it so that rules of the same feature are compared between the foil and the sample .
def report_foils(self, sample: DataFrame, parents: Dict[int, List[int]] = None,
                     value_leaves: Dict[int, List[int]] = None) -> None:
        if (parents is None) or (value_leaves is None):
            parents, value_leaves = self._inspect_tree()
        sample_class = self.model.predict(sample)[0]
        sample_leaf = self.model.apply(sample)[0]
        sample_parents = parents[sample_leaf]
        for value, leaves in value_leaves.items():
            if value == sample_class:
                continue
            close_leaf = None
            close_dist = float('inf')
            close_parent = None
            for leaf in leaves:
                leaf_parents = parents[leaf]
                overlap = set(sample_parents).intersection(leaf_parents)
                if not overlap:
                    continue
                closest_overlap = (None, float('inf'))
                for shared_p in overlap:
                    distance = sample_parents.index(shared_p) + leaf_parents.index(shared_p)
                    if distance < closest_overlap[1]:
                        closest_overlap = (shared_p, distance)
                if closest_overlap[1] < close_dist:
                    close_leaf = leaf
                    close_dist = closest_overlap[1]
                    close_parent = closest_overlap[0]
            print("Closest leaf resulting in a {}: {}, distance = {}.".
                  format(self.target_names[value], close_leaf, close_dist + 1))
            sample_cut_index = sample_parents.index(close_parent)
            sample_lowers = [*sample_parents[:sample_cut_index], close_parent]
            leaf_cut_index = parents[close_leaf].index(close_parent)
            leaf_lowers = [*parents[close_leaf][:leaf_cut_index], close_parent]
            decisions_sample = self._aggregate_features(sample_lowers, sample_leaf, sample)
            decisions_foil = self._aggregate_features(leaf_lowers, close_leaf)
            decisions_sample = [x for x in decisions_sample if x not in decisions_foil]
            self._print_comparison(decisions_sample, decisions_foil, sample)
def report_foils ( self , sample : DataFrame , parents : Dict [ int , List [ int ] ] = None , value_leaves : Dict [ int , List [ int ] ] = None ) -> None : if ( parents is None ) or ( value_leaves is None ) : parents , value_leaves = self . _inspect_tree ( ) sample_class = self . model . predict ( sample ) [ 0 ] sample_leaf = self . model . apply ( sample ) [ 0 ] sample_parents = parents [ sample_leaf ] for value , leaves in value_leaves . items ( ) : if value == sample_class : continue close_leaf = None close_dist = float ( 'inf' ) close_parent = None for leaf in leaves : leaf_parents = parents [ leaf ] overlap = set ( sample_parents ) . intersection ( leaf_parents ) if not overlap : continue closest_overlap = ( None , float ( 'inf' ) ) for shared_p in overlap : distance = sample_parents . index ( shared_p ) + leaf_parents . index ( shared_p ) if distance < closest_overlap [ 1 ] : closest_overlap = ( shared_p , distance ) if closest_overlap [ 1 ] < close_dist : close_leaf = leaf close_dist = closest_overlap [ 1 ] close_parent = closest_overlap [ 0 ] print ( "Closest leaf resulting in a {}: {}, distance = {}." . format ( self . target_names [ value ] , close_leaf , close_dist + 1 ) ) sample_cut_index = sample_parents . index ( close_parent ) sample_lowers = [ * sample_parents [ : sample_cut_index ] , close_parent ] leaf_cut_index = parents [ close_leaf ] . index ( close_parent ) leaf_lowers = [ * parents [ close_leaf ] [ : leaf_cut_index ] , close_parent ] decisions_sample = self . _aggregate_features ( sample_lowers , sample_leaf , sample ) decisions_foil = self . _aggregate_features ( leaf_lowers , close_leaf ) decisions_sample = [ x for x in decisions_sample if x not in decisions_foil ] self . _print_comparison ( decisions_sample , decisions_foil , sample )
Report for each class to which the sample wasn't assigned, what the difference is between
its node and the closest node with a different class.
Report for each class to which the sample wasn ' t assigned what the difference is between its node and the closest node with a different class .
"""
        Report for each class to which the sample wasn't assigned, what the difference is between
        its node and the closest node with a different class.

        TODO: make it so that rules of the same feature are compared between the
        foil and the sample.
        """
self
sample
DataFrame
parents
Dict[int, List[int]]
value_leaves
Dict[int, List[int]]