ECOCPAK v0.9
|
00001 // Copyright (C) 2011 the authors listed below 00002 // http://ecocpak.sourceforge.net 00003 // 00004 // Authors: 00005 // - Dimitrios Bouzas (bouzas at ieee dot org) 00006 // - Nikolaos Arvanitopoulos (niarvani at ieee dot org) 00007 // - Anastasios Tefas (tefas at aiia dot csd dot auth dot gr) 00008 // 00009 // This file is part of the ECOC PAK C++ library. It is 00010 // provided without any warranty of fitness for any purpose. 00011 // 00012 // You can redistribute this file and/or modify it under 00013 // the terms of the GNU Lesser General Public License (LGPL) 00014 // as published by the Free Software Foundation, either 00015 // version 3 of the License or (at your option) any later 00016 // version. 00017 // (see http://www.opensource.org/licenses for more info) 00018 00019 00022 00023 00024 00038 double 00039 compute_sigma 00040 ( 00041 const vector<ClassData>& classes_vector 00042 ) 00043 { 00044 double maximum = 0.0; 00045 double d = 0.0; 00046 00047 // create samples matrix 00048 mat samples = create_samples_matrix(classes_vector); 00049 00050 const u32 n_rows_j = samples.n_rows; 00051 const u32 n_rows_i = samples.n_rows - 1; 00052 00053 // find the minimum distance between all the samples in the set 00054 for(u32 i = 0; i < n_rows_i; i++) 00055 { 00056 for(u32 j = i + 1; j < n_rows_j; j++) 00057 { 00058 // compute distance as the Euclidean norm 00059 d = norm(samples.row(i) - samples.row(j), 2); 00060 00061 if(maximum < d) 00062 { 00063 maximum = d; 00064 } 00065 00066 } 00067 00068 } 00069 00070 return maximum / 2.0; 00071 } 00072 00073 00074 00100 template<typename T1, typename T2> 00101 typename T1::elem_type 00102 fqmi 00103 ( 00104 const Base<typename T1::elem_type, T1>& X, 00105 const Base<typename T2::elem_type, T2>& Y, 00106 const typename T1::elem_type sigma 00107 ) 00108 { 00109 arma_extra_debug_sigprint(); 00110 00111 // alias to element type of samples' matrix 00112 typedef typename T1::elem_type eT1; 00113 00114 // alias to element type of labels' vector 00115 typedef typename T2::elem_type eT2; 00116 00117 // unwrap samples matrix 00118 const unwrap<T1> tmp_X(X.get_ref()); 00119 const Mat<eT1>& samples = tmp_X.M; 00120 00121 // unwrap labels vector 00122 const unwrap<T2> tmp_Y(Y.get_ref()); 00123 const Mat<eT2> labels = tmp_Y.M; 00124 00125 // number of samples 00126 const u32 n_samples = samples.n_rows; 00127 00128 // number of attributes 00129 const u32 n_attributes = samples.n_cols; 00130 00131 // check whether input labels is a vector 00132 arma_debug_check 00133 ( 00134 (labels.is_vec() == false), 00135 "fqmi(): Input class labels should be a vector" 00136 ); 00137 00138 // check whether input labels number of elements is equal to the 00139 // number of samples 00140 arma_debug_check 00141 ( 00142 labels.n_elem != n_samples, 00143 "fqmi(): Input class labels must have the same number of elements with the number of input samples" 00144 ); 00145 00146 // Initialize VIN, VALL and VBTW terms to zero. 00147 00148 // VIN can be seen as interactions between pairs of 00149 // samples inside each class. 00150 eT1 vin = 0; 00151 00152 // VBTW consists of interactions between samples of 00153 // each class against all other samples. 00154 eT1 vbtw = 0; 00155 00156 // VALL consists of interactions between all pairs of 00157 // samples, regardless of class membership. 00158 eT1 vall = 0; 00159 00160 // find number of classes 00161 // find number of samples in each class 00162 // create new labels that start from one if necessary 00163 u32 n_classes = 0; 00164 Col<eT1> n_samples_each_class; 00165 Col<eT2> new_labels = 00166 process_labels(labels, n_samples_each_class, n_classes); 00167 00168 // compute normalization constant for later use 00169 eT1 n_samples_square = 1.0 / eT1(n_samples * n_samples); 00170 00171 // compute normalization constant for later use 00172 eT1 v = 2 * sigma * sigma; 00173 00174 // compact expression used in the kernel for later use 00175 eT1 exp_sigma = eT1(-1) / eT1(2 * v); 00176 00177 // compute normalization constant for later use 00178 eT1 nc = 00179 eT1(1) / eT1 00180 ( 00181 std::sqrt 00182 ( 00183 std::pow(2.0 * math::pi(), 00184 n_attributes) * std::pow(v, n_attributes) 00185 ) 00186 ); 00187 00188 // initialize temporary vector VBTW_tmp to hold intermediate 00189 // computations of VBTW term actually each position of vbtw_tmp 00190 // corresponds to a class label and holds the sums of the VBTW term 00191 // for each of the available classes 00192 Col<eT1> vbtw_tmp = zeros< Col<eT1> >(n_classes); 00193 00194 // initialize temporary scalar to hold intermediate computation of the 00195 // kernel 00196 eT1 tmp = 0; 00197 00198 // double for to compute the interactions of all samples with each 00199 // other it needs N^2 / 2 iterations, where N is the number of samples 00200 00201 // iterate through samples 00202 for(u32 i = 0; i < n_samples; i++) 00203 { 00204 // compute self interaction of the ith sample 00205 // exponential becomes zero and consequently 00206 // interaction is a constant as such update 00207 // VIN, VALL and VBTW accordingly 00208 vall += nc; 00209 vbtw_tmp[labels[i] - 1] += nc; 00210 vin += nc; 00211 00212 // compute interaction of ith sample with the rest of the samples 00213 for(u32 j = i + 1; j < n_samples; j++) 00214 { 00215 // compute the difference between ith and jth vectors 00216 Row<eT1> centered_sample = samples.row(i) - samples.row(j); 00217 00218 // compute kernel 00219 tmp = 00220 nc * std::exp 00221 ( 00222 exp_sigma * accu(centered_sample % centered_sample) 00223 ); 00224 00225 // update each of term VALL, VBTW and VIN accordingly 00226 00227 // multiply the kernel result by 2 because k(i,j) = k(j,i) 00228 vall += (2 * tmp); 00229 00230 // update the sum jth sample's class 00231 vbtw_tmp[labels[j] - 1] += tmp; 00232 00233 // update the sum jth sample's class 00234 vbtw_tmp[labels[i] - 1] += tmp; 00235 00236 // kernel result contributes to the VIN sum if ith and jth 00237 // samples belong to the same class (i.e., their respective 00238 // class labels are equal) 00239 if(labels[i] == labels[j]) 00240 { 00241 // multiply the kernel result by 2 because k(i,j) = k(j,i) 00242 vin += (2 * tmp); 00243 } 00244 00245 } 00246 00247 } 00248 00249 // normalization of VIN, VBTW and VALL terms 00250 vall = 00251 accu 00252 ( 00253 ( 00254 n_samples_each_class % n_samples_each_class 00255 ) * 00256 n_samples_square * vall 00257 ) * 00258 n_samples_square; 00259 00260 vbtw = 00261 n_samples_square * 00262 accu(vbtw_tmp % n_samples_each_class) / eT1(n_samples); 00263 00264 vin *= n_samples_square; 00265 00266 // compute and return MI value from vin, vall and vbtw terms 00267 00268 // equation is obtained by using a Parzen estimate with a 00269 // symmetrical Gaussian kernel of width sigma 00270 return (vin + vall) - (2.0 * vbtw); 00271 } 00272 00273 00274