001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.ml.timeseries.processor;
031
032import org.openimaj.ml.regression.LinearRegression;
033import org.openimaj.ml.timeseries.series.DoubleTimeSeries;
034import org.openimaj.util.array.ArrayUtils;
035
036import Jama.Matrix;
037
038/**
039 * Using a {@link LinearRegression} model, a time series is used as input to
040 * calculate the coefficients of a linear regression such that value = b * time
041 * + c
042 * 
043 * This is the simplest kind of model that can be applied to a time series
044 * 
045 * @author Sina Samangooei (ss@ecs.soton.ac.uk)
046 * 
047 */
048public class LinearRegressionProcessor implements TimeSeriesProcessor<double[], Double, DoubleTimeSeries> {
049
050        private LinearRegression reg;
051        private boolean regdefined;
052
053        /**
054         * Calculate the regression from the same time series inputed
055         */
056        public LinearRegressionProcessor() {
057                this.regdefined = false;
058        }
059
060        /**
061         * Use reg as the linear regression to predict. The
062         * {@link #process(DoubleTimeSeries)} function simply calls
063         * {@link LinearRegression#predict(Matrix)} with the times in the series as
064         * input
065         * 
066         * @param reg
067         */
068        public LinearRegressionProcessor(LinearRegression reg) {
069                this.reg = reg;
070                this.regdefined = true;
071        }
072
073        @Override
074        public void process(DoubleTimeSeries series) {
075                final Matrix x = new Matrix(new double[][] { ArrayUtils.convertToDouble(series.getTimes()) }).transpose();
076                if (!regdefined)
077                {
078                        this.reg = new LinearRegression();
079                        final Matrix y = new Matrix(new double[][] { series.getData() }).transpose();
080                        reg.estimate(y, x);
081                }
082                final Matrix predicted = this.reg.predict(x);
083                series.set(series.getTimes(), predicted.transpose().getArray()[0]);
084        }
085
086        /**
087         * @param regdefined
088         *            if true, process holds its last {@link LinearRegression}
089         */
090        public void holdreg(boolean regdefined) {
091                this.regdefined = regdefined;
092        }
093
094        /**
095         * @return the {@link LinearRegressionProcessor}'s underlying
096         *         {@link LinearRegression} model
097         */
098        public LinearRegression getRegression() {
099                return this.reg;
100        }
101
102}