def estimate_mixture_params(EmissionParameters, curr_counts_orig, curr_nr_of_counts_orig, curr_state, rand_sample_size, max_nr_iter, nr_of_iter=20, stop_crit=1.0, nr_of_init=10, verbosity=1): ''' This function estimates thedirichlet multinomial mixture parameters ''' #1) Copy old parameters and use it as initialisation for the first iteration alphas_list = [] mixtures_list = [] lls_list = [] curr_counts = deepcopy(curr_counts_orig) curr_nr_of_counts = deepcopy(curr_nr_of_counts_orig) if len(curr_counts.shape) == 1: curr_counts = np.expand_dims(curr_counts, axis=1) if np.sum(np.sum(curr_counts, axis=0) > 0) > 0: curr_nr_of_counts = curr_nr_of_counts[:, np.sum(curr_counts, axis=0) >0] curr_counts = curr_counts[:, np.sum(curr_counts, axis=0) >0] #Test for fitting distributions only on diag events curr_nr_of_counts = curr_nr_of_counts[:, np.sum(curr_counts, axis=0) > 10] curr_counts = curr_counts[:, np.sum(curr_counts, axis=0) > 10] tracks_per_rep = EmissionParameters['Diag_event_params']['alpha'][curr_state].shape[0] NrOfReplicates = curr_counts.shape[0] / tracks_per_rep noncon = np.sum(curr_counts[[tracks_per_rep - 1 + (tracks_per_rep * i) for i in range(NrOfReplicates)],:], axis=0) conv = np.sum(curr_counts, axis=0) - noncon ratio = conv / np.float64(conv + noncon) rat_ix = ((ratio > 0.05) * (ratio < 0.95)) > 0 rat_ix = ((ratio < 0.95)) > 0 curr_nr_of_counts = curr_nr_of_counts[:, rat_ix] curr_counts = curr_counts[:, rat_ix] #end test if len(curr_counts.shape) == 1: curr_counts = np.expand_dims(curr_counts, axis=1) #Save old lls mixtures and alphas mixtures = deepcopy(EmissionParameters['Diag_event_params']['mix_comp'][curr_state]) OldAlpha = deepcopy(EmissionParameters['Diag_event_params']['alpha'][curr_state]) #pdb.set_trace() scored_counts = score_counts(curr_counts, curr_state, EmissionParameters) scored_counts += np.tile(np.log(mixtures[:, np.newaxis]), (1, scored_counts.shape[1])) ll = np.sum(np.sum(logsumexp(scored_counts, axis=0) + np.log(curr_nr_of_counts))) alphas_list.append(deepcopy(EmissionParameters['Diag_event_params']['alpha'][curr_state])) mixtures_list.append(deepcopy(EmissionParameters['Diag_event_params']['mix_comp'][curr_state])) lls_list.append(ll) for curr_init in range(nr_of_init): #compute the curr mixture, ll and alpha #initialiste the parameters old_ll = 0 if curr_init == 0: OldAlpha = deepcopy(EmissionParameters['Diag_event_params']['alpha'][curr_state]) mixtures = deepcopy(mixtures) else: OldAlpha = np.random.uniform(low=0.0001, high=0.1, size=OldAlpha.shape) for i in range(OldAlpha.shape[1]): OldAlpha[np.random.randint(OldAlpha.shape[0]-1), i] = np.random.random() * 10.0 OldAlpha[-2, i] = np.random.random() * 1.0 OldAlpha[-1, i] = np.random.random() * 10.0 mixtures = np.random.uniform(low=0.0001, high=1.0, size=mixtures.shape) mixtures /= np.sum(mixtures) if EmissionParameters['Diag_event_params']['nr_mix_comp'] == 1: #Case that only one mixture component is given EmissionParameters['Diag_event_params']['alpha'][curr_state][:, 0] = diag_event_model.estimate_multinomial_parameters(curr_counts, curr_nr_of_counts, EmissionParameters, OldAlpha[:]) #compute ll scored_counts = score_counts(curr_counts, curr_state, EmissionParameters) scored_counts += np.tile(np.log(mixtures[:, np.newaxis]), (1, scored_counts.shape[1])) ll = np.sum(np.sum(logsumexp(scored_counts, axis=0) + np.log(curr_nr_of_counts))) alphas_list.append(deepcopy(EmissionParameters['Diag_event_params']['alpha'][curr_state])) mixtures_list.append(deepcopy(EmissionParameters['Diag_event_params']['mix_comp'][curr_state])) lls_list.append(ll) else: zero_ix = [] for iter_nr in range(max_nr_iter): print('em-iteration ' + str(iter_nr)) scored_counts = score_counts(curr_counts, curr_state, EmissionParameters) scored_counts += np.tile(np.log(mixtures[:, np.newaxis]), (1, scored_counts.shape[1])) # 2) Compute the mixture components #compute the normalisation factor normalised_likelihood = logsumexp(scored_counts, axis=0) old_ll = ll ll = np.sum(np.sum(logsumexp(scored_counts, axis=0) + np.log(curr_nr_of_counts))) if np.abs(old_ll - ll) < stop_crit: #Check if convergence has been reached if len(zero_ix) == 0: break normalised_scores = scored_counts - np.tile(normalised_likelihood, (scored_counts.shape[0], 1)) un_norm_mixtures = logsumexp(normalised_scores, b=np.tile(curr_nr_of_counts, (scored_counts.shape[0], 1)), axis = 1) mixtures = np.exp(un_norm_mixtures - logsumexp(un_norm_mixtures)) # 3) Compute for eachcount the most likely mixture component curr_weights = np.exp(normalised_scores) curr_weights = (curr_weights == np.tile(np.max(curr_weights, axis=0), (curr_weights.shape[0], 1))) *1.0 zero_mix = np.sum(curr_weights,axis=1) == 0 zero_ix = np.where(zero_mix)[0].tolist() EmissionParameters['Diag_event_params']['mix_comp'][curr_state] = mixtures #Get number of positions that are used. (In case there are fewer entries that rand_sample_size in counts) rand_size = min(rand_sample_size, curr_counts.shape[1]) for i in zero_ix: random_ix = np.random.choice(curr_counts.shape[1], rand_size, p=(curr_nr_of_counts[0, :] / np.float(np.sum(curr_nr_of_counts[0, :])))) curr_counts = np.hstack([curr_counts, curr_counts[:, random_ix]]) curr_nr_of_counts = np.hstack([curr_nr_of_counts, np.ones((1, rand_size))]) temp_array = np.zeros((normalised_scores.shape[0], rand_size)) temp_array[i, :] = i normalised_scores = np.hstack([normalised_scores, temp_array]) temp_array = np.zeros((curr_weights.shape[0], rand_size)) temp_array[i, :] = 1 curr_weights = np.hstack([curr_weights, temp_array]) # 4) Compute the dirichlet-multinomial parameters for curr_mix_comp in range(EmissionParameters['Diag_event_params']['nr_mix_comp']): local_counts = curr_counts local_nr_counts = curr_nr_of_counts * curr_weights[curr_mix_comp, :] local_counts = local_counts[:, local_nr_counts[0, :] > 0] local_nr_counts = local_nr_counts[0, local_nr_counts[0, :] > 0] if len(local_counts.shape) == 1: local_counts = np.expand_dims(local_counts, axis=1) curr_alpha = diag_event_model.estimate_multinomial_parameters(local_counts, local_nr_counts, EmissionParameters, OldAlpha[:, curr_mix_comp]) if curr_mix_comp in zero_ix: OldAlpha[:, curr_mix_comp] = np.random.uniform(low=0.0001, high=0.1, size=OldAlpha[:, curr_mix_comp].shape) OldAlpha[np.random.randint(OldAlpha.shape[0]), curr_mix_comp] = np.random.random() * 10.0 OldAlpha[-2, curr_mix_comp] = np.random.random() * 1.0 OldAlpha[-1, curr_mix_comp] = np.random.random() * 10.0 else: OldAlpha[:, curr_mix_comp] = curr_alpha if (len(zero_ix) > 0) and (iter_nr + 2 < max_nr_iter): #Treat the case where some mixtures have prob zero mixtures[zero_ix] = np.mean(mixtures) mixtures /= np.sum(mixtures) EmissionParameters['Diag_event_params']['mix_comp'][curr_state] = deepcopy(mixtures) EmissionParameters['Diag_event_params']['alpha'][curr_state] = deepcopy(OldAlpha) # Check if convergence has been achieved. alphas_list.append(deepcopy(OldAlpha)) mixtures[zero_ix] = np.min(mixtures[mixtures > 0]) mixtures /= np.sum(mixtures) mixtures_list.append(deepcopy(mixtures)) lls_list.append(ll) #select which alpha had the highest ll max_ll_pos = np.argmax(np.array(lls_list)) alpha = alphas_list[max_ll_pos] mixtures = mixtures_list[max_ll_pos] return alpha, mixtures
def Parallel_estimate_single_mixture_params(args): ''' This function estimates thedirichlet multinomial mixture parameters ''' stop_crit, rand_sample_size, max_nr_iter, curr_init, EmissionParameters, curr_state, curr_counts, curr_nr_of_counts = args #compute the curr mixture, ll and alpha #initialiste the parameters old_ll = 0 ll = -10 OldAlpha = deepcopy(EmissionParameters['Diag_event_params']['alpha'][curr_state]) mixtures = deepcopy(EmissionParameters['Diag_event_params']['mix_comp'][curr_state]) if curr_init > 0: OldAlpha = np.random.uniform(low=0.0001, high=0.1, size=OldAlpha.shape) for i in range(OldAlpha.shape[1]): OldAlpha[np.random.randint(OldAlpha.shape[0]-1), i] = np.random.random() * 10.0 OldAlpha[-2, i] = np.random.random() * 1.0 OldAlpha[-1, i] = np.random.random() * 10.0 mixtures = np.random.uniform(low=0.0001, high=1.0, size=mixtures.shape) mixtures /= np.sum(mixtures) if EmissionParameters['Diag_event_params']['nr_mix_comp'] == 1: #Case that only one mixture component is given EmissionParameters['Diag_event_params']['alpha'][curr_state][:, 0] = diag_event_model.estimate_multinomial_parameters(curr_counts, curr_nr_of_counts, EmissionParameters, OldAlpha[:]) #compute ll scored_counts = score_counts(curr_counts, curr_state, EmissionParameters) scored_counts += np.tile(np.log(mixtures[:, np.newaxis]), (1, scored_counts.shape[1])) ll = np.sum(np.sum(logsumexp(scored_counts, axis=0) + np.log(curr_nr_of_counts))) OldAlpha = deepcopy(EmissionParameters['Diag_event_params']['alpha'][curr_state]) mixtures = deepcopy(EmissionParameters['Diag_event_params']['mix_comp'][curr_state]) else: zero_ix = [] for iter_nr in range(max_nr_iter): print('em-iteration ' + str(iter_nr)) scored_counts = score_counts(curr_counts, curr_state, EmissionParameters) scored_counts += np.tile(np.log(mixtures[:, np.newaxis]), (1, scored_counts.shape[1])) # 2) Compute the mixture components #compute the normalisation factor normalised_likelihood = logsumexp(scored_counts, axis=0) old_ll = ll ll = np.sum(np.sum(logsumexp(scored_counts, axis=0) + np.log(curr_nr_of_counts))) if np.abs(old_ll - ll) < stop_crit: if len(zero_ix) == 0: break normalised_scores = scored_counts - np.tile(normalised_likelihood, (scored_counts.shape[0], 1)) un_norm_mixtures = logsumexp(normalised_scores, b=np.tile(curr_nr_of_counts, (scored_counts.shape[0], 1)), axis = 1) mixtures = np.exp(un_norm_mixtures - logsumexp(un_norm_mixtures)) # 3) Compute for eachcount the most likely mixture component curr_weights = np.exp(normalised_scores) curr_weights = (curr_weights == np.tile(np.max(curr_weights, axis=0), (curr_weights.shape[0], 1))) *1.0 zero_mix = np.sum(curr_weights,axis=1) == 0 zero_ix = np.where(zero_mix)[0].tolist() EmissionParameters['Diag_event_params']['mix_comp'][curr_state] = mixtures #Get number of positions that are used. (In case there are fewer entries that rand_sample_size in counts) rand_size = min(rand_sample_size, curr_counts.shape[1]) for i in zero_ix: random_ix = np.random.choice(curr_counts.shape[1], rand_size, p=(curr_nr_of_counts[0, :] / np.float(np.sum(curr_nr_of_counts[0, :])))) curr_counts = np.hstack([curr_counts, curr_counts[:, random_ix]]) curr_nr_of_counts = np.hstack([curr_nr_of_counts, np.ones((1, rand_size))]) temp_array = np.zeros((normalised_scores.shape[0], rand_size)) temp_array[i, :] = i normalised_scores = np.hstack([normalised_scores, temp_array]) temp_array = np.zeros((curr_weights.shape[0], rand_size)) temp_array[i, :] = 1 curr_weights = np.hstack([curr_weights, temp_array]) # 4) Compute the dirichlet-multinomial parameters for curr_mix_comp in range(EmissionParameters['Diag_event_params']['nr_mix_comp']): local_counts = curr_counts local_nr_counts = curr_nr_of_counts * curr_weights[curr_mix_comp, :] local_counts = local_counts[:, local_nr_counts[0, :] > 0] local_nr_counts = local_nr_counts[0, local_nr_counts[0, :] > 0] if len(local_counts.shape) == 1: local_counts = np.expand_dims(local_counts, axis=1) curr_alpha = diag_event_model.estimate_multinomial_parameters(local_counts, local_nr_counts, EmissionParameters, OldAlpha[:, curr_mix_comp]) if curr_mix_comp in zero_ix: OldAlpha[:, curr_mix_comp] = np.random.uniform(low=0.0001, high=0.1, size=OldAlpha[:, curr_mix_comp].shape) OldAlpha[np.random.randint(OldAlpha.shape[0]), curr_mix_comp] = np.random.random() * 10.0 OldAlpha[-2, curr_mix_comp] = np.random.random() * 1.0 OldAlpha[-1, curr_mix_comp] = np.random.random() * 10.0 else: OldAlpha[:, curr_mix_comp] = curr_alpha if (len(zero_ix) > 0) and (iter_nr + 2 < max_nr_iter): #Treat the case where some mixtures have prob zero mixtures[zero_ix] = np.mean(mixtures) mixtures /= np.sum(mixtures) EmissionParameters['Diag_event_params']['mix_comp'][curr_state] = deepcopy(mixtures) EmissionParameters['Diag_event_params']['alpha'][curr_state] = deepcopy(OldAlpha) # Check if convergence has been achieved. mixtures[zero_ix] = np.min(mixtures[mixtures > 0]) mixtures /= np.sum(mixtures) return [deepcopy(OldAlpha), mixtures, ll]