(self, data)
return best_res
Select the attribute for the next split.

        Returns:
            tuple with an instance of Node and a numpy array indicating
            the branch index for each data instance, or -1 if data instance
            is dropped
Select the attribute for the next split.
Select the attribute for the next split .
def _select_attr(self, data):
        """Select the attribute for the next split.

        Returns:
            tuple with an instance of Node and a numpy array indicating
            the branch index for each data instance, or -1 if data instance
            is dropped
        """
        # Prevent false warnings by pylint
        attr = attr_no = None
        col_x = None
        REJECT_ATTRIBUTE = 0, None, None, 0

        def _score_disc():
            """Scoring for discrete attributes, no binarization

            The class computes the entropy itself, not by calling other
            functions. This is to make sure that it uses the same
            definition as the below classes that compute entropy themselves
            for efficiency reasons."""
            n_values = len(attr.values)
            if n_values < 2:
                return REJECT_ATTRIBUTE

            cont = _tree_scorers.contingency(col_x, len(data.domain.attributes[attr_no].values),
                                             data.Y, len(data.domain.class_var.values))
            attr_distr = np.sum(cont, axis=0)
            null_nodes = attr_distr < self.min_samples_leaf
            # This is just for speed. If there is only a single non-null-node,
            # entropy wouldn't decrease anyway.
            if sum(null_nodes) >= n_values - 1:
                return REJECT_ATTRIBUTE
            cont[:, null_nodes] = 0
            attr_distr = np.sum(cont, axis=0)
            cls_distr = np.sum(cont, axis=1)
            n = np.sum(attr_distr)
            # Avoid log(0); <= instead of == because we need an array
            cls_distr[cls_distr <= 0] = 1
            attr_distr[attr_distr <= 0] = 1
            cont[cont <= 0] = 1
            class_entr = n * np.log(n) - np.sum(cls_distr * np.log(cls_distr))
            attr_entr = np.sum(attr_distr * np.log(attr_distr))
            cont_entr = np.sum(cont * np.log(cont))
            score = (class_entr - attr_entr + cont_entr) / n / np.log(2)
            score *= n / len(data)  # punishment for missing values
            branches = col_x.copy()
            branches[np.isnan(branches)] = -1
            if score == 0:
                return REJECT_ATTRIBUTE
            node = DiscreteNode(attr, attr_no, None)
            return score, node, branches, n_values

        def _score_disc_bin():
            """Scoring for discrete attributes, with binarization"""
            n_values = len(attr.values)
            if n_values <= 2:
                return _score_disc()
            cont = contingency.Discrete(data, attr)
            attr_distr = np.sum(cont, axis=0)
            # Skip instances with missing value of the attribute
            cls_distr = np.sum(cont, axis=1)
            if np.sum(attr_distr) == 0:  # all values are missing
                return REJECT_ATTRIBUTE
            best_score, best_mapping = _tree_scorers.find_binarization_entropy(
                cont, cls_distr, attr_distr, self.min_samples_leaf)
            if best_score <= 0:
                return REJECT_ATTRIBUTE
            best_score *= 1 - np.sum(cont.unknowns) / len(data)
            mapping, branches = MappedDiscreteNode.branches_from_mapping(
                col_x, best_mapping, n_values)
            node = MappedDiscreteNode(attr, attr_no, mapping, None)
            return best_score, node, branches, 2

        def _score_cont():
            """Scoring for numeric attributes"""
            nans = np.sum(np.isnan(col_x))
            non_nans = len(col_x) - nans
            arginds = np.argsort(col_x)[:non_nans]
            best_score, best_cut = _tree_scorers.find_threshold_entropy(
                col_x, data.Y, arginds,
                len(class_var.values), self.min_samples_leaf)
            if best_score == 0:
                return REJECT_ATTRIBUTE
            best_score *= non_nans / len(col_x)
            branches = np.full(len(col_x), -1, dtype=int)
            mask = ~np.isnan(col_x)
            branches[mask] = (col_x[mask] > best_cut).astype(int)
            node = NumericNode(attr, attr_no, best_cut, None)
            return best_score, node, branches, 2

        #######################################
        # The real _select_attr starts here
        is_sparse = sp.issparse(data.X)
        domain = data.domain
        class_var = domain.class_var
        best_score, *best_res = REJECT_ATTRIBUTE
        best_res = [Node(None, None, None)] + best_res[1:]
        disc_scorer = _score_disc_bin if self.binarize else _score_disc
        for attr_no, attr in enumerate(domain.attributes):
            col_x = data.X[:, attr_no]
            if is_sparse:
                col_x = col_x.toarray()
                col_x = col_x.flatten()
            sc, *res = disc_scorer() if attr.is_discrete else _score_cont()
            if res[0] is not None and sc > best_score:
                best_score, best_res = sc, res
        best_res[0].value = distribution.Discrete(data, class_var)
        return best_res
