@@ -1023,10 +1023,11 @@ def update_posterior(
1023
1023
* 'random_responsibility': randomly assign responsibility to gamma_vecs
1024
1024
"""
1025
1025
_check .float_vecs (x ,'x' ,DataFormatError )
1026
- if x .shape [- 1 ] != self .c_degree :
1027
- raise (DataFormatError (
1028
- "x.shape[-1] must be self.c_degree: "
1029
- + f"x.shape[-1]={ x .shape [- 1 ]} , self.c_degree={ self .c_degree } " ))
1026
+ _check .shape_consistency (
1027
+ x .shape [- 1 ],"x.shape[-1]" ,
1028
+ self .c_degree ,"self.c_degree" ,
1029
+ DataFormatError
1030
+ )
1030
1031
x = x .reshape (- 1 ,self .c_degree )
1031
1032
self ._length = x .shape [0 ]
1032
1033
self ._ln_rho = np .zeros ([self ._length ,self .c_num_classes ])
@@ -1105,19 +1106,24 @@ def estimate_params(self,loss="squared"):
1105
1106
"""Estimate the parameter under the given criterion.
1106
1107
1107
1108
Note that the criterion is applied to estimating
1108
- ``xxx``, ``xxx`` and ``xxx`` independently.
1109
- Therefore, a tuple of xxx, xxx and xxx will be returned when loss=\" xxx\"
1109
+ ``pi_vec``, ``a_mat`` ``mu_vecs`` and ``lambda_mats`` independently.
1110
+ Therefore, a tuple of the dirichlet distribution,
1111
+ the student's t-distributions and
1112
+ the wishart distributions will be returned when loss=\" KL\"
1110
1113
1111
1114
Parameters
1112
1115
----------
1113
1116
loss : str, optional
1114
1117
Loss function underlying the Bayes risk function, by default \" xxx\" .
1115
- This function supports \" xxx \" , \" xxx \" , and \" xxx \" .
1118
+ This function supports \" squared \" , \" 0-1 \" , and \" KL \" .
1116
1119
1117
1120
Returns
1118
1121
-------
1119
1122
Estimates : a tuple of {numpy ndarray, float, None, or rv_frozen}
1120
- * ``xxx`` : the estimate for xxx
1123
+ * ``pi_vec_hat`` : the estimate for pi_vec
1124
+ * ``a_mat_hat`` : the estimate for a_mat
1125
+ * ``mu_vecs_hat`` : the estimate for mu_vecs
1126
+ * ``Lambda_mats_hat`` : the estimate for Lambda_mats
1121
1127
The estimated values under the given loss function.
1122
1128
If it is not exist, `np.nan` will be returned.
1123
1129
If the loss function is \" KL\" , the posterior distribution itself
@@ -1128,16 +1134,150 @@ def estimate_params(self,loss="squared"):
1128
1134
scipy.stats.rv_continuous
1129
1135
scipy.stats.rv_discrete
1130
1136
"""
1131
- pass
1137
+ if loss == "squared" :
1138
+ return (self .hn_eta_vec / self .hn_eta_vec .sum (),
1139
+ self .hn_zeta_vecs / self .hn_zeta_vecs .sum (axis = 1 ,keepdims = True ),
1140
+ self .hn_m_vecs ,
1141
+ self ._e_lambda_mats )
1142
+ elif loss == "0-1" :
1143
+ pi_vec_hat = np .empty (self .c_num_classes )
1144
+ if np .all (self .hn_eta_vec > 1 ):
1145
+ pi_vec_hat [:] = (self .hn_eta_vec - 1 ) / (np .sum (self .hn_eta_vec ) - self .c_degree )
1146
+ else :
1147
+ warnings .warn ("MAP estimate of pi_vec doesn't exist for the current hn_eta_vec." ,ResultWarning )
1148
+ pi_vec_hat [:] = np .nan
1149
+ a_mat_hat = np .empty ([self .c_num_classes ,self .c_num_classes ])
1150
+ for i in range (self .c_num_classes ):
1151
+ if np .all (self .hn_eta_vec > 1 ):
1152
+ a_mat_hat [i ] = (self .hn_zeta_vecs [i ] - 1 ) / (np .sum (self .hn_zeta_vecs [i ]) - self .c_degree )
1153
+ else :
1154
+ warnings .warn (f"MAP estimate of a_mat[{ i } ] doesn't exist for the current hn_zeta_vecs[{ i } ]." ,ResultWarning )
1155
+ a_mat_hat [i ] = np .nan
1156
+ lambda_mats_hat = np .empty ([self .c_num_classes ,self .c_degree ,self .c_degree ])
1157
+ for k in range (self .c_num_classes ):
1158
+ if self .hn_nus [k ] >= self .c_degree + 1 :
1159
+ lambda_mats_hat [k ] = (self .hn_nus [k ] - self .c_degree - 1 ) * self .hn_w_mats [k ]
1160
+ else :
1161
+ warnings .warn (f"MAP estimate of lambda_mat doesn't exist for the current hn_nus[{ k } ]." ,ResultWarning )
1162
+ lambda_mats_hat [k ] = np .nan
1163
+ return pi_vec_hat , a_mat_hat , self .hn_m_vecs , lambda_mats_hat
1164
+ elif loss == "KL" :
1165
+ a_mat_pdfs = []
1166
+ mu_vec_pdfs = []
1167
+ lambda_mat_pdfs = []
1168
+ for k in range (self .c_num_classes ):
1169
+ a_mat_pdfs .append (ss_dirichlet (self .hn_zeta_vecs [k ]))
1170
+ mu_vec_pdfs .append (ss_multivariate_t (loc = self .hn_m_vecs [k ],
1171
+ shape = self .hn_w_mats_inv [k ] / self .hn_kappas [k ] / (self .hn_nus [k ] - self .c_degree + 1 ),
1172
+ df = self .hn_nus [k ] - self .c_degree + 1 ))
1173
+ lambda_mat_pdfs .append (ss_wishart (df = self .hn_nus [k ],scale = self .hn_w_mats [k ]))
1174
+ return (ss_dirichlet (self .hn_eta_vec ),
1175
+ a_mat_pdfs ,
1176
+ mu_vec_pdfs ,
1177
+ lambda_mat_pdfs )
1178
+ else :
1179
+ raise (CriteriaError (f"loss={ loss } is unsupported. "
1180
+ + "This function supports \" squared\" , \" 0-1\" , and \" KL\" ." ))
1132
1181
1133
1182
def visualize_posterior (self ):
1134
1183
"""Visualize the posterior distribution for the parameter.
1135
1184
1136
1185
Examples
1137
1186
--------
1138
- >>> from bayesml import xxx
1187
+ >>> from bayesml import hiddenmarkovnormal
1188
+ >>> gen_model = hiddenmarkovnormal.GenModel(
1189
+ >>> c_num_classes=2,
1190
+ >>> c_degree=1,
1191
+ >>> mu_vecs=np.array([[2],[-2]]),
1192
+ >>> a_mat=np.array([[0.95,0.05],[0.1,0.9]])
1193
+ >>> x,z = gen_model.gen_sample(100)
1194
+ >>> learn_model = hiddenmarkovnormal.LearnModel(c_num_classes=2, c_degree=1)
1195
+ >>> learn_model.update_posterior(x)
1196
+ >>> learn_model.visualize_posterior()
1197
+ hn_alpha_vec:
1198
+ [103.89444088 97.10555912]
1199
+ E[pi_vec]:
1200
+ [0.51688777 0.48311223]
1201
+ hn_zeta_vecs:
1202
+ [[0.90892737 0.09107263]
1203
+ [0.08810659 0.91189341]]
1204
+ hn_m_vecs (equivalent to E[mu_vecs]):
1205
+ [[-2.00135008]
1206
+ [ 1.97461369]]
1207
+ hn_kappas:
1208
+ [104.39444088 97.60555912]
1209
+ hn_nus:
1210
+ [104.39444088 97.60555912]
1211
+ hn_w_mats:
1212
+ [[[0.00890667]]
1213
+
1214
+ [[0.01009789]]]
1215
+ E[lambda_mats]=
1216
+ [[[0.92980714]]
1217
+
1218
+ [[0.98560985]]]
1219
+
1220
+ .. image:: ./images/hiddenmarkovnormal_posterior.png
1139
1221
"""
1140
- pass
1222
+ print ("hn_alpha_vec:" )
1223
+ print (f"{ self .hn_eta_vec } " )
1224
+ print ("E[pi_vec]:" )
1225
+ print (f"{ self .hn_eta_vec / self .hn_eta_vec .sum ()} " )
1226
+ print ("hn_zeta_vecs:" )
1227
+ print (f"{ self .hn_zeta_vecs / self .hn_zeta_vecs .sum (axis = 1 ,keepdims = True )} " )
1228
+ print ("hn_m_vecs (equivalent to E[mu_vecs]):" )
1229
+ print (f"{ self .hn_m_vecs } " )
1230
+ print ("hn_kappas:" )
1231
+ print (f"{ self .hn_kappas } " )
1232
+ print ("hn_nus:" )
1233
+ print (f"{ self .hn_nus } " )
1234
+ print ("hn_w_mats:" )
1235
+ print (f"{ self .hn_w_mats } " )
1236
+ print ("E[lambda_mats]=" )
1237
+ print (f"{ self ._e_lambda_mats } " )
1238
+ _ , _ , mu_vec_pdfs , lambda_mat_pdfs = self .estimate_params (loss = "KL" )
1239
+ if self .c_degree == 1 :
1240
+ fig , axes = plt .subplots (1 ,2 )
1241
+ axes [0 ].set_xlabel ("mu_vecs" )
1242
+ axes [0 ].set_ylabel ("Density" )
1243
+ axes [1 ].set_xlabel ("lambda_mats" )
1244
+ axes [1 ].set_ylabel ("Log density" )
1245
+ for k in range (self .c_num_classes ):
1246
+ # for mu_vecs
1247
+ x = np .linspace (self .hn_m_vecs [k ,0 ]- 4.0 * np .sqrt ((self .hn_w_mats_inv [k ] / self .hn_kappas [k ] / self .hn_nus [k ])[0 ,0 ]),
1248
+ self .hn_m_vecs [k ,0 ]+ 4.0 * np .sqrt ((self .hn_w_mats_inv [k ] / self .hn_kappas [k ] / self .hn_nus [k ])[0 ,0 ]),
1249
+ 100 )
1250
+ axes [0 ].plot (x ,mu_vec_pdfs [k ].pdf (x ))
1251
+ # for lambda_mats
1252
+ x = np .linspace (max (1.0e-8 ,self .hn_nus [k ]* self .hn_w_mats [k ]- 4.0 * np .sqrt (self .hn_nus [k ]/ 2.0 )* (2.0 * self .hn_w_mats [k ])),
1253
+ self .hn_nus [k ]* self .hn_w_mats [k ]+ 4.0 * np .sqrt (self .hn_nus [k ]/ 2.0 )* (2.0 * self .hn_w_mats [k ]),
1254
+ 500 )
1255
+ axes [1 ].plot (x [:,0 ,0 ],lambda_mat_pdfs [k ].logpdf (x [:,0 ,0 ]))
1256
+
1257
+ fig .tight_layout ()
1258
+ plt .show ()
1259
+
1260
+ elif self .c_degree == 2 :
1261
+ fig , axes = plt .subplots ()
1262
+ for k in range (self .c_num_classes ):
1263
+ x = np .linspace (self .hn_m_vecs [k ,0 ]- 3.0 * np .sqrt ((self .hn_w_mats_inv [k ] / self .hn_kappas [k ] / self .hn_nus [k ])[0 ,0 ]),
1264
+ self .hn_m_vecs [k ,0 ]+ 3.0 * np .sqrt ((self .hn_w_mats_inv [k ] / self .hn_kappas [k ] / self .hn_nus [k ])[0 ,0 ]),
1265
+ 100 )
1266
+ y = np .linspace (self .hn_m_vecs [k ,1 ]- 3.0 * np .sqrt ((self .hn_w_mats_inv [k ] / self .hn_kappas [k ] / self .hn_nus [k ])[1 ,1 ]),
1267
+ self .hn_m_vecs [k ,1 ]+ 3.0 * np .sqrt ((self .hn_w_mats_inv [k ] / self .hn_kappas [k ] / self .hn_nus [k ])[1 ,1 ]),
1268
+ 100 )
1269
+ xx , yy = np .meshgrid (x ,y )
1270
+ grid = np .empty ((100 ,100 ,2 ))
1271
+ grid [:,:,0 ] = xx
1272
+ grid [:,:,1 ] = yy
1273
+ axes .contour (xx ,yy ,mu_vec_pdfs [k ].pdf (grid ),cmap = 'Blues' )
1274
+ axes .plot (self .hn_m_vecs [k ,0 ],self .hn_m_vecs [k ,1 ],marker = "x" ,color = 'red' )
1275
+ axes .set_xlabel ("mu_vec[0]" )
1276
+ axes .set_ylabel ("mu_vec[1]" )
1277
+ plt .show ()
1278
+
1279
+ else :
1280
+ raise (ParameterFormatError ("if c_degree > 2, it is impossible to visualize the model by this function." ))
1141
1281
1142
1282
def get_p_params (self ):
1143
1283
"""Get the parameters of the predictive distribution.
0 commit comments