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 java.util.ArrayList; 033import java.util.Iterator; 034import java.util.List; 035 036import org.openimaj.ml.regression.LinearRegression; 037import org.openimaj.ml.timeseries.series.DoubleTimeSeries; 038import org.openimaj.util.pair.IndependentPair; 039 040import Jama.Matrix; 041 042/** 043 * An implementation of an autoregressive model such that Xt = 044 * b*X{t-offset-window,t-offset} + c 045 * 046 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 047 * 048 */ 049public class WindowedLinearRegressionProcessor implements TimeSeriesProcessor<double[], Double, DoubleTimeSeries> { 050 051 private static final int DEFAULT_WINDOW_SIZE = 3; 052 private static final int DEFAULT_OFFSET = 1; 053 private LinearRegression reg; 054 private boolean regdefined; 055 private int windowsize; 056 private int offset; 057 058 /** 059 * Calculate the regression from the same time series inputed 060 */ 061 public WindowedLinearRegressionProcessor() { 062 this.windowsize = DEFAULT_WINDOW_SIZE; 063 this.offset = DEFAULT_OFFSET; 064 this.regdefined = false; 065 } 066 067 /** 068 * Perform regression s.t. y = Sum(w_{0-i} * x_{0-i}) + c for i from 1 to 069 * windowsize 070 * 071 * @param windowsize 072 */ 073 public WindowedLinearRegressionProcessor(int windowsize) { 074 this.windowsize = windowsize; 075 this.offset = DEFAULT_OFFSET; 076 this.regdefined = false; 077 078 } 079 080 /** 081 * Perform regression s.t. y = Sum(w_{0-i} * x_{0-i}) + c for i from 1 to 082 * windowsize 083 * 084 * @param windowsize 085 * @param offset 086 */ 087 public WindowedLinearRegressionProcessor(int windowsize, int offset) { 088 this.windowsize = windowsize; 089 this.offset = offset; 090 this.regdefined = false; 091 092 } 093 094 /** 095 * Use reg as the linear regression to predict. The 096 * {@link #process(DoubleTimeSeries)} function simply calls 097 * {@link LinearRegression#predict(Matrix)} with the times in the series as 098 * input 099 * 100 * @param reg 101 */ 102 public WindowedLinearRegressionProcessor(LinearRegression reg) { 103 this.reg = reg; 104 this.regdefined = true; 105 } 106 107 public WindowedLinearRegressionProcessor(DoubleTimeSeries yearFirstHalf, int i) { 108 final WindowedLinearRegressionProcessor inner = new WindowedLinearRegressionProcessor(i); 109 inner.process(yearFirstHalf); 110 this.reg = inner.reg; 111 this.windowsize = i; 112 this.regdefined = true; 113 } 114 115 public WindowedLinearRegressionProcessor(DoubleTimeSeries yearFirstHalf, int windowsize, int offset) { 116 final WindowedLinearRegressionProcessor inner = new WindowedLinearRegressionProcessor(windowsize, offset); 117 inner.process(yearFirstHalf); 118 this.reg = inner.reg; 119 this.windowsize = windowsize; 120 this.offset = offset; 121 this.regdefined = true; 122 } 123 124 @Override 125 public void process(DoubleTimeSeries series) { 126 final List<IndependentPair<double[], double[]>> instances = new ArrayList<IndependentPair<double[], double[]>>(); 127 final double[] data = series.getData(); 128 129 for (int i = this.windowsize + (offset - 1); i < series.size(); i++) { 130 final int start = i - this.windowsize - (offset - 1); 131 final double[] datawindow = new double[this.windowsize]; 132 System.arraycopy(data, start, datawindow, 0, this.windowsize); 133 instances.add(IndependentPair.pair(datawindow, new double[] { data[i] })); 134 } 135 if (!regdefined) 136 { 137 this.reg = new LinearRegression(); 138 this.reg.estimate(instances); 139 } 140 System.out.println(this.reg); 141 final Iterator<IndependentPair<double[], double[]>> instanceIter = instances.iterator(); 142 for (int i = this.windowsize + (offset - 1); i < series.size(); i++) { 143 data[i] = this.reg.predict(instanceIter.next().firstObject())[0]; 144 } 145 final long[] times = series.getTimes(); 146 final long begin = times[this.windowsize + (offset - 1)]; 147 final long end = times[times.length - 1]; 148 series.internalAssign(series.get(begin, end)); 149 } 150 151 /** 152 * @param regdefined 153 * if true, process holds its last {@link LinearRegression} 154 */ 155 public void holdreg(boolean regdefined) { 156 this.regdefined = regdefined; 157 } 158 159 /** 160 * @return the {@link WindowedLinearRegressionProcessor}'s underlying 161 * {@link LinearRegression} model 162 */ 163 public LinearRegression getRegression() { 164 return this.reg; 165 } 166 167}