View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.stat.regression;
23  
24  import org.hipparchus.linear.Array2DRowRealMatrix;
25  import org.hipparchus.linear.LUDecomposition;
26  import org.hipparchus.linear.RealMatrix;
27  import org.hipparchus.linear.RealVector;
28  
29  /**
30   * The GLS implementation of multiple linear regression.
31   *
32   * GLS assumes a general covariance matrix Omega of the error
33   * <pre>
34   * u ~ N(0, Omega)
35   * </pre>
36   *
37   * Estimated by GLS,
38   * <pre>
39   * b=(X' Omega^-1 X)^-1X'Omega^-1 y
40   * </pre>
41   * whose variance is
42   * <pre>
43   * Var(b)=(X' Omega^-1 X)^-1
44   * </pre>
45   */
46  public class GLSMultipleLinearRegression extends AbstractMultipleLinearRegression {
47  
48      /** Covariance matrix. */
49      private RealMatrix Omega;
50  
51      /** Inverse of covariance matrix. */
52      private RealMatrix OmegaInverse;
53  
54      /** Empty constructor.
55       * <p>
56       * This constructor is not strictly necessary, but it prevents spurious
57       * javadoc warnings with JDK 18 and later.
58       * </p>
59       * @since 3.0
60       */
61      public GLSMultipleLinearRegression() { // NOPMD - unnecessary constructor added intentionally to make javadoc happy
62          // nothing to do
63      }
64  
65      /** Replace sample data, overriding any previous sample.
66       * @param y y values of the sample
67       * @param x x values of the sample
68       * @param covariance array representing the covariance matrix
69       */
70      public void newSampleData(double[] y, double[][] x, double[][] covariance) {
71          validateSampleData(x, y);
72          newYSampleData(y);
73          newXSampleData(x);
74          validateCovarianceData(x, covariance);
75          newCovarianceData(covariance);
76      }
77  
78      /**
79       * Add the covariance data.
80       *
81       * @param omega the [n,n] array representing the covariance
82       */
83      protected void newCovarianceData(double[][] omega){
84          this.Omega = new Array2DRowRealMatrix(omega);
85          this.OmegaInverse = null;
86      }
87  
88      /**
89       * Get the inverse of the covariance.
90       * <p>The inverse of the covariance matrix is lazily evaluated and cached.</p>
91       * @return inverse of the covariance
92       */
93      protected RealMatrix getOmegaInverse() {
94          if (OmegaInverse == null) {
95              OmegaInverse = new LUDecomposition(Omega).getSolver().getInverse();
96          }
97          return OmegaInverse;
98      }
99  
100     /**
101      * Calculates beta by GLS.
102      * <pre>
103      *  b=(X' Omega^-1 X)^-1X'Omega^-1 y
104      * </pre>
105      * @return beta
106      */
107     @Override
108     protected RealVector calculateBeta() {
109         RealMatrix OI = getOmegaInverse();
110         RealMatrix XT = getX().transpose();
111         RealMatrix XTOIX = XT.multiply(OI).multiply(getX());
112         RealMatrix inverse = new LUDecomposition(XTOIX).getSolver().getInverse();
113         return inverse.multiply(XT).multiply(OI).operate(getY());
114     }
115 
116     /**
117      * Calculates the variance on the beta.
118      * <pre>
119      *  Var(b)=(X' Omega^-1 X)^-1
120      * </pre>
121      * @return The beta variance matrix
122      */
123     @Override
124     protected RealMatrix calculateBetaVariance() {
125         RealMatrix OI = getOmegaInverse();
126         RealMatrix XTOIX = getX().transposeMultiply(OI).multiply(getX());
127         return new LUDecomposition(XTOIX).getSolver().getInverse();
128     }
129 
130 
131     /**
132      * Calculates the estimated variance of the error term using the formula
133      * <pre>
134      *  Var(u) = Tr(u' Omega^-1 u)/(n-k)
135      * </pre>
136      * where n and k are the row and column dimensions of the design
137      * matrix X.
138      *
139      * @return error variance
140      */
141     @Override
142     protected double calculateErrorVariance() {
143         RealVector residuals = calculateResiduals();
144         double t = residuals.dotProduct(getOmegaInverse().operate(residuals));
145         return t / (getX().getRowDimension() - getX().getColumnDimension());
146 
147     }
148 
149 }