<commit_before>package CloudForest

import ()

//Tree represents a single decision tree.
type Tree struct {
	//Tree int
	Root *Node
}

//AddNode adds a node a the specified path with the specivied pred value and/or
//Splitter. Paths are specified in the same format as in rf-aces sf files, as a
//string of 'L' and 'R'. Nodes must be added from the root up as the case where
//the path specifies a node whose parent does not allready exist in the tree is
//not handled well.
func (t *Tree) AddNode(path string, pred string, splitter *Splitter) {
	n := new(Node)
	n.Pred = pred
	n.Splitter = splitter
	if t.Root == nil {
		t.Root = n
	} else {
		loc := t.Root
		for i := 0; i < len(path); i++ {
			switch path[i : i+1] {
			case "L":
				if loc.Left == nil {
					loc.Left = n
				}
				loc = loc.Left
			case "R":
				if loc.Right == nil {
					loc.Right = n
				}
				loc = loc.Right
			}

		}
	}

}

/*
tree.Grow grows the reciever tree through recursion. It uses impurity decrease to selct spliters at
each node as in Brieman's Random Forest. It should be called on a tree with only a root node defined.

fm is a feature matrix of training data.

target is the feature to predict via regression or classification as determined by feature type.

cases specifies the cases to calculate impurity decrease over and can contain repeated values
to allow for sampeling of cases with replacment as in RF.

mTry specifies the number of canidate features to evaluate for each split.

leafSize specifies the minimum number of cases at a leafNode.
*/
func (t *Tree) Grow(fm *FeatureMatrix,
	target *Feature,
	cases []int,
	canidates []int,
	mTry int,
	leafSize int,
	itter bool,
	l *[]int,
	r *[]int) {

	t.Root.Recurse(func(n *Node, innercases []int) {

		if 2*leafSize <= len(innercases) {
			SampleFirstN(&canidates, mTry)
			best, impDec := target.BestSplitter(fm, innercases, canidates[:mTry], itter, l, r)
			if best != nil && impDec > minImp {
				//not a leaf node so define the spliter and left and right nodes
				//so recursion will continue
				n.Splitter = best
				n.Pred = ""
				n.Left = &Node{nil, nil, "", nil}
				n.Right = &Node{nil, nil, "", nil}
				return
			}
		}

		//Leaf node so find the predictive value and set it in n.Pred<commit_msg>Don't split small leafs<commit_after>package CloudForest

import ()

//Tree represents a single decision tree.
type Tree struct {
	//Tree int
	Root *Node
}

//AddNode adds a node a the specified path with the specivied pred value and/or
//Splitter. Paths are specified in the same format as in rf-aces sf files, as a
//string of 'L' and 'R'. Nodes must be added from the root up as the case where
//the path specifies a node whose parent does not allready exist in the tree is
//not handled well.
func (t *Tree) AddNode(path string, pred string, splitter *Splitter) {
	n := new(Node)
	n.Pred = pred
	n.Splitter = splitter
	if t.Root == nil {
		t.Root = n
	} else {
		loc := t.Root
		for i := 0; i < len(path); i++ {
			switch path[i : i+1] {
			case "L":
				if loc.Left == nil {
					loc.Left = n
				}
				loc = loc.Left
			case "R":
				if loc.Right == nil {
					loc.Right = n
				}
				loc = loc.Right
			}

		}
	}

}

/*
tree.Grow grows the reciever tree through recursion. It uses impurity decrease to selct spliters at
each node as in Brieman's Random Forest. It should be called on a tree with only a root node defined.

fm is a feature matrix of training data.

target is the feature to predict via regression or classification as determined by feature type.

cases specifies the cases to calculate impurity decrease over and can contain repeated values
to allow for sampeling of cases with replacment as in RF.

mTry specifies the number of canidate features to evaluate for each split.

leafSize specifies the minimum number of cases at a leafNode.
*/
func (t *Tree) Grow(fm *FeatureMatrix,
	target *Feature,
	cases []int,
	canidates []int,
	mTry int,
	leafSize int,
	itter bool,
	l *[]int,
	r *[]int) {

	t.Root.Recurse(func(n *Node, innercases []int) {

		if (2 * leafSize) <= len(innercases) {
			SampleFirstN(&canidates, mTry)
			best, impDec := target.BestSplitter(fm, innercases, canidates[:mTry], itter, l, r)
			if best != nil && impDec > minImp {
				//not a leaf node so define the spliter and left and right nodes
				//so recursion will continue
				n.Splitter = best
				n.Pred = ""
				n.Left = &Node{nil, nil, "", nil}
				n.Right = &Node{nil, nil, "", nil}
				return
			}
		}

		//Leaf node so find the predictive value and set it in n.Pred
{'fraction_non_alphanumeric': 0.09748010610079576, 'fraction_numerical': 0.001326259946949602, 'mean_word_length': 3.0401785714285716, 'pattern_counts': {'":': 4, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4271210', 'n_tokens_mistral': 1630, 'n_tokens_neox': 1451, 'n_words': 641}