0602cf17a696f9340e4df74a9e78301c6f914b8a
[pspp-builds.git] / src / math / linreg / predict.c
1 /*
2    lib/linreg/predict.c
3
4    Copyright (C) 2005 Free Software Foundation, Inc. Written by Jason H. Stover.
5
6    This program is free software; you can redistribute it and/or modify it under
7    the terms of the GNU General Public License as published by the Free
8    Software Foundation; either version 2 of the License, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful, but WITHOUT
12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14    more details.
15
16    You should have received a copy of the GNU General Public License along with
17    this program; if not, write to the Free Software Foundation, Inc., 51
18    Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
19  */
20
21 #include <config.h>
22 #include <math/linreg/linreg.h>
23 #include <math/coefficient.h>
24 #include <gl/xalloc.h>
25
26 /*
27   Predict the value of the dependent variable with the
28   new set of predictors. PREDICTORS must point to a list
29   of variables, each of whose values are stored in VALS,
30   in the same order.
31  */
32 double
33 pspp_linreg_predict (const struct variable **predictors,
34                      const union value **vals, const void *c_, int n_vals)
35 {
36   const pspp_linreg_cache *c = c_;
37   int i;
38   int j;
39   const struct pspp_coeff **found;
40   const struct pspp_coeff *coe;
41   double result;
42   double tmp;
43
44   if (predictors == NULL || vals == NULL || c == NULL)
45     {
46       return GSL_NAN;
47     }
48   if (c->coeff == NULL)
49     {
50       /* The stupid model: just guess the mean. */
51       return c->depvar_mean;
52     }
53   found = xnmalloc (c->n_coeffs, sizeof (*found));
54   *found = c->coeff[0];
55   result = c->coeff[0]->estimate;       /* Intercept. */
56
57   /*
58      The loops guard against the possibility that the caller passed us
59      inadequate information, such as too few or too many values, or
60      a redundant list of variable names.
61    */
62   for (j = 0; j < n_vals; j++)
63     {
64       coe = pspp_linreg_get_coeff (c, predictors[j], vals[j]);
65       i = 1;
66       while (found[i] == coe && i < c->n_coeffs)
67         {
68           i++;
69         }
70       if (i < c->n_coeffs)
71         {
72           found[i] = coe;
73           tmp = pspp_coeff_get_est (coe);
74           if (var_is_numeric (predictors[j]))
75             {
76               tmp *= vals[j]->f;
77             }
78           result += tmp;
79         }
80     }
81   free (found);
82
83   return result;
84 }
85
86 double
87 pspp_linreg_residual (const struct variable **predictors,
88                       const union value **vals,
89                       const union value *obs, const void *c, int n_vals)
90 {
91   double pred;
92   double result;
93
94   if (predictors == NULL || vals == NULL || c == NULL || obs == NULL)
95     {
96       return GSL_NAN;
97     }
98   pred = pspp_linreg_predict (predictors, vals, c, n_vals);
99
100   result = gsl_isnan (pred) ? GSL_NAN : (obs->f - pred);
101   return result;
102 }