def _select_attr ( self , data ) : # Prevent false warnings by pylint attr = attr_no = None col_x = None REJECT_ATTRIBUTE = 0 , None , None , 0 def _score_disc ( ) : """Scoring for discrete attributes, no binarization

            The class computes the entropy itself, not by calling other
            functions. This is to make sure that it uses the same
            definition as the below classes that compute entropy themselves
            for efficiency reasons.""" n_values = len ( attr . values ) if n_values < 2 : return REJECT_ATTRIBUTE cont = _tree_scorers . contingency ( col_x , len ( data . domain . attributes [ attr_no ] . values ) , data . Y , len ( data . domain . class_var . values ) ) attr_distr = np . sum ( cont , axis = 0 ) null_nodes = attr_distr < self . min_samples_leaf # This is just for speed. If there is only a single non-null-node, # entropy wouldn't decrease anyway. if sum ( null_nodes ) >= n_values - 1 : return REJECT_ATTRIBUTE cont [ : , null_nodes ] = 0 attr_distr = np . sum ( cont , axis = 0 ) cls_distr = np . sum ( cont , axis = 1 ) n = np . sum ( attr_distr ) # Avoid log(0); <= instead of == because we need an array cls_distr [ cls_distr <= 0 ] = 1 attr_distr [ attr_distr <= 0 ] = 1 cont [ cont <= 0 ] = 1 class_entr = n * np . log ( n ) - np . sum ( cls_distr * np . log ( cls_distr ) ) attr_entr = np . sum ( attr_distr * np . log ( attr_distr ) ) cont_entr = np . sum ( cont * np . log ( cont ) ) score = ( class_entr - attr_entr + cont_entr ) / n / np . log ( 2 ) score *= n / len ( data ) # punishment for missing values branches = col_x . copy ( ) branches [ np . isnan ( branches ) ] = - 1 if score == 0 : return REJECT_ATTRIBUTE node = DiscreteNode ( attr , attr_no , None ) return score , node , branches , n_values def _score_disc_bin ( ) : """Scoring for discrete attributes, with binarization""" n_values = len ( attr . values ) if n_values <= 2 : return _score_disc ( ) cont = contingency . Discrete ( data , attr ) attr_distr = np . sum ( cont , axis = 0 ) # Skip instances with missing value of the attribute cls_distr = np . sum ( cont , axis = 1 ) if np . sum ( attr_distr ) == 0 : # all values are missing return REJECT_ATTRIBUTE best_score , best_mapping = _tree_scorers . find_binarization_entropy ( cont , cls_distr , attr_distr , self . min_samples_leaf ) if best_score <= 0 : return REJECT_ATTRIBUTE best_score *= 1 - np . sum ( cont . unknowns ) / len ( data ) mapping , branches = MappedDiscreteNode . branches_from_mapping ( col_x , best_mapping , n_values ) node = MappedDiscreteNode ( attr , attr_no , mapping , None ) return best_score , node , branches , 2 def _score_cont ( ) : """Scoring for numeric attributes""" nans = np . sum ( np . isnan ( col_x ) ) non_nans = len ( col_x ) - nans arginds = np . argsort ( col_x ) [ : non_nans ] best_score , best_cut = _tree_scorers . find_threshold_entropy ( col_x , data . Y , arginds , len ( class_var . values ) , self . min_samples_leaf ) if best_score == 0 : return REJECT_ATTRIBUTE best_score *= non_nans / len ( col_x ) branches = np . full ( len ( col_x ) , - 1 , dtype = int ) mask = ~ np . isnan ( col_x ) branches [ mask ] = ( col_x [ mask ] > best_cut ) . astype ( int ) node = NumericNode ( attr , attr_no , best_cut , None ) return best_score , node , branches , 2 ####################################### # The real _select_attr starts here is_sparse = sp . issparse ( data . X ) domain = data . domain class_var = domain . class_var best_score , * best_res = REJECT_ATTRIBUTE best_res = [ Node ( None , None , None ) ] + best_res [ 1 : ] disc_scorer = _score_disc_bin if self . binarize else _score_disc for attr_no , attr in enumerate ( domain . attributes ) : col_x = data . X [ : , attr_no ] if is_sparse : col_x = col_x . toarray ( ) col_x = col_x . flatten ( ) sc , * res = disc_scorer ( ) if attr . is_discrete else _score_cont ( ) if res [ 0 ] is not None and sc > best_score : best_score , best_res = sc , res best_res [ 0 ] . value = distribution . Discrete ( data , class_var ) return best_res