//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** @author John Miller * @version 1.6 * @date Fri Jan 5 14:03:36 EST 2018 * @see LICENSE (MIT style license file). * * @title Model: Null Model (predict the mean) */ package scalation.analytics import scala.collection.mutable.Set import scalation.linalgebra.{MatriD, MatrixD, VectoD, VectorD} import scalation.plot.Plot import scalation.util.{banner, Error} //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `NullModel` class implements the simplest type of predictive modeling technique * that just predicts the response 'y' to be the mean. * Fit the parameter vector 'b' in the null regression equation *

* y = b dot x + e = b0 + e *

* where 'e' represents the residual/error vector (the part not explained by the model). * @param y the response/output vector */ class NullModel (y: VectoD) extends Fit (y, 1, 1, y.dim) with Predictor with NoFeatureSelection { private var b: VectoD = null // parameter vector [b0] private var e: VectoD = null // residual/error vector [e_0, e_1, ... e_m-1 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the 'used' data matrix 'x' (for this model it's null). */ def getX: MatriD = null //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the 'used' response vector 'y'. */ def getY: VectoD = y //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Train the predictor by fitting the parameter vector (b-vector) in the * null regression equation. * @param x_null the training/full data/input matrix (ignored by `NullModel`) * @param y_ the training/full response/output vector */ def train (x_null: MatriD, y_ : VectoD): NullModel = { b = VectorD (y_.mean) // parameter vector [b0] this } // train //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Compute the error vector 'e' (difference between actual and predicted) and * useful diagnostics. * @param x_null the test/full data/input matrix (ignored by `NullModel`) * @param y_e the test/full response/output vector */ def eval (x_null: MatriD, y_e: VectoD): NullModel = { val yp = VectorD.fill (y_e.dim)(b(0)) // y predicted for (test/full) e = y_e - yp // compute residual/error vector e diagnose (e, y_e, yp) // compute diagnostics this } // eval //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Analyze a dataset using this model using ordinary training with the * 'train' method. * @param x_ the data/input matrix (ignored by `NullModel`) * @param y_ the response/output vector (training/full) * @param x_e the data/input matrix (ignored by `NullModel`) * @param y_e the response/output vector (testing/full) */ def analyze (x_ : MatriD = null, y_ : VectoD = y, x_e: MatriD = null, y_e: VectoD = y): NullModel = { train (x_, y_) // train the model on the training dataset val ym = y_.mean // compute mean of training response - FIX use ym eval (x_e, y_e) // evaluate using the testing dataset this } // analyze //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the hyper-parameters (the NullModel has none). */ def hparameter: HyperParameter = null //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the vector of parameter/coefficient values. */ def parameter: VectoD = b //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return a basic report on the trained model. * @see 'summary' method for more details */ def report: String = { s""" REPORT hparameter hp = $hparameter parameter b = $parameter fitMap qof = $fitMap """ } // report //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the vector of residuals/errors. */ def residual: VectoD = e //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Predict the value of 'y = f(z)' by evaluating the formula 'y = b dot z', * i.e., '[b0] dot [z0]'. * @param z the new vector to predict */ def predict (z: VectoD): Double = b(0) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Predict the value of 'y = f(z)' by evaluating the formula 'y = b dot z', * for each row of matrix 'z'. * @param z the new matrix to predict (only used for dimension) */ def predict (z: MatriD = null): VectoD = VectorD.fill (y.dim)(b(0)) } // NullModel class //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `NullModel` companion object provides a simple factory method * for building null models. */ object NullModel extends Error { //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a Simplee Linear Regression model from a combined data matrix. * @param xy the combined data matrix */ def apply (xy: MatriD): NullModel = { val n = xy.dim2 if (n < 1) { flaw ("apply", "the length of the 'xy' matrix must be at least 1"); null } else new NullModel (xy.col(n-1)) } // apply } // NullModel object //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `NullModelTest` object is used to test the `NullModel` class. *

* y = b dot x + e = b0 + e *

* > runMain scalation.analytics.NullModelTest */ object NullModelTest extends App { // 4 data points: val y = VectorD (1, 3, 3, 4) // y vector println (s"y = $y") val rg = new NullModel (y) rg.train (null, y).eval (null, y) println (rg.report) val z = VectorD (5) // predict y for one point val yp = rg.predict (z) println (s"predict ($z) = $yp") } // NullModelTest object //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `NullModelTest2` object is used to test the `NullModel` class. *

* y = b dot x + e = b0 + e *

* > runMain scalation.analytics.NullModelTest2 */ object NullModelTest2 extends App { // 5 data points: val y = VectorD (2.0, 3.0, 5.0, 4.0, 6.0) // response vector y println (s"y = $y") val rg = new NullModel (y) // create a NullModel rg.train (null, y).eval (null, y) // train on data and evaluate println (rg.report) val z = VectorD (5.0) // predict y for one point val yp = rg.predict (z) // yp (y-predicted or y-hat) println (s"predict ($z) = $yp") } // NullModelTest2 object