/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package edu.uci.jforests.learning.trees.decision;

import edu.uci.jforests.dataset.Dataset;
import edu.uci.jforests.learning.trees.TreeSplit;
import edu.uci.jforests.learning.trees.Tree;
import edu.uci.jforests.sample.Sample;
import edu.uci.jforests.util.ArraysUtil;
import edu.uci.jforests.util.MathUtil;

/**
 * @author Yasser Ganjisaffar 
 */

public class DecisionTree extends Tree {

	private double[][] leafTargetDistributions;
	private int numClasses;

	public DecisionTree() {
	}

	@Override
	public Object clone() {
		DecisionTree copy = new DecisionTree();
		super.copyTo(copy);
		copy.leafTargetDistributions = MathUtil.cloneDoubleMatrix(leafTargetDistributions);
		return copy;
	}

	public void init(int maxLeaves, int numClasses) {
		super.init(maxLeaves);
		this.numClasses = numClasses;
		leafTargetDistributions = new double[maxLeaves][numClasses];
	}

	public double[] getLeafTargetDistribution(int leaf) {
		return leafTargetDistributions[leaf];
	}

	public void setLeafTargetDistribution(int leaf, double[] dist) {
		System.arraycopy(dist, 0, leafTargetDistributions[leaf], 0, dist.length);
	}

	public int classify(Dataset dataset, int instanceIndex) {
		double[] dist = leafTargetDistributions[getLeaf(dataset, instanceIndex)];
		return ArraysUtil.findMaxIndex(dist);
	}
	
	public double[] getDistributionForInstance(Dataset dataset, int instanceIndex) {
		return leafTargetDistributions[getLeaf(dataset, instanceIndex)];
	}

	public int[] getPredictions(Dataset dataset) {
		int[] predictions = new int[dataset.numInstances];
		for (int i = 0; i < dataset.numInstances; i++) {
			predictions[i] = classify(dataset, i);
		}
		return predictions;
	}

	/**
	 * turns a leaf of the tree into an internal node with two leaf-children
	 */
	@Override
	public int split(int leaf, TreeSplit split) {
		int indexOfNewNonLeaf = super.split(leaf, split);
		DecisionTreeSplit dsplit = (DecisionTreeSplit) split;
		for (int c = 0; c < numClasses; c++) {
			leafTargetDistributions[leaf][c] = dsplit.leftTargetDist[c];
			leafTargetDistributions[numLeaves - 1][c] = dsplit.rightTargetDist[c];			
		}		
		normalizeLeafTargetDistributions(leaf);
		normalizeLeafTargetDistributions(numLeaves - 1);
		return indexOfNewNonLeaf;
	}
	
	/*public void normalizeLeafTargetDistributions() {
		for (int l = 0; l < numLeaves; l++) {
			normalizeLeafTargetDistributions(l);
		}
	}*/
	
	private void normalizeLeafTargetDistributions(int leaf) {
		double sum = 0;
		for (int c = 0; c < numClasses; c++) {
			sum += leafTargetDistributions[leaf][c];
		}
		for (int c = 0; c < numClasses; c++) {
			leafTargetDistributions[leaf][c] /= sum;
		}
	}

	@Override
	public void loadCustomData(String str) throws Exception {
		leafTargetDistributions = ArraysUtil.loadDoubleMatrixFromLine(removeXmlTag(str, "LeafTargetDistributions"), numLeaves, numClasses);
	}

	@Override
	protected void addCustomData(String linePrefix, StringBuilder sb) {
		StringBuilder sbOutput = new StringBuilder();
		for (int n = 0; n < numLeaves; n++) {
			for (int c = 0; c < numClasses; c++) {
				sbOutput.append(" " + leafTargetDistributions[n][c]);
			}
		}
		sb.append("\n" + linePrefix + "\t" + sbOutput.toString().trim() + "");
	}

	@Override
	public void backfit(Sample sample) {
		double[][] distPerLeaf = new double[numLeaves][numClasses];
		for (int i = 0; i < sample.size; i++) {
			int leaf = getLeaf(sample.dataset, sample.indicesInDataset[i]);
			distPerLeaf[leaf][(int) sample.targets[i]] += sample.weights[i];
		}
		double[] weightedCountPerLeaf = new double[numLeaves];
		for (int l = 0; l < numLeaves; l++) {
			for (int c = 0; c < numClasses; c++) {
				weightedCountPerLeaf[l] += distPerLeaf[l][c];
			}
		}
		boolean hasZeroCountLeaf = false;
		double[][] distPerInternalNode = new double[numLeaves - 1][numClasses];		
		for (int l = 0; l < numLeaves; l++) {
			if (weightedCountPerLeaf[l] > 0) {
				setLeafTargetDistribution(l, distPerLeaf[l]);
				int parent = getParent(~l);
				while (parent >= 0) {
					for (int c = 0; c < numClasses; c++) {
						distPerInternalNode[parent][c] += distPerLeaf[l][c];
					}
					parent = getParent(parent);
				}
			} else {
				hasZeroCountLeaf = true;
			}
		}
		if (hasZeroCountLeaf) {
			double[] weightedCountPerInternalNode = new double[numLeaves - 1];
			for (int i = 0; i < weightedCountPerInternalNode.length; i++) {
				for (int c = 0; c < numClasses; c++) {
					weightedCountPerInternalNode[i] += distPerInternalNode[i][c];
				}
			}
			for (int l = 0; l < numLeaves; l++) {
				if (weightedCountPerLeaf[l] == 0) {
					int parent = getParent(~l);
					while (parent >= 0) {
						if (weightedCountPerInternalNode[parent] > 0) {
							setLeafTargetDistribution(l, distPerInternalNode[parent]);							
							break;
						}
						parent = getParent(parent);
					}
				}
			}
		}
	}
}

 

Ads help maintain this website.