1 | /* |
---|
2 | * This program is free software; you can redistribute it and/or modify |
---|
3 | * it under the terms of the GNU General Public License as published by |
---|
4 | * the Free Software Foundation; either version 2 of the License, or (at |
---|
5 | * your option) any later version. |
---|
6 | * |
---|
7 | * This program is distributed in the hope that it will be useful, but |
---|
8 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
10 | * General Public License for more details. |
---|
11 | * |
---|
12 | * You should have received a copy of the GNU General Public License |
---|
13 | * along with this program; if not, write to the Free Software |
---|
14 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
---|
15 | |
---|
16 | /* |
---|
17 | * PaceMatrix.java |
---|
18 | * Copyright (C) 2002 University of Waikato, Hamilton, New Zealand |
---|
19 | * |
---|
20 | */ |
---|
21 | |
---|
22 | package weka.classifiers.functions.pace; |
---|
23 | |
---|
24 | import weka.core.RevisionUtils; |
---|
25 | import weka.core.matrix.DoubleVector; |
---|
26 | import weka.core.matrix.FlexibleDecimalFormat; |
---|
27 | import weka.core.matrix.IntVector; |
---|
28 | import weka.core.matrix.Matrix; |
---|
29 | import weka.core.matrix.Maths; |
---|
30 | |
---|
31 | import java.util.Random; |
---|
32 | import java.text.DecimalFormat; |
---|
33 | |
---|
34 | /** |
---|
35 | * Class for matrix manipulation used for pace regression. <p> |
---|
36 | * |
---|
37 | * REFERENCES <p> |
---|
38 | * |
---|
39 | * Wang, Y. (2000). "A new approach to fitting linear models in high |
---|
40 | * dimensional spaces." PhD Thesis. Department of Computer Science, |
---|
41 | * University of Waikato, New Zealand. <p> |
---|
42 | * |
---|
43 | * Wang, Y. and Witten, I. H. (2002). "Modeling for optimal probability |
---|
44 | * prediction." Proceedings of ICML'2002. Sydney. <p> |
---|
45 | * |
---|
46 | * @author Yong Wang (yongwang@cs.waikato.ac.nz) |
---|
47 | * @version $Revision: 1.6 $ |
---|
48 | */ |
---|
49 | public class PaceMatrix |
---|
50 | extends Matrix { |
---|
51 | |
---|
52 | /** for serialization */ |
---|
53 | static final long serialVersionUID = 2699925616857843973L; |
---|
54 | |
---|
55 | /* ------------------------ |
---|
56 | Constructors |
---|
57 | * ------------------------ */ |
---|
58 | |
---|
59 | /** Construct an m-by-n PACE matrix of zeros. |
---|
60 | @param m Number of rows. |
---|
61 | @param n Number of colums. |
---|
62 | */ |
---|
63 | public PaceMatrix( int m, int n ) { |
---|
64 | super( m, n ); |
---|
65 | } |
---|
66 | |
---|
67 | /** Construct an m-by-n constant PACE matrix. |
---|
68 | @param m Number of rows. |
---|
69 | @param n Number of colums. |
---|
70 | @param s Fill the matrix with this scalar value. |
---|
71 | */ |
---|
72 | public PaceMatrix( int m, int n, double s ) { |
---|
73 | super( m, n, s ); |
---|
74 | } |
---|
75 | |
---|
76 | /** Construct a PACE matrix from a 2-D array. |
---|
77 | @param A Two-dimensional array of doubles. |
---|
78 | @throws IllegalArgumentException All rows must have the same length |
---|
79 | */ |
---|
80 | public PaceMatrix( double[][] A ) { |
---|
81 | super( A ); |
---|
82 | } |
---|
83 | |
---|
84 | /** Construct a PACE matrix quickly without checking arguments. |
---|
85 | @param A Two-dimensional array of doubles. |
---|
86 | @param m Number of rows. |
---|
87 | @param n Number of colums. |
---|
88 | */ |
---|
89 | public PaceMatrix( double[][] A, int m, int n ) { |
---|
90 | super( A, m, n ); |
---|
91 | } |
---|
92 | |
---|
93 | /** Construct a PaceMatrix from a one-dimensional packed array |
---|
94 | @param vals One-dimensional array of doubles, packed by columns (ala Fortran). |
---|
95 | @param m Number of rows. |
---|
96 | @throws IllegalArgumentException Array length must be a multiple of m. |
---|
97 | */ |
---|
98 | public PaceMatrix( double vals[], int m ) { |
---|
99 | super( vals, m ); |
---|
100 | } |
---|
101 | |
---|
102 | /** Construct a PaceMatrix with a single column from a DoubleVector |
---|
103 | @param v DoubleVector |
---|
104 | */ |
---|
105 | public PaceMatrix( DoubleVector v ) { |
---|
106 | this( v.size(), 1 ); |
---|
107 | setMatrix( 0, v.size()-1, 0, v ); |
---|
108 | } |
---|
109 | |
---|
110 | /** Construct a PaceMatrix from a Matrix |
---|
111 | @param X Matrix |
---|
112 | */ |
---|
113 | public PaceMatrix( Matrix X ) { |
---|
114 | super( X.getRowDimension(), X.getColumnDimension() ); |
---|
115 | A = X.getArray(); |
---|
116 | } |
---|
117 | |
---|
118 | /* ------------------------ |
---|
119 | Public Methods |
---|
120 | * ------------------------ */ |
---|
121 | |
---|
122 | /** Set the row dimenion of the matrix |
---|
123 | * @param rowDimension the row dimension |
---|
124 | */ |
---|
125 | public void setRowDimension( int rowDimension ) |
---|
126 | { |
---|
127 | m = rowDimension; |
---|
128 | } |
---|
129 | |
---|
130 | /** Set the column dimenion of the matrix |
---|
131 | * @param columnDimension the column dimension |
---|
132 | */ |
---|
133 | public void setColumnDimension( int columnDimension ) |
---|
134 | { |
---|
135 | n = columnDimension; |
---|
136 | } |
---|
137 | |
---|
138 | /** |
---|
139 | * Clone the PaceMatrix object. |
---|
140 | * |
---|
141 | * @return the clone |
---|
142 | */ |
---|
143 | public Object clone () { |
---|
144 | PaceMatrix X = new PaceMatrix(m,n); |
---|
145 | double[][] C = X.getArray(); |
---|
146 | for (int i = 0; i < m; i++) { |
---|
147 | for (int j = 0; j < n; j++) { |
---|
148 | C[i][j] = A[i][j]; |
---|
149 | } |
---|
150 | } |
---|
151 | return (Object) X; |
---|
152 | } |
---|
153 | |
---|
154 | /** Add a value to an element and reset the element |
---|
155 | * @param i the row number of the element |
---|
156 | * @param j the column number of the element |
---|
157 | * @param s the double value to be added with |
---|
158 | */ |
---|
159 | public void setPlus(int i, int j, double s) { |
---|
160 | A[i][j] += s; |
---|
161 | } |
---|
162 | |
---|
163 | /** Multiply a value with an element and reset the element |
---|
164 | * @param i the row number of the element |
---|
165 | * @param j the column number of the element |
---|
166 | * @param s the double value to be multiplied with |
---|
167 | */ |
---|
168 | public void setTimes(int i, int j, double s) { |
---|
169 | A[i][j] *= s; |
---|
170 | } |
---|
171 | |
---|
172 | /** Set the submatrix A[i0:i1][j0:j1] with a same value |
---|
173 | * @param i0 the index of the first element of the column |
---|
174 | * @param i1 the index of the last element of the column |
---|
175 | * @param j0 the index of the first column |
---|
176 | * @param j1 the index of the last column |
---|
177 | * @param s the value to be set to |
---|
178 | */ |
---|
179 | public void setMatrix( int i0, int i1, int j0, int j1, double s ) { |
---|
180 | try { |
---|
181 | for( int i = i0; i <= i1; i++ ) { |
---|
182 | for( int j = j0; j <= j1; j++ ) { |
---|
183 | A[i][j] = s; |
---|
184 | } |
---|
185 | } |
---|
186 | } catch( ArrayIndexOutOfBoundsException e ) { |
---|
187 | throw new ArrayIndexOutOfBoundsException( "Index out of bounds" ); |
---|
188 | } |
---|
189 | } |
---|
190 | |
---|
191 | /** Set the submatrix A[i0:i1][j] with the values stored in a |
---|
192 | * DoubleVector |
---|
193 | * @param i0 the index of the first element of the column |
---|
194 | * @param i1 the index of the last element of the column |
---|
195 | * @param j the index of the column |
---|
196 | * @param v the vector that stores the values*/ |
---|
197 | public void setMatrix( int i0, int i1, int j, DoubleVector v ) { |
---|
198 | for( int i = i0; i <= i1; i++ ) { |
---|
199 | A[i][j] = v.get(i-i0); |
---|
200 | } |
---|
201 | } |
---|
202 | |
---|
203 | /** Set the whole matrix from a 1-D array |
---|
204 | * @param v 1-D array of doubles |
---|
205 | * @param columnFirst Whether to fill the column first or the row. |
---|
206 | * @throws ArrayIndexOutOfBoundsException Submatrix indices |
---|
207 | */ |
---|
208 | public void setMatrix ( double[] v, boolean columnFirst ) { |
---|
209 | try { |
---|
210 | if( v.length != m * n ) |
---|
211 | throw new IllegalArgumentException("sizes not match."); |
---|
212 | int i, j, count = 0; |
---|
213 | if( columnFirst ) { |
---|
214 | for( i = 0; i < m; i++ ) { |
---|
215 | for( j = 0; j < n; j++ ) { |
---|
216 | A[i][j] = v[count]; |
---|
217 | count ++; |
---|
218 | } |
---|
219 | } |
---|
220 | } |
---|
221 | else { |
---|
222 | for( j = 0; j < n; j++ ) { |
---|
223 | for( i = 0; i < m; i++ ){ |
---|
224 | A[i][j] = v[count]; |
---|
225 | count ++; |
---|
226 | } |
---|
227 | } |
---|
228 | } |
---|
229 | |
---|
230 | } catch( ArrayIndexOutOfBoundsException e ) { |
---|
231 | throw new ArrayIndexOutOfBoundsException( "Submatrix indices" ); |
---|
232 | } |
---|
233 | } |
---|
234 | |
---|
235 | /** Returns the maximum absolute value of all elements |
---|
236 | @return the maximum value |
---|
237 | */ |
---|
238 | public double maxAbs () { |
---|
239 | double ma = Math.abs(A[0][0]); |
---|
240 | for (int j = 0; j < n; j++) { |
---|
241 | for (int i = 0; i < m; i++) { |
---|
242 | ma = Math.max(ma, Math.abs(A[i][j])); |
---|
243 | } |
---|
244 | } |
---|
245 | return ma; |
---|
246 | } |
---|
247 | |
---|
248 | /** Returns the maximum absolute value of some elements of a column, |
---|
249 | that is, the elements of A[i0:i1][j]. |
---|
250 | @param i0 the index of the first element of the column |
---|
251 | @param i1 the index of the last element of the column |
---|
252 | @param j the index of the column |
---|
253 | @return the maximum value */ |
---|
254 | public double maxAbs ( int i0, int i1, int j ) { |
---|
255 | double m = Math.abs(A[i0][j]); |
---|
256 | for (int i = i0+1; i <= i1; i++) { |
---|
257 | m = Math.max(m, Math.abs(A[i][j])); |
---|
258 | } |
---|
259 | return m; |
---|
260 | } |
---|
261 | |
---|
262 | /** Returns the minimum absolute value of some elements of a column, |
---|
263 | that is, the elements of A[i0:i1][j]. |
---|
264 | @param i0 the index of the first element of the column |
---|
265 | @param i1 the index of the last element of the column |
---|
266 | @param column the index of the column |
---|
267 | @return the minimum value |
---|
268 | */ |
---|
269 | public double minAbs ( int i0, int i1, int column ) { |
---|
270 | double m = Math.abs(A[i0][column]); |
---|
271 | for (int i = i0+1; i <= i1; i++) { |
---|
272 | m = Math.min(m, Math.abs(A[i][column])); |
---|
273 | } |
---|
274 | return m; |
---|
275 | } |
---|
276 | |
---|
277 | /** Check if the matrix is empty |
---|
278 | * @return true if the matrix is empty |
---|
279 | */ |
---|
280 | public boolean isEmpty(){ |
---|
281 | if(m == 0 || n == 0) return true; |
---|
282 | if(A == null) return true; |
---|
283 | return false; |
---|
284 | } |
---|
285 | |
---|
286 | /** Return a DoubleVector that stores a column of the matrix |
---|
287 | * @param j the index of the column |
---|
288 | * @return the column |
---|
289 | */ |
---|
290 | public DoubleVector getColumn( int j ) { |
---|
291 | DoubleVector v = new DoubleVector( m ); |
---|
292 | double [] a = v.getArray(); |
---|
293 | for(int i = 0; i < m; i++) |
---|
294 | a[i] = A[i][j]; |
---|
295 | return v; |
---|
296 | } |
---|
297 | |
---|
298 | /** Return a DoubleVector that stores some elements of a column of the |
---|
299 | * matrix |
---|
300 | * @param i0 the index of the first element of the column |
---|
301 | * @param i1 the index of the last element of the column |
---|
302 | * @param j the index of the column |
---|
303 | * @return the DoubleVector |
---|
304 | */ |
---|
305 | public DoubleVector getColumn( int i0, int i1, int j ) { |
---|
306 | DoubleVector v = new DoubleVector( i1-i0+1 ); |
---|
307 | double [] a = v.getArray(); |
---|
308 | int count = 0; |
---|
309 | for( int i = i0; i <= i1; i++ ) { |
---|
310 | a[count] = A[i][j]; |
---|
311 | count++; |
---|
312 | } |
---|
313 | return v; |
---|
314 | } |
---|
315 | |
---|
316 | |
---|
317 | /** Multiplication between a row (or part of a row) of the first matrix |
---|
318 | * and a column (or part or a column) of the second matrix. |
---|
319 | * @param i the index of the row in the first matrix |
---|
320 | * @param j0 the index of the first column in the first matrix |
---|
321 | * @param j1 the index of the last column in the first matrix |
---|
322 | * @param B the second matrix |
---|
323 | * @param l the index of the column in the second matrix |
---|
324 | * @return the result of the multiplication |
---|
325 | */ |
---|
326 | public double times( int i, int j0, int j1, PaceMatrix B, int l ) { |
---|
327 | double s = 0.0; |
---|
328 | for(int j = j0; j <= j1; j++ ) { |
---|
329 | s += A[i][j] * B.A[j][l]; |
---|
330 | } |
---|
331 | return s; |
---|
332 | } |
---|
333 | |
---|
334 | /** Decimal format for converting a matrix into a string |
---|
335 | * @return the default decimal format |
---|
336 | */ |
---|
337 | protected DecimalFormat [] format() { |
---|
338 | return format(0, m-1, 0, n-1, 7, false ); |
---|
339 | } |
---|
340 | |
---|
341 | /** Decimal format for converting a matrix into a string |
---|
342 | * @param digits the number of digits |
---|
343 | * @return the decimal format |
---|
344 | */ |
---|
345 | protected DecimalFormat [] format( int digits ) { |
---|
346 | return format(0, m-1, 0, n-1, digits, false); |
---|
347 | } |
---|
348 | |
---|
349 | /** Decimal format for converting a matrix into a string |
---|
350 | * @param digits the number of digits |
---|
351 | * @param trailing |
---|
352 | * @return the decimal format |
---|
353 | */ |
---|
354 | protected DecimalFormat [] format( int digits, boolean trailing ) { |
---|
355 | return format(0, m-1, 0, n-1, digits, trailing); |
---|
356 | } |
---|
357 | |
---|
358 | /** Decimal format for converting a matrix into a string |
---|
359 | * @param i0 |
---|
360 | * @param i1 |
---|
361 | * @param j |
---|
362 | * @param digits the number of digits |
---|
363 | * @param trailing |
---|
364 | * @return the decimal format |
---|
365 | */ |
---|
366 | protected DecimalFormat format(int i0, int i1, int j, int digits, |
---|
367 | boolean trailing) { |
---|
368 | FlexibleDecimalFormat df = new FlexibleDecimalFormat(digits, trailing); |
---|
369 | df.grouping( true ); |
---|
370 | for(int i = i0; i <= i1; i ++ ) |
---|
371 | df.update( A[i][j] ); |
---|
372 | return df; |
---|
373 | } |
---|
374 | |
---|
375 | /** Decimal format for converting a matrix into a string |
---|
376 | * @param i0 |
---|
377 | * @param i1 |
---|
378 | * @param j0 |
---|
379 | * @param j1 |
---|
380 | * @param trailing |
---|
381 | * @param digits the number of digits |
---|
382 | * @return the decimal format |
---|
383 | */ |
---|
384 | protected DecimalFormat [] format(int i0, int i1, int j0, int j1, |
---|
385 | int digits, boolean trailing) { |
---|
386 | DecimalFormat [] f = new DecimalFormat[j1-j0+1]; |
---|
387 | for( int j = j0; j <= j1; j++ ) { |
---|
388 | f[j] = format(i0, i1, j, digits, trailing); |
---|
389 | } |
---|
390 | return f; |
---|
391 | } |
---|
392 | |
---|
393 | /** |
---|
394 | * Converts matrix to string |
---|
395 | * |
---|
396 | * @return the matrix as string |
---|
397 | */ |
---|
398 | public String toString() { |
---|
399 | return toString( 5, false ); |
---|
400 | } |
---|
401 | |
---|
402 | /** |
---|
403 | * Converts matrix to string |
---|
404 | * |
---|
405 | * @param digits number of digits after decimal point |
---|
406 | * @param trailing true if trailing zeros are padded |
---|
407 | * @return the matrix as string |
---|
408 | */ |
---|
409 | public String toString( int digits, boolean trailing ) { |
---|
410 | |
---|
411 | if( isEmpty() ) return "null matrix"; |
---|
412 | |
---|
413 | StringBuffer text = new StringBuffer(); |
---|
414 | DecimalFormat [] nf = format( digits, trailing ); |
---|
415 | int numCols = 0; |
---|
416 | int count = 0; |
---|
417 | int width = 80; |
---|
418 | int lenNumber; |
---|
419 | |
---|
420 | int [] nCols = new int[n]; |
---|
421 | int nk=0; |
---|
422 | for( int j = 0; j < n; j++ ) { |
---|
423 | lenNumber = nf[j].format( A[0][j]).length(); |
---|
424 | if( count + 1 + lenNumber > width -1 ) { |
---|
425 | nCols[nk++] = numCols; |
---|
426 | count = 0; |
---|
427 | numCols = 0; |
---|
428 | } |
---|
429 | count += 1 + lenNumber; |
---|
430 | ++numCols; |
---|
431 | } |
---|
432 | nCols[nk] = numCols; |
---|
433 | |
---|
434 | nk = 0; |
---|
435 | for( int k = 0; k < n; ) { |
---|
436 | for( int i = 0; i < m; i++ ) { |
---|
437 | for( int j = k; j < k + nCols[nk]; j++) |
---|
438 | text.append( " " + nf[j].format( A[i][j]) ); |
---|
439 | text.append("\n"); |
---|
440 | } |
---|
441 | k += nCols[nk]; |
---|
442 | ++nk; |
---|
443 | text.append("\n"); |
---|
444 | } |
---|
445 | |
---|
446 | return text.toString(); |
---|
447 | } |
---|
448 | |
---|
449 | /** Squared sum of a column or row in a matrix |
---|
450 | * @param j the index of the column or row |
---|
451 | * @param i0 the index of the first element |
---|
452 | * @param i1 the index of the last element |
---|
453 | * @param col if true, sum over a column; otherwise, over a row |
---|
454 | * @return the squared sum |
---|
455 | */ |
---|
456 | public double sum2( int j, int i0, int i1, boolean col ) { |
---|
457 | double s2 = 0; |
---|
458 | if( col ) { // column |
---|
459 | for( int i = i0; i <= i1; i++ ) |
---|
460 | s2 += A[i][j] * A[i][j]; |
---|
461 | } |
---|
462 | else { |
---|
463 | for( int i = i0; i <= i1; i++ ) |
---|
464 | s2 += A[j][i] * A[j][i]; |
---|
465 | } |
---|
466 | return s2; |
---|
467 | } |
---|
468 | |
---|
469 | /** Squared sum of columns or rows of a matrix |
---|
470 | * @param col if true, sum over columns; otherwise, over rows |
---|
471 | * @return the squared sum |
---|
472 | */ |
---|
473 | public double[] sum2( boolean col ) { |
---|
474 | int l = col ? n : m; |
---|
475 | int p = col ? m : n; |
---|
476 | double [] s2 = new double[l]; |
---|
477 | for( int i = 0; i < l; i++ ) |
---|
478 | s2[i] = sum2( i, 0, p-1, col ); |
---|
479 | return s2; |
---|
480 | } |
---|
481 | |
---|
482 | /** Constructs single Householder transformation for a column |
---|
483 | * |
---|
484 | @param j the index of the column |
---|
485 | @param k the index of the row |
---|
486 | @return d and q |
---|
487 | */ |
---|
488 | public double [] h1( int j, int k ) { |
---|
489 | double dq[] = new double[2]; |
---|
490 | double s2 = sum2(j, k, m-1, true); |
---|
491 | dq[0] = A[k][j] >= 0 ? - Math.sqrt( s2 ) : Math.sqrt( s2 ); |
---|
492 | A[k][j] -= dq[0]; |
---|
493 | dq[1] = A[k][j] * dq[0]; |
---|
494 | return dq; |
---|
495 | } |
---|
496 | |
---|
497 | /** Performs single Householder transformation on one column of a matrix |
---|
498 | * |
---|
499 | @param j the index of the column |
---|
500 | @param k the index of the row |
---|
501 | @param q q = - u'u/2; must be negative |
---|
502 | @param b the matrix to be transformed |
---|
503 | @param l the column of the matrix b |
---|
504 | */ |
---|
505 | public void h2( int j, int k, double q, PaceMatrix b, int l ) { |
---|
506 | double s = 0, alpha; |
---|
507 | for( int i = k; i < m; i++ ) |
---|
508 | s += A[i][j] * b.A[i][l]; |
---|
509 | alpha = s / q; |
---|
510 | for( int i = k; i < m; i++ ) |
---|
511 | b.A[i][l] += alpha * A[i][j]; |
---|
512 | } |
---|
513 | |
---|
514 | /** Constructs the Givens rotation |
---|
515 | * @param a |
---|
516 | * @param b |
---|
517 | * @return a double array that stores the cosine and sine values |
---|
518 | */ |
---|
519 | public double [] g1( double a, double b ) { |
---|
520 | double cs[] = new double[2]; |
---|
521 | double r = Maths.hypot(a, b); |
---|
522 | if( r == 0.0 ) { |
---|
523 | cs[0] = 1; |
---|
524 | cs[1] = 0; |
---|
525 | } |
---|
526 | else { |
---|
527 | cs[0] = a / r; |
---|
528 | cs[1] = b / r; |
---|
529 | } |
---|
530 | return cs; |
---|
531 | } |
---|
532 | |
---|
533 | /** Performs the Givens rotation |
---|
534 | * @param cs a array storing the cosine and sine values |
---|
535 | * @param i0 the index of the row of the first element |
---|
536 | * @param i1 the index of the row of the second element |
---|
537 | * @param j the index of the column |
---|
538 | */ |
---|
539 | public void g2( double cs[], int i0, int i1, int j ){ |
---|
540 | double w = cs[0] * A[i0][j] + cs[1] * A[i1][j]; |
---|
541 | A[i1][j] = - cs[1] * A[i0][j] + cs[0] * A[i1][j]; |
---|
542 | A[i0][j] = w; |
---|
543 | } |
---|
544 | |
---|
545 | /** Forward ordering of columns in terms of response explanation. On |
---|
546 | * input, matrices A and b are already QR-transformed. The indices of |
---|
547 | * transformed columns are stored in the pivoting vector. |
---|
548 | * |
---|
549 | *@param b the PaceMatrix b |
---|
550 | *@param pvt the pivoting vector |
---|
551 | *@param k0 the first k0 columns (in pvt) of A are not to be changed |
---|
552 | **/ |
---|
553 | public void forward( PaceMatrix b, IntVector pvt, int k0 ) { |
---|
554 | for( int j = k0; j < Math.min(pvt.size(), m); j++ ) { |
---|
555 | steplsqr( b, pvt, j, mostExplainingColumn(b, pvt, j), true ); |
---|
556 | } |
---|
557 | } |
---|
558 | |
---|
559 | /** Returns the index of the column that has the largest (squared) |
---|
560 | * response, when each of columns pvt[ks:] is moved to become the |
---|
561 | * ks-th column. On input, A and b are both QR-transformed. |
---|
562 | * |
---|
563 | * @param b response |
---|
564 | * @param pvt pivoting index of A |
---|
565 | * @param ks columns pvt[ks:] of A are to be tested |
---|
566 | * @return the index of the column |
---|
567 | */ |
---|
568 | public int mostExplainingColumn( PaceMatrix b, IntVector pvt, int ks ) { |
---|
569 | double val; |
---|
570 | int [] p = pvt.getArray(); |
---|
571 | double ma = columnResponseExplanation( b, pvt, ks, ks ); |
---|
572 | int jma = ks; |
---|
573 | for( int i = ks+1; i < pvt.size(); i++ ) { |
---|
574 | val = columnResponseExplanation( b, pvt, i, ks ); |
---|
575 | if( val > ma ) { |
---|
576 | ma = val; |
---|
577 | jma = i; |
---|
578 | } |
---|
579 | } |
---|
580 | return jma; |
---|
581 | } |
---|
582 | |
---|
583 | /** Backward ordering of columns in terms of response explanation. On |
---|
584 | * input, matrices A and b are already QR-transformed. The indices of |
---|
585 | * transformed columns are stored in the pivoting vector. |
---|
586 | * |
---|
587 | * A and b must have the same number of rows, being the (pseudo-)rank. |
---|
588 | * |
---|
589 | * @param b PaceMatrix b |
---|
590 | * @param pvt pivoting vector |
---|
591 | * @param ks number of QR-transformed columns; psuedo-rank of A |
---|
592 | * @param k0 first k0 columns in pvt[] are not to be ordered. |
---|
593 | */ |
---|
594 | public void backward( PaceMatrix b, IntVector pvt, int ks, int k0 ) { |
---|
595 | for( int j = ks; j > k0; j-- ) { |
---|
596 | steplsqr( b, pvt, j, leastExplainingColumn(b, pvt, j, k0), false ); |
---|
597 | } |
---|
598 | } |
---|
599 | |
---|
600 | /** Returns the index of the column that has the smallest (squared) |
---|
601 | * response, when the column is moved to become the (ks-1)-th |
---|
602 | * column. On input, A and b are both QR-transformed. |
---|
603 | * |
---|
604 | * @param b response |
---|
605 | * @param pvt pivoting index of A |
---|
606 | * @param ks psudo-rank of A |
---|
607 | * @param k0 A[][pvt[0:(k0-1)]] are excluded from the testing. |
---|
608 | * @return the index of the column |
---|
609 | */ |
---|
610 | public int leastExplainingColumn( PaceMatrix b, IntVector pvt, int ks, |
---|
611 | int k0 ) { |
---|
612 | double val; |
---|
613 | int [] p = pvt.getArray(); |
---|
614 | double mi = columnResponseExplanation( b, pvt, ks-1, ks ); |
---|
615 | int jmi = ks-1; |
---|
616 | for( int i = k0; i < ks - 1; i++ ) { |
---|
617 | val = columnResponseExplanation( b, pvt, i, ks ); |
---|
618 | if( val <= mi ) { |
---|
619 | mi = val; |
---|
620 | jmi = i; |
---|
621 | } |
---|
622 | } |
---|
623 | return jmi; |
---|
624 | } |
---|
625 | |
---|
626 | /** Returns the squared ks-th response value if the j-th column becomes |
---|
627 | * the ks-th after orthogonal transformation. A[][pvt[ks:j]] (or |
---|
628 | * A[][pvt[j:ks]], if ks > j) and b[] are already QR-transformed |
---|
629 | * on input and will remain unchanged on output. |
---|
630 | * |
---|
631 | * More generally, it returns the inner product of the corresponding |
---|
632 | * row vector of the response PaceMatrix. (To be implemented.) |
---|
633 | * |
---|
634 | *@param b PaceMatrix b |
---|
635 | *@param pvt pivoting vector |
---|
636 | *@param j the column A[pvt[j]][] is to be moved |
---|
637 | *@param ks the target column A[pvt[ks]][] |
---|
638 | *@return the squared response value */ |
---|
639 | public double columnResponseExplanation( PaceMatrix b, IntVector pvt, |
---|
640 | int j, int ks ) { |
---|
641 | /* Implementation: |
---|
642 | * |
---|
643 | * If j == ks - 1, returns the squared ks-th response directly. |
---|
644 | * |
---|
645 | * If j > ks -1, returns the ks-th response after |
---|
646 | * Householder-transforming the j-th column and the response. |
---|
647 | * |
---|
648 | * If j < ks - 1, returns the ks-th response after a sequence of |
---|
649 | * Givens rotations starting from the j-th row. */ |
---|
650 | |
---|
651 | int k, l; |
---|
652 | double [] xxx = new double[n]; |
---|
653 | int [] p = pvt.getArray(); |
---|
654 | double val; |
---|
655 | |
---|
656 | if( j == ks -1 ) val = b.A[j][0]; |
---|
657 | else if( j > ks - 1 ) { |
---|
658 | int jm = Math.min(n-1, j); |
---|
659 | DoubleVector u = getColumn(ks,jm,p[j]); |
---|
660 | DoubleVector v = b.getColumn(ks,jm,0); |
---|
661 | val = v.innerProduct(u) / u.norm2(); |
---|
662 | } |
---|
663 | else { // ks > j |
---|
664 | for( k = j+1; k < ks; k++ ) // make a copy of A[j][] |
---|
665 | xxx[k] = A[j][p[k]]; |
---|
666 | val = b.A[j][0]; |
---|
667 | double [] cs; |
---|
668 | for( k = j+1; k < ks; k++ ) { |
---|
669 | cs = g1( xxx[k], A[k][p[k]] ); |
---|
670 | for( l = k+1; l < ks; l++ ) |
---|
671 | xxx[l] = - cs[1] * xxx[l] + cs[0] * A[k][p[l]]; |
---|
672 | val = - cs[1] * val + cs[0] * b.A[k][0]; |
---|
673 | } |
---|
674 | } |
---|
675 | return val * val; // or inner product in later implementation??? |
---|
676 | } |
---|
677 | |
---|
678 | /** |
---|
679 | * QR transformation for a least squares problem<br/> |
---|
680 | * A x = b<br/> |
---|
681 | * implicitly both A and b are transformed. pvt.size() is the psuedo-rank of |
---|
682 | * A. |
---|
683 | * |
---|
684 | * @param b PaceMatrix b |
---|
685 | * @param pvt pivoting vector |
---|
686 | * @param k0 the first k0 columns of A (indexed by pvt) are pre-chosen. |
---|
687 | * (But subject to rank examination.) |
---|
688 | * |
---|
689 | * For example, the constant term may be reserved, in which |
---|
690 | * case k0 = 1. |
---|
691 | **/ |
---|
692 | public void lsqr( PaceMatrix b, IntVector pvt, int k0 ) { |
---|
693 | final double TINY = 1e-15; |
---|
694 | int [] p = pvt.getArray(); |
---|
695 | int ks = 0; // psuedo-rank |
---|
696 | for(int j = 0; j < k0; j++ ) // k0 pre-chosen columns |
---|
697 | if( sum2(p[j],ks,m-1,true) > TINY ){ // large diagonal element |
---|
698 | steplsqr(b, pvt, ks, j, true); |
---|
699 | ks++; |
---|
700 | } |
---|
701 | else { // collinear column |
---|
702 | pvt.shiftToEnd( j ); |
---|
703 | pvt.setSize(pvt.size()-1); |
---|
704 | k0--; |
---|
705 | j--; |
---|
706 | } |
---|
707 | |
---|
708 | // initial QR transformation |
---|
709 | for(int j = k0; j < Math.min( pvt.size(), m ); j++ ) { |
---|
710 | if( sum2(p[j], ks, m-1, true) > TINY ) { |
---|
711 | steplsqr(b, pvt, ks, j, true); |
---|
712 | ks++; |
---|
713 | } |
---|
714 | else { // collinear column |
---|
715 | pvt.shiftToEnd( j ); |
---|
716 | pvt.setSize(pvt.size()-1); |
---|
717 | j--; |
---|
718 | } |
---|
719 | } |
---|
720 | |
---|
721 | b.m = m = ks; // reset number of rows |
---|
722 | pvt.setSize( ks ); |
---|
723 | } |
---|
724 | |
---|
725 | /** QR transformation for a least squares problem <br/> |
---|
726 | * A x = b <br/> |
---|
727 | * implicitly both A and b are transformed. pvt.size() is the psuedo-rank of A. |
---|
728 | * |
---|
729 | * @param b PaceMatrix b |
---|
730 | * @param pvt pivoting vector |
---|
731 | * @param k0 the first k0 columns of A (indexed by pvt) are pre-chosen. |
---|
732 | * (But subject to rank examination.) |
---|
733 | * |
---|
734 | * For example, the constant term may be reserved, in which |
---|
735 | * case k0 = 1. |
---|
736 | **/ |
---|
737 | public void lsqrSelection( PaceMatrix b, IntVector pvt, int k0 ) { |
---|
738 | int numObs = m; // number of instances |
---|
739 | int numXs = pvt.size(); |
---|
740 | |
---|
741 | lsqr( b, pvt, k0 ); |
---|
742 | |
---|
743 | if( numXs > 200 || numXs > numObs ) { // too many columns. |
---|
744 | forward(b, pvt, k0); |
---|
745 | } |
---|
746 | backward(b, pvt, pvt.size(), k0); |
---|
747 | } |
---|
748 | |
---|
749 | /** |
---|
750 | * Sets all diagonal elements to be positive (or nonnegative) without |
---|
751 | * changing the least squares solution |
---|
752 | * @param Y the response |
---|
753 | * @param pvt the pivoted column index |
---|
754 | */ |
---|
755 | public void positiveDiagonal( PaceMatrix Y, IntVector pvt ) { |
---|
756 | |
---|
757 | int [] p = pvt.getArray(); |
---|
758 | for( int i = 0; i < pvt.size(); i++ ) { |
---|
759 | if( A[i][p[i]] < 0.0 ) { |
---|
760 | for( int j = i; j < pvt.size(); j++ ) |
---|
761 | A[i][p[j]] = - A[i][p[j]]; |
---|
762 | Y.A[i][0] = - Y.A[i][0]; |
---|
763 | } |
---|
764 | } |
---|
765 | } |
---|
766 | |
---|
767 | /** Stepwise least squares QR-decomposition of the problem |
---|
768 | * A x = b |
---|
769 | @param b PaceMatrix b |
---|
770 | @param pvt pivoting vector |
---|
771 | @param ks number of transformed columns |
---|
772 | @param j pvt[j], the column to adjoin or delete |
---|
773 | @param adjoin to adjoin if true; otherwise, to delete */ |
---|
774 | public void steplsqr( PaceMatrix b, IntVector pvt, int ks, int j, |
---|
775 | boolean adjoin ) { |
---|
776 | final int kp = pvt.size(); // number of columns under consideration |
---|
777 | int [] p = pvt.getArray(); |
---|
778 | |
---|
779 | if( adjoin ) { // adjoining |
---|
780 | int pj = p[j]; |
---|
781 | pvt.swap( ks, j ); |
---|
782 | double dq[] = h1( pj, ks ); |
---|
783 | int pk; |
---|
784 | for( int k = ks+1; k < kp; k++ ){ |
---|
785 | pk = p[k]; |
---|
786 | h2( pj, ks, dq[1], this, pk); |
---|
787 | } |
---|
788 | h2( pj, ks, dq[1], b, 0 ); // for matrix. ??? |
---|
789 | A[ks][pj] = dq[0]; |
---|
790 | for( int k = ks+1; k < m; k++ ) |
---|
791 | A[k][pj] = 0; |
---|
792 | } |
---|
793 | else { // removing |
---|
794 | int pj = p[j]; |
---|
795 | for( int i = j; i < ks-1; i++ ) |
---|
796 | p[i] = p[i+1]; |
---|
797 | p[ks-1] = pj; |
---|
798 | double [] cs; |
---|
799 | for( int i = j; i < ks-1; i++ ){ |
---|
800 | cs = g1( A[i][p[i]], A[i+1][p[i]] ); |
---|
801 | for( int l = i; l < kp; l++ ) |
---|
802 | g2( cs, i, i+1, p[l] ); |
---|
803 | for( int l = 0; l < b.n; l++ ) |
---|
804 | b.g2( cs, i, i+1, l ); |
---|
805 | } |
---|
806 | } |
---|
807 | } |
---|
808 | |
---|
809 | /** Solves upper-triangular equation <br/> |
---|
810 | * R x = b <br/> |
---|
811 | * On output, the solution is stored in b |
---|
812 | * @param b the response |
---|
813 | * @param pvt the pivoting vector |
---|
814 | * @param kp the number of the first columns involved |
---|
815 | */ |
---|
816 | public void rsolve( PaceMatrix b, IntVector pvt, int kp) { |
---|
817 | if(kp == 0) b.m = 0; |
---|
818 | int i, j, k; |
---|
819 | int [] p = pvt.getArray(); |
---|
820 | double s; |
---|
821 | double [][] ba = b.getArray(); |
---|
822 | for( k = 0; k < b.n; k++ ) { |
---|
823 | ba[kp-1][k] /= A[kp-1][p[kp-1]]; |
---|
824 | for( i = kp - 2; i >= 0; i-- ){ |
---|
825 | s = 0; |
---|
826 | for( j = i + 1; j < kp; j++ ) |
---|
827 | s += A[i][p[j]] * ba[j][k]; |
---|
828 | ba[i][k] -= s; |
---|
829 | ba[i][k] /= A[i][p[i]]; |
---|
830 | } |
---|
831 | } |
---|
832 | b.m = kp; |
---|
833 | } |
---|
834 | |
---|
835 | /** Returns a new matrix which binds two matrices together with rows. |
---|
836 | * @param b the second matrix |
---|
837 | * @return the combined matrix |
---|
838 | */ |
---|
839 | public PaceMatrix rbind( PaceMatrix b ){ |
---|
840 | if( n != b.n ) |
---|
841 | throw new IllegalArgumentException("unequal numbers of rows."); |
---|
842 | PaceMatrix c = new PaceMatrix( m + b.m, n ); |
---|
843 | c.setMatrix( 0, m - 1, 0, n - 1, this ); |
---|
844 | c.setMatrix( m, m + b.m - 1, 0, n - 1, b ); |
---|
845 | return c; |
---|
846 | } |
---|
847 | |
---|
848 | /** Returns a new matrix which binds two matrices with columns. |
---|
849 | * @param b the second matrix |
---|
850 | * @return the combined matrix |
---|
851 | */ |
---|
852 | public PaceMatrix cbind( PaceMatrix b ) { |
---|
853 | if( m != b.m ) |
---|
854 | throw new IllegalArgumentException("unequal numbers of rows: " + |
---|
855 | m + " and " + b.m); |
---|
856 | PaceMatrix c = new PaceMatrix(m, n + b.n); |
---|
857 | c.setMatrix( 0, m - 1, 0, n - 1, this ); |
---|
858 | c.setMatrix( 0, m - 1, n, n + b.n - 1, b ); |
---|
859 | return c; |
---|
860 | } |
---|
861 | |
---|
862 | /** Solves the nonnegative linear squares problem. That is, <p> |
---|
863 | * <center> min || A x - b||, subject to x >= 0. </center> <p> |
---|
864 | * |
---|
865 | * For algorithm, refer to P161, Chapter 23 of C. L. Lawson and |
---|
866 | * R. J. Hanson (1974). "Solving Least Squares |
---|
867 | * Problems". Prentice-Hall. |
---|
868 | * @param b the response |
---|
869 | * @param pvt vector storing pivoting column indices |
---|
870 | * @return solution */ |
---|
871 | public DoubleVector nnls( PaceMatrix b, IntVector pvt ) { |
---|
872 | int j, t, counter = 0, jm = -1, n = pvt.size(); |
---|
873 | double ma, max, alpha, wj; |
---|
874 | int [] p = pvt.getArray(); |
---|
875 | DoubleVector x = new DoubleVector( n ); |
---|
876 | double [] xA = x.getArray(); |
---|
877 | PaceMatrix z = new PaceMatrix(n, 1); |
---|
878 | PaceMatrix bt; |
---|
879 | |
---|
880 | // step 1 |
---|
881 | int kp = 0; // #variables in the positive set P |
---|
882 | while ( true ) { // step 2 |
---|
883 | if( ++counter > 3*n ) // should never happen |
---|
884 | throw new RuntimeException("Does not converge"); |
---|
885 | t = -1; |
---|
886 | max = 0.0; |
---|
887 | bt = new PaceMatrix( b.transpose() ); |
---|
888 | for( j = kp; j <= n-1; j++ ) { // W = A' (b - A x) |
---|
889 | wj = bt.times( 0, kp, m-1, this, p[j] ); |
---|
890 | if( wj > max ) { // step 4 |
---|
891 | max = wj; |
---|
892 | t = j; |
---|
893 | } |
---|
894 | } |
---|
895 | |
---|
896 | // step 3 |
---|
897 | if ( t == -1) break; // optimum achieved |
---|
898 | |
---|
899 | // step 5 |
---|
900 | pvt.swap( kp, t ); // move variable from set Z to set P |
---|
901 | kp++; |
---|
902 | xA[kp-1] = 0; |
---|
903 | steplsqr( b, pvt, kp-1, kp-1, true ); |
---|
904 | // step 6 |
---|
905 | ma = 0; |
---|
906 | while ( ma < 1.5 ) { |
---|
907 | for( j = 0; j <= kp-1; j++ ) z.A[j][0] = b.A[j][0]; |
---|
908 | rsolve(z, pvt, kp); |
---|
909 | ma = 2; jm = -1; |
---|
910 | for( j = 0; j <= kp-1; j++ ) { // step 7, 8 and 9 |
---|
911 | if( z.A[j][0] <= 0.0 ) { // alpha always between 0 and 1 |
---|
912 | alpha = xA[j] / ( xA[j] - z.A[j][0] ); |
---|
913 | if( alpha < ma ) { |
---|
914 | ma = alpha; jm = j; |
---|
915 | } |
---|
916 | } |
---|
917 | } |
---|
918 | if( ma > 1.5 ) |
---|
919 | for( j = 0; j <= kp-1; j++ ) xA[j] = z.A[j][0]; // step 7 |
---|
920 | else { |
---|
921 | for( j = kp-1; j >= 0; j-- ) { // step 10 |
---|
922 | // Modified to avoid round-off error (which seemingly |
---|
923 | // can cause infinite loop). |
---|
924 | if( j == jm ) { // step 11 |
---|
925 | xA[j] = 0.0; |
---|
926 | steplsqr( b, pvt, kp, j, false ); |
---|
927 | kp--; // move variable from set P to set Z |
---|
928 | } |
---|
929 | else xA[j] += ma * ( z.A[j][0] - xA[j] ); |
---|
930 | } |
---|
931 | } |
---|
932 | } |
---|
933 | } |
---|
934 | x.setSize(kp); |
---|
935 | pvt.setSize(kp); |
---|
936 | return x; |
---|
937 | } |
---|
938 | |
---|
939 | /** Solves the nonnegative least squares problem with equality |
---|
940 | * constraint. That is, <p> |
---|
941 | * <center> min ||A x - b||, subject to x >= 0 and c x = d. </center> <p> |
---|
942 | * |
---|
943 | * @param b the response |
---|
944 | * @param c coeficients of equality constraints |
---|
945 | * @param d constants of equality constraints |
---|
946 | * @param pvt vector storing pivoting column indices |
---|
947 | * @return the solution |
---|
948 | */ |
---|
949 | public DoubleVector nnlse( PaceMatrix b, PaceMatrix c, PaceMatrix d, |
---|
950 | IntVector pvt ) { |
---|
951 | double eps = 1e-10 * Math.max( c.maxAbs(), d.maxAbs() ) / |
---|
952 | Math.max( maxAbs(), b.maxAbs() ); |
---|
953 | |
---|
954 | PaceMatrix e = c.rbind( new PaceMatrix( times(eps) ) ); |
---|
955 | PaceMatrix f = d.rbind( new PaceMatrix( b.times(eps) ) ); |
---|
956 | |
---|
957 | return e.nnls( f, pvt ); |
---|
958 | } |
---|
959 | |
---|
960 | /** Solves the nonnegative least squares problem with equality |
---|
961 | * constraint. That is, <p> |
---|
962 | * <center> min ||A x - b||, subject to x >= 0 and || x || = 1. </center> |
---|
963 | * <p> |
---|
964 | * @param b the response |
---|
965 | * @param pvt vector storing pivoting column indices |
---|
966 | * @return the solution |
---|
967 | */ |
---|
968 | public DoubleVector nnlse1( PaceMatrix b, IntVector pvt ) { |
---|
969 | PaceMatrix c = new PaceMatrix( 1, n, 1 ); |
---|
970 | PaceMatrix d = new PaceMatrix( 1, b.n, 1 ); |
---|
971 | |
---|
972 | return nnlse(b, c, d, pvt); |
---|
973 | } |
---|
974 | |
---|
975 | /** Generate matrix with standard-normally distributed random elements |
---|
976 | @param m Number of rows. |
---|
977 | @param n Number of colums. |
---|
978 | @return An m-by-n matrix with random elements. */ |
---|
979 | public static Matrix randomNormal( int m, int n ) { |
---|
980 | Random random = new Random(); |
---|
981 | |
---|
982 | Matrix A = new Matrix(m,n); |
---|
983 | double[][] X = A.getArray(); |
---|
984 | for (int i = 0; i < m; i++) { |
---|
985 | for (int j = 0; j < n; j++) { |
---|
986 | X[i][j] = random.nextGaussian(); |
---|
987 | } |
---|
988 | } |
---|
989 | return A; |
---|
990 | } |
---|
991 | |
---|
992 | /** |
---|
993 | * Returns the revision string. |
---|
994 | * |
---|
995 | * @return the revision |
---|
996 | */ |
---|
997 | public String getRevision() { |
---|
998 | return RevisionUtils.extract("$Revision: 1.6 $"); |
---|
999 | } |
---|
1000 | |
---|
1001 | /** |
---|
1002 | * for testing only |
---|
1003 | * |
---|
1004 | * @param args the commandline arguments - ignored |
---|
1005 | */ |
---|
1006 | public static void main( String args[] ) { |
---|
1007 | System.out.println("================================================" + |
---|
1008 | "==========="); |
---|
1009 | System.out.println("To test the pace estimators of linear model\n" + |
---|
1010 | "coefficients.\n"); |
---|
1011 | |
---|
1012 | double sd = 2; // standard deviation of the random error term |
---|
1013 | int n = 200; // total number of observations |
---|
1014 | double beta0 = 100; // intercept |
---|
1015 | int k1 = 20; // number of coefficients of the first cluster |
---|
1016 | double beta1 = 0; // coefficient value of the first cluster |
---|
1017 | int k2 = 20; // number of coefficients of the second cluster |
---|
1018 | double beta2 = 5; // coefficient value of the second cluster |
---|
1019 | int k = 1 + k1 + k2; |
---|
1020 | |
---|
1021 | DoubleVector beta = new DoubleVector( 1 + k1 + k2 ); |
---|
1022 | beta.set( 0, beta0 ); |
---|
1023 | beta.set( 1, k1, beta1 ); |
---|
1024 | beta.set( k1+1, k1+k2, beta2 ); |
---|
1025 | |
---|
1026 | System.out.println("The data set contains " + n + |
---|
1027 | " observations plus " + (k1 + k2) + |
---|
1028 | " variables.\n\nThe coefficients of the true model" |
---|
1029 | + " are:\n\n" + beta ); |
---|
1030 | |
---|
1031 | System.out.println("\nThe standard deviation of the error term is " + |
---|
1032 | sd ); |
---|
1033 | |
---|
1034 | System.out.println("===============================================" |
---|
1035 | + "============"); |
---|
1036 | |
---|
1037 | PaceMatrix X = new PaceMatrix( n, k1+k2+1 ); |
---|
1038 | X.setMatrix( 0, n-1, 0, 0, 1 ); |
---|
1039 | X.setMatrix( 0, n-1, 1, k1+k2, random(n, k1+k2) ); |
---|
1040 | |
---|
1041 | PaceMatrix Y = new |
---|
1042 | PaceMatrix( X.times( new PaceMatrix(beta) ). |
---|
1043 | plusEquals( randomNormal(n,1).times(sd) ) ); |
---|
1044 | |
---|
1045 | IntVector pvt = (IntVector) IntVector.seq(0, k1+k2); |
---|
1046 | |
---|
1047 | /*System.out.println( "The OLS estimate (by jama.Matrix.solve()) is:\n\n" + |
---|
1048 | (new PaceMatrix(X.solve(Y))).getColumn(0) );*/ |
---|
1049 | |
---|
1050 | X.lsqrSelection( Y, pvt, 1 ); |
---|
1051 | X.positiveDiagonal( Y, pvt ); |
---|
1052 | |
---|
1053 | PaceMatrix sol = (PaceMatrix) Y.clone(); |
---|
1054 | X.rsolve( sol, pvt, pvt.size() ); |
---|
1055 | DoubleVector betaHat = sol.getColumn(0).unpivoting( pvt, k ); |
---|
1056 | System.out.println( "\nThe OLS estimate (through lsqr()) is: \n\n" + |
---|
1057 | betaHat ); |
---|
1058 | |
---|
1059 | System.out.println( "\nQuadratic loss of the OLS estimate (||X b - X bHat||^2) = " + |
---|
1060 | ( new PaceMatrix( X.times( new |
---|
1061 | PaceMatrix(beta.minus(betaHat)) ))) |
---|
1062 | .getColumn(0).sum2() ); |
---|
1063 | |
---|
1064 | System.out.println("=============================================" + |
---|
1065 | "=============="); |
---|
1066 | System.out.println(" *** Pace estimation *** \n"); |
---|
1067 | DoubleVector r = Y.getColumn( pvt.size(), n-1, 0); |
---|
1068 | double sde = Math.sqrt(r.sum2() / r.size()); |
---|
1069 | |
---|
1070 | System.out.println( "Estimated standard deviation = " + sde ); |
---|
1071 | |
---|
1072 | DoubleVector aHat = Y.getColumn( 0, pvt.size()-1, 0).times( 1./sde ); |
---|
1073 | System.out.println("\naHat = \n" + aHat ); |
---|
1074 | |
---|
1075 | System.out.println("\n========= Based on chi-square mixture ============"); |
---|
1076 | |
---|
1077 | ChisqMixture d2 = new ChisqMixture(); |
---|
1078 | int method = MixtureDistribution.NNMMethod; |
---|
1079 | DoubleVector AHat = aHat.square(); |
---|
1080 | d2.fit( AHat, method ); |
---|
1081 | System.out.println( "\nEstimated mixing distribution is:\n" + d2 ); |
---|
1082 | |
---|
1083 | DoubleVector ATilde = d2.pace2( AHat ); |
---|
1084 | DoubleVector aTilde = ATilde.sqrt().times(aHat.sign()); |
---|
1085 | PaceMatrix YTilde = new |
---|
1086 | PaceMatrix((new PaceMatrix(aTilde)).times( sde )); |
---|
1087 | X.rsolve( YTilde, pvt, pvt.size() ); |
---|
1088 | DoubleVector betaTilde = |
---|
1089 | YTilde.getColumn(0).unpivoting( pvt, k ); |
---|
1090 | System.out.println( "\nThe pace2 estimate of coefficients = \n" + |
---|
1091 | betaTilde ); |
---|
1092 | System.out.println( "Quadratic loss = " + |
---|
1093 | ( new PaceMatrix( X.times( new |
---|
1094 | PaceMatrix(beta.minus(betaTilde)) ))) |
---|
1095 | .getColumn(0).sum2() ); |
---|
1096 | |
---|
1097 | ATilde = d2.pace4( AHat ); |
---|
1098 | aTilde = ATilde.sqrt().times(aHat.sign()); |
---|
1099 | YTilde = new PaceMatrix((new PaceMatrix(aTilde)).times( sde )); |
---|
1100 | X.rsolve( YTilde, pvt, pvt.size() ); |
---|
1101 | betaTilde = YTilde.getColumn(0).unpivoting( pvt, k ); |
---|
1102 | System.out.println( "\nThe pace4 estimate of coefficients = \n" + |
---|
1103 | betaTilde ); |
---|
1104 | System.out.println( "Quadratic loss = " + |
---|
1105 | ( new PaceMatrix( X.times( new |
---|
1106 | PaceMatrix(beta.minus(betaTilde)) ))) |
---|
1107 | .getColumn(0).sum2() ); |
---|
1108 | |
---|
1109 | ATilde = d2.pace6( AHat ); |
---|
1110 | aTilde = ATilde.sqrt().times(aHat.sign()); |
---|
1111 | YTilde = new PaceMatrix((new PaceMatrix(aTilde)).times( sde )); |
---|
1112 | X.rsolve( YTilde, pvt, pvt.size() ); |
---|
1113 | betaTilde = YTilde.getColumn(0).unpivoting( pvt, k ); |
---|
1114 | System.out.println( "\nThe pace6 estimate of coefficients = \n" + |
---|
1115 | betaTilde ); |
---|
1116 | System.out.println( "Quadratic loss = " + |
---|
1117 | ( new PaceMatrix( X.times( new |
---|
1118 | PaceMatrix(beta.minus(betaTilde)) ))) |
---|
1119 | .getColumn(0).sum2() ); |
---|
1120 | |
---|
1121 | System.out.println("\n========= Based on normal mixture ============"); |
---|
1122 | |
---|
1123 | NormalMixture d = new NormalMixture(); |
---|
1124 | d.fit( aHat, method ); |
---|
1125 | System.out.println( "\nEstimated mixing distribution is:\n" + d ); |
---|
1126 | |
---|
1127 | aTilde = d.nestedEstimate( aHat ); |
---|
1128 | YTilde = new PaceMatrix((new PaceMatrix(aTilde)).times( sde )); |
---|
1129 | X.rsolve( YTilde, pvt, pvt.size() ); |
---|
1130 | betaTilde = YTilde.getColumn(0).unpivoting( pvt, k ); |
---|
1131 | System.out.println( "The nested estimate of coefficients = \n" + |
---|
1132 | betaTilde ); |
---|
1133 | System.out.println( "Quadratic loss = " + |
---|
1134 | ( new PaceMatrix( X.times( new |
---|
1135 | PaceMatrix(beta.minus(betaTilde)) ))) |
---|
1136 | .getColumn(0).sum2() ); |
---|
1137 | |
---|
1138 | |
---|
1139 | aTilde = d.subsetEstimate( aHat ); |
---|
1140 | YTilde = new PaceMatrix((new PaceMatrix(aTilde)).times( sde )); |
---|
1141 | X.rsolve( YTilde, pvt, pvt.size() ); |
---|
1142 | betaTilde = |
---|
1143 | YTilde.getColumn(0).unpivoting( pvt, k ); |
---|
1144 | System.out.println( "\nThe subset estimate of coefficients = \n" + |
---|
1145 | betaTilde ); |
---|
1146 | System.out.println( "Quadratic loss = " + |
---|
1147 | ( new PaceMatrix( X.times( new |
---|
1148 | PaceMatrix(beta.minus(betaTilde)) ))) |
---|
1149 | .getColumn(0).sum2() ); |
---|
1150 | |
---|
1151 | aTilde = d.empiricalBayesEstimate( aHat ); |
---|
1152 | YTilde = new PaceMatrix((new PaceMatrix(aTilde)).times( sde )); |
---|
1153 | X.rsolve( YTilde, pvt, pvt.size() ); |
---|
1154 | betaTilde = YTilde.getColumn(0).unpivoting( pvt, k ); |
---|
1155 | System.out.println( "\nThe empirical Bayes estimate of coefficients = \n"+ |
---|
1156 | betaTilde ); |
---|
1157 | |
---|
1158 | System.out.println( "Quadratic loss = " + |
---|
1159 | ( new PaceMatrix( X.times( new |
---|
1160 | PaceMatrix(beta.minus(betaTilde)) ))) |
---|
1161 | .getColumn(0).sum2() ); |
---|
1162 | |
---|
1163 | } |
---|
1164 | } |
---|
1165 | |
---|
1166 | |
---|
1167 | |
---|