/* * RapidMiner * * Copyright (C) 2001-2011 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.operator.learner.functions; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import Jama.Matrix; import com.rapidminer.example.Attribute; import com.rapidminer.example.AttributeRole; import com.rapidminer.example.Example; import com.rapidminer.example.ExampleSet; import com.rapidminer.operator.Model; import com.rapidminer.operator.OperatorCapability; import com.rapidminer.operator.OperatorDescription; import com.rapidminer.operator.OperatorException; import com.rapidminer.operator.annotation.ResourceConsumptionEstimator; import com.rapidminer.operator.learner.AbstractLearner; import com.rapidminer.operator.learner.PredictionModel; import com.rapidminer.parameter.ParameterType; import com.rapidminer.parameter.ParameterTypeBoolean; import com.rapidminer.parameter.ParameterTypeDouble; import com.rapidminer.tools.OperatorResourceConsumptionHandler; /** * This operator performs a vector linear regression. It regresses all regular * attributes upon a vector of labels. The attributes forming the vector have * to be marked as special, the special role names of all label attributes have * to start with <code>label</code>. * * TODO: Adapt meta data of model, but needs change of complete construction... * * @author Tobias Malbrecht */ public class VectorLinearRegression extends AbstractLearner { public static final String PARAMETER_USE_BIAS = "use_bias"; public static final String PARAMETER_RIDGE = "ridge"; public VectorLinearRegression(OperatorDescription description) { super(description); } public Model learn(ExampleSet exampleSet) throws OperatorException { boolean useBias = getParameterAsBoolean(PARAMETER_USE_BIAS); double ridge = getParameterAsDouble(PARAMETER_RIDGE); List<Attribute> labels = new LinkedList<Attribute>(); for (Iterator<AttributeRole> roleIterator = exampleSet.getAttributes().allAttributeRoles(); roleIterator.hasNext(); ) { AttributeRole role = roleIterator.next(); if (role.getSpecialName() != null && role.getSpecialName().startsWith("label")) { labels.add(role.getAttribute()); } } int biasOffset = useBias ? 1 : 0; int width = exampleSet.getAttributes().size() + 1; Matrix x = new Matrix(exampleSet.size(), width); Matrix y = new Matrix(exampleSet.size(), labels.size()); int j = 0; for (Example example : exampleSet) { if (useBias) { x.set(j, 0, 1); } int i = biasOffset; for (Attribute attribute : exampleSet.getAttributes()) { x.set(j, i, example.getValue(attribute)); i++; } int k = 0; for (Attribute label : labels) { y.set(j, k, example.getValue(label)); k++; } j++; } int numberOfColumns = x.getColumnDimension(); Matrix xTransposed = x.transpose(); Matrix result = null; boolean finished = false; while (!finished) { Matrix xTx = xTransposed.times(x); for (int i = 0; i < numberOfColumns; i++) xTx.set(i, i, xTx.get(i, i) + ridge); Matrix xTy = xTransposed.times(y); try { result = xTx.solve(xTy); finished = true; } catch (Exception ex) { ridge *= 10; finished = false; } } String[] labelNames = new String[labels.size()]; for (int i = 0; i < labels.size(); i++) { labelNames[i] = labels.get(i).getName(); } return new VectorRegressionModel(exampleSet, labelNames, result, useBias); } @Override public Class<? extends PredictionModel> getModelClass() { return VectorRegressionModel.class; } public boolean supportsCapability(OperatorCapability lc) { if (lc.equals(OperatorCapability.NUMERICAL_ATTRIBUTES)) return true; if (lc.equals(OperatorCapability.NUMERICAL_LABEL)) return true; if (lc == OperatorCapability.WEIGHTED_EXAMPLES) return false; return false; } @Override public List<ParameterType> getParameterTypes() { List<ParameterType> types = super.getParameterTypes(); types.add(new ParameterTypeBoolean(PARAMETER_USE_BIAS, "Indicates if an intercept value should be calculated.", true)); types.add(new ParameterTypeDouble(PARAMETER_RIDGE, "The ridge parameter.", 0, Double.POSITIVE_INFINITY, 1.0E-8)); return types; } @Override public ResourceConsumptionEstimator getResourceConsumptionEstimator() { return OperatorResourceConsumptionHandler.getResourceConsumptionEstimator(getExampleSetInputPort(), VectorLinearRegression.class, null); } }