00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "cmtkGeneralLinearModel.h"
00034
00035 #include <math.h>
00036 #include <stdlib.h>
00037 #include <stdio.h>
00038
00039 #ifdef HAVE_IEEEFP_H
00040 # include <ieeefp.h>
00041 #endif
00042
00043 #include <System/cmtkProgress.h>
00044
00045 #include <Base/cmtkMathUtil.h>
00046
00047 namespace
00048 cmtk
00049 {
00050
00053
00054 #define TOL 1.0e-5
00055 GeneralLinearModel::GeneralLinearModel
00056 ( const size_t nParameters, const size_t nData, const double* designMatrix ) :
00057 NParameters( nParameters ),
00058 NData( nData ),
00059 DesignMatrix( nData, nParameters, designMatrix ),
00060 Up( nParameters ),
00061 Vp( nParameters ),
00062 Wp( nParameters ),
00063 VariableMean( nParameters ),
00064 VariableSD( nParameters )
00065 {
00066 U = new Matrix2D<double>( NData, NParameters );
00067 V = new Matrix2D<double>( NParameters, NParameters );
00068 W = new std::vector<double>( NParameters );
00069
00070 double wmax, thresh;
00071
00072 std::vector<double> data( this->NData );
00073 for ( size_t j=0; j < NParameters; ++j )
00074 {
00075
00076 for ( size_t i=0; i < this->NData; ++i )
00077 {
00078 data[i] = DesignMatrix[i][j];
00079 (*U)[i][j] = DesignMatrix[i][j];
00080 }
00081
00082
00083 this->VariableMean[j] = MathUtil::Mean<double>( data );
00084 this->VariableSD[j] = MathUtil::Variance<double>( data, this->VariableMean[j] );
00085
00086
00087 this->VariableSD[j] = sqrt( this->VariableSD[j] );
00088 }
00089
00090
00091
00092
00093 MathUtil::SVD( this->U, this->NData, this->NParameters, this->W, this->V );
00094
00095
00096 for ( size_t p=0; p < this->NParameters; ++p)
00097 {
00098 Up[p] = new Matrix2D<double>( NData, NParameters-1 );
00099 Vp[p] = new Matrix2D<double>( NParameters-1, NParameters-1 );
00100 Wp[p] = new std::vector<double>( NParameters-1 );
00101
00102
00103 for ( size_t i=0; i < this->NData; ++i )
00104 {
00105 size_t jj = 0;
00106 for ( size_t j=0; j < this->NParameters; ++j )
00107 {
00108 if ( j != p )
00109 {
00110 (*(this->Up[p]))[i][jj] = DesignMatrix[i][j];
00111 ++jj;
00112 }
00113 }
00114 }
00115
00116
00117 MathUtil::SVD( this->Up[p], this->NData, this->NParameters-1, this->Wp[p], this->Vp[p] );
00118 }
00119
00120 wmax=0.0;
00121 for ( size_t j=0;j<NParameters;j++)
00122 if ((*W)[j] > wmax) wmax=(*W)[j];
00123 thresh=TOL*wmax;
00124 for ( size_t j=0;j<NParameters;j++)
00125 if ((*W)[j] < thresh) (*W)[j]=0.0;
00126 }
00127
00128
00129 Matrix2D<double>*
00130 GeneralLinearModel::GetCorrelationMatrix() const
00131 {
00132 Matrix2D<double>* CC = new Matrix2D<double>( this->NParameters, this->NParameters );
00133
00134 std::vector<double> pi( this->NData );
00135 std::vector<double> pj( this->NData );
00136
00137 for ( size_t i = 0; i < this->NParameters; ++i )
00138 {
00139 for ( size_t n = 0; n < this->NData; ++n )
00140 {
00141 pi[n] = this->DesignMatrix[n][i];
00142 }
00143
00144 for ( size_t j = 0; j < this->NParameters; ++j )
00145 {
00146 if ( i <= j )
00147 {
00148 for ( size_t n = 0; n < this->NData; ++n )
00149 {
00150 pj[n] = this->DesignMatrix[n][j];
00151 }
00152 (*CC)[i][j] = MathUtil::Correlation( pi, pj );
00153 }
00154 else
00155 {
00156 (*CC)[i][j] = (*CC)[j][i];
00157 }
00158 }
00159 }
00160
00161 return CC;
00162 }
00163
00164 GeneralLinearModel::~GeneralLinearModel()
00165 {
00166 for ( size_t p=0; p < this->NParameters; ++p)
00167 {
00168 delete this->Wp[p];
00169 delete this->Vp[p];
00170 delete this->Up[p];
00171 }
00172 delete this->W;
00173 delete this->V;
00174 delete this->U;
00175 }
00176
00177 void
00178 GeneralLinearModel::InitResults( const size_t nPixels )
00179 {
00180 Model.clear();
00181 TStat.clear();
00182 for (size_t p = 0; (p<this->NParameters); ++p )
00183 {
00184 TypedArray::SmartPtr nextModel( TypedArray::Create( TYPE_FLOAT, nPixels ) );
00185 Model.push_back( nextModel );
00186
00187 TypedArray::SmartPtr nextTStat( TypedArray::Create( TYPE_FLOAT, nPixels ) );
00188 TStat.push_back( nextTStat );
00189 }
00190
00191 FStat = TypedArray::SmartPtr( TypedArray::Create( TYPE_FLOAT, nPixels ) );
00192 }
00193
00194 void
00195 GeneralLinearModel::FitModel
00196 ( std::vector<TypedArray::SmartPtr>& y, const bool normalizeParameters )
00197 {
00198 assert( y.size() == this->NData );
00199 const size_t nPixels = y[0]->GetDataSize();
00200 this->InitResults( nPixels );
00201
00202 std::vector<double> lm_params( this->NParameters );
00203 std::vector<double> b( this->NData );
00204 std::vector<double> valueYhat( this->NData );
00205
00206
00207
00208 const int df = this->NData - this->NParameters;
00209
00210 const size_t pixelUpdateIncrement = 10000;
00211 Progress::Begin( 0, nPixels, pixelUpdateIncrement, "Linear model fitting" );
00212
00213 for ( size_t n = 0; n < nPixels; ++n )
00214 {
00215 if ( ! (n % pixelUpdateIncrement) )
00216 if ( Progress::SetProgress( n ) != Progress::OK ) break;
00217
00218 bool missing = false;
00219 Types::DataItem value;
00220 for (size_t i = 0; (i<this->NData) && !missing; i++)
00221 if ( y[i]->Get( value, n ) && finite( value ) )
00222 b[i] = value;
00223 else
00224 missing = true;
00225
00226 if ( missing )
00227 {
00228 for (size_t p = 0; (p<this->NParameters); ++p )
00229 {
00230 this->Model[p]->SetPaddingAt( n );
00231 this->TStat[p]->SetPaddingAt( n );
00232 }
00233 }
00234 else
00235 {
00236
00237 MathUtil::SVDLinearRegression( this->U, this->NData, this->NParameters, this->W, this->V, &b[0], lm_params );
00238
00239
00240 double varY, avgY;
00241 avgY = MathUtil::Mean<double>( this->NData, &b[0] );
00242 varY = MathUtil::Variance<double>( this->NData, &b[0], avgY );
00243
00244
00245 for (size_t p = 0; (p<this->NParameters); ++p )
00246 {
00247 value = lm_params[p];
00248 if ( normalizeParameters )
00249
00250
00251 value *= this->GetNormFactor( p );
00252
00253 if ( finite( value ) )
00254 this->Model[p]->Set( value, n );
00255 else
00256 this->Model[p]->SetPaddingAt( n );
00257 }
00258
00259
00260 double varYhat, avgYhat;
00261 for (size_t i = 0; i<this->NData; i++)
00262 {
00263 valueYhat[i] = 0.0;
00264 for (size_t pi = 0; (pi<this->NParameters); ++pi )
00265 valueYhat[i] += lm_params[pi] * this->DesignMatrix[i][pi];
00266 }
00267 avgYhat = MathUtil::Mean<double>( this->NData, &valueYhat[0] );
00268 varYhat = MathUtil::Variance<double>( this->NData, &valueYhat[0], avgYhat );
00269
00270
00271 const double R2 = varYhat / varY;
00272 this->FStat->Set( (R2*df) / ((1-R2)*this->NParameters), n );
00273
00274 std::vector<double> lm_params_P( this->NParameters-1 );
00275 std::vector<double> valueYhatp( this->NData );
00276
00277
00278 for (size_t p = 0; p < this->NParameters; ++p )
00279 {
00280
00281
00282 {
00283
00284 MathUtil::SVDLinearRegression( this->Up[p], this->NData, this->NParameters-1, this->Wp[p], this->Vp[p], &b[0], lm_params_P );
00285
00286
00287 for (size_t i = 0; i < this->NData; i++)
00288 {
00289 valueYhatp[i] = 0.0;
00290 size_t pip = 0;
00291 for (size_t pi = 0; pi < this->NParameters; ++pi )
00292 {
00293 if ( p != pi )
00294 {
00295 valueYhatp[i] += lm_params_P[pip] * this->DesignMatrix[i][pi];
00296 ++pip;
00297 }
00298 }
00299 }
00300
00301 double varYhatp, avgYhatp;
00302 avgYhatp = MathUtil::Mean<double>( valueYhatp );
00303 varYhatp = MathUtil::Variance<double>( valueYhatp, avgYhatp );
00304
00305
00306 const double R2p = varYhatp / varY;
00307
00308
00309 const double srp = sqrt( R2 - R2p );
00310
00311
00312 double tStat = static_cast<double>( srp * sqrt( df / (1.0-R2) ) );
00313
00314 if ( MathUtil::IsNaN( tStat ) )
00315 tStat = 0;
00316 this->TStat[p]->Set( tStat, n );
00317 }
00318 }
00319 }
00320 }
00321
00322 Progress::Done();
00323 }
00324
00325 }