JWS C Library
C language utility library
|
00001 /* 00002 * This work is licensed under a Creative Commons 00003 * Attribution-Noncommercial-Share Alike 3.0 United States License. 00004 * 00005 * http://creativecommons.org/licenses/by-nc-sa/3.0/us/ 00006 * 00007 * You are free: 00008 * 00009 * to Share - to copy, distribute, display, and perform the work 00010 * to Remix - to make derivative works 00011 * 00012 * Under the following conditions: 00013 * 00014 * Attribution. You must attribute the work in the manner specified by the 00015 * author or licensor (but not in any way that suggests that they endorse you 00016 * or your use of the work). 00017 * 00018 * Noncommercial. You may not use this work for commercial purposes. 00019 * 00020 * Share Alike. If you alter, transform, or build upon this work, you may 00021 * distribute the resulting work only under the same or similar license to 00022 * this one. 00023 * 00024 * For any reuse or distribution, you must make clear to others the license 00025 * terms of this work. The best way to do this is by including this header. 00026 * 00027 * Any of the above conditions can be waived if you get permission from the 00028 * copyright holder. 00029 * 00030 * Apart from the remix rights granted under this license, nothing in this 00031 * license impairs or restricts the author's moral rights. 00032 */ 00033 00034 00046 #include <jwsc/config.h> 00047 00048 #include <stdlib.h> 00049 #include <stdio.h> 00050 #include <assert.h> 00051 #include <math.h> 00052 #include <inttypes.h> 00053 00054 #include "jwsc/base/limits.h" 00055 #include "jwsc/vector/vector.h" 00056 #include "jwsc/vector/vector_math.h" 00057 #include "jwsc/matrix/matrix.h" 00058 #include "jwsc/matrix/matrix_math.h" 00059 #include "jwsc/matblock/matblock.h" 00060 #include "jwsc/prob/mv_pmf.h" 00061 #include "jwsc/stat/stat.h" 00062 #include "jwsc/stat/kmeans.h" 00063 #include "jwsc/stat/bmm.h" 00064 00065 00067 static void bmm_e_step_d 00068 ( 00069 const Matrix_d* mu, 00070 const Vector_d* pi, 00071 Matrix_d* gamma, 00072 const Matrix_u32* x 00073 ) 00074 { 00075 double b; 00076 double C_n; 00077 uint32_t k, K; 00078 uint32_t n, N; 00079 00080 Vector_u32* x_n = 0; 00081 Vector_d* mu_k = 0; 00082 00083 K = pi->num_elts; 00084 N = x->num_rows; 00085 00086 create_zero_matrix_d(&gamma, N, K); 00087 00088 for (n = 0; n < N; n++) 00089 { 00090 copy_vector_from_matrix_u32(&x_n, x, MATRIX_ROW_VECTOR, n); 00091 C_n = 0; 00092 00093 for (k = 0; k < K; k++) 00094 { 00095 copy_vector_from_matrix_d(&mu_k, mu, MATRIX_ROW_VECTOR, k); 00096 00097 mv_bernoulli_pmf_d(&b, mu_k, x_n); 00098 00099 gamma->elts[ n ][ k ] = pi->elts[ k ] * b; 00100 00101 C_n += gamma->elts[ n ][ k ]; 00102 } 00103 00104 assert(C_n > 0); 00105 00106 for (k = 0; k < K; k++) 00107 { 00108 gamma->elts[ n ][ k ] /= C_n; 00109 } 00110 } 00111 00112 free_vector_u32(x_n); 00113 free_vector_d(mu_k); 00114 } 00115 00116 00118 static void bmm_m_step_d 00119 ( 00120 Matrix_d* mu, 00121 Vector_d* pi, 00122 const Matrix_d* gamma, 00123 const Matrix_u32* x 00124 ) 00125 { 00126 uint32_t k, K; 00127 uint32_t n, N; 00128 uint32_t d, D; 00129 00130 Vector_d* mu_k = NULL; 00131 00132 K = pi->num_elts; 00133 N = x->num_rows; 00134 D = x->num_cols; 00135 00136 create_zero_vector_d(&pi, K); 00137 00138 // mu 00139 create_matrix_d(&mu, K, D); 00140 for (k = 0; k < K; k++) 00141 { 00142 create_zero_vector_d(&mu_k, D); 00143 00144 for (n = 0; n < N; n++) 00145 { 00146 for (d = 0; d < D; d++) 00147 { 00148 mu_k->elts[ d ] += gamma->elts[ n ][ k ]*x->elts[ n ][ d ]; 00149 } 00150 00151 pi->elts[ k ] += gamma->elts[ n ][ k ]; 00152 } 00153 00154 assert(pi->elts[ k ] > 0); 00155 00156 multiply_vector_by_scalar_d(&mu_k, mu_k, 1.0 / pi->elts[ k ]); 00157 copy_vector_into_matrix_d(&mu, mu, mu_k, MATRIX_ROW_VECTOR, k); 00158 } 00159 00160 // pi 00161 multiply_vector_by_scalar_d(&pi, pi, 1.0 / N); 00162 00163 free_vector_d(mu_k); 00164 } 00165 00166 00172 double bmm_log_likelihood_d 00173 ( 00174 const Matrix_d* mu, 00175 const Vector_d* pi, 00176 const Matrix_u32* x 00177 ) 00178 { 00179 uint32_t n, N; 00180 uint32_t k, K; 00181 double p, q; 00182 double ll; 00183 00184 Vector_u32* x_n = NULL; 00185 Vector_d* mu_k = NULL; 00186 00187 N = x->num_rows; 00188 K = pi->num_elts; 00189 00190 ll = 0; 00191 00192 for (n = 0; n < N; n++) 00193 { 00194 p = 0; 00195 copy_vector_from_matrix_u32(&x_n, x, MATRIX_ROW_VECTOR, n); 00196 00197 for (k = 0; k < K; k++) 00198 { 00199 copy_vector_from_matrix_d(&mu_k, mu, MATRIX_ROW_VECTOR, k); 00200 00201 mv_bernoulli_pmf_d(&q, mu_k, x_n); 00202 00203 p += pi->elts[ k ] * q; 00204 00205 #if defined(JWSC_HAVE_ISNAN) && defined(JWSC_HAVE_ISINF) 00206 assert(!isnan(p) && !isinf(p)); 00207 #endif 00208 } 00209 00210 ll += log((p < JWSC_MIN_LOG_ARG) ? JWSC_MIN_LOG_ARG : p); 00211 } 00212 00213 free_vector_u32(x_n); 00214 free_vector_d(mu_k); 00215 00216 return ll; 00217 } 00218 00219 00231 void bmm_kmeans_init_d 00232 ( 00233 Matrix_d** mu_out, 00234 Vector_d** pi_out, 00235 const Matrix_u32* x, 00236 uint32_t K 00237 ) 00238 { 00239 uint32_t d, D; 00240 uint32_t n, nn, N; 00241 uint32_t k; 00242 00243 Vector_i32* members = NULL; 00244 Vector_u32* counts = NULL; 00245 Matrix_d* x_d = NULL; 00246 Matrix_d* x_k = NULL; 00247 00248 D = x->num_cols; 00249 N = x->num_rows; 00250 00251 create_matrix_d(&x_d, N, D); 00252 for (n = 0; n < N; n++) 00253 { 00254 for (d = 0; d < D; d++) 00255 { 00256 x_d->elts[ n ][ d ] = (double)x->elts[ n ][ d ]; 00257 } 00258 } 00259 00260 init_kmeans_randomly_d(mu_out, x_d, K); 00261 kmeans_d(mu_out, &members, x_d, K, 2); 00262 00263 create_zero_vector_u32(&counts, K); 00264 00265 for (n = 0; n < N; n++) 00266 { 00267 k = members->elts[ n ]; 00268 counts->elts[ k ]++; 00269 } 00270 for (k = 0; k < K; k++) 00271 { 00272 create_matrix_d(&x_k, counts->elts[ k ], D); 00273 00274 nn = 0; 00275 for (n = 0; n < N; n++) 00276 { 00277 if (k == members->elts[ n ]) 00278 { 00279 for (d = 0; d < D; d++) 00280 { 00281 x_k->elts[ nn ][ d ] = x_d->elts[ n ][ d ]; 00282 } 00283 nn++; 00284 } 00285 } 00286 } 00287 00288 create_vector_d(pi_out, K); 00289 for (k = 0; k < K; k++) 00290 { 00291 (*pi_out)->elts[ k ] = counts->elts[ k ] / (double)N; 00292 } 00293 00294 free_vector_i32(members); 00295 free_vector_u32(counts); 00296 free_matrix_d(x_k); 00297 free_matrix_d(x_d); 00298 } 00299 00300 00310 void train_bmm_d 00311 ( 00312 Matrix_d** mu_out, 00313 Vector_d** pi_out, 00314 const Matrix_u32* x, 00315 uint32_t K 00316 ) 00317 { 00318 double ll, ll_prev; 00319 00320 Matrix_d* mu; 00321 Vector_d* pi; 00322 Matrix_d* gamma = 0; 00323 00324 bmm_kmeans_init_d(mu_out, pi_out, x, K); 00325 mu = *mu_out; 00326 pi = *pi_out; 00327 00328 create_matrix_d(&gamma, x->num_rows, pi->num_elts); 00329 00330 ll_prev = 0; 00331 ll = log(0); 00332 00333 while (fabs(ll - ll_prev) > 1.0e-10) 00334 { 00335 bmm_e_step_d(mu, pi, gamma, x); 00336 bmm_m_step_d(mu, pi, gamma, x); 00337 00338 ll_prev = ll; 00339 ll = bmm_log_likelihood_d(mu, pi, x); 00340 } 00341 00342 free_matrix_d(gamma); 00343 }