def best_parent(self, g, s, i, data, max_parents): """ Returns g by adding to node i the best parent that maximizes the score """ found_new = False r = g.compute_r(data) s_i = g.score_node(i, data, r) s_max = s g_max = g g_work = BayesNet(bn=g) for j in range(g.n): if j not in g_work.parents[i]: success = g_work.add_edge(j, i, max_parents) if success: s_new = s - s_i + g_work.score_node(i, data, r) if s_new > s_max: found_new = True s_max = s_new g_max = BayesNet(bn=g_work) g_work.remove_edge(j, i) return g_max, s_max, found_new
def best_neighbour(self, names, data, g0, max_parents): """ Find best neighboor of a BN Args names (list of string): the name of the nodes data (np array): (nsamples, nfeatures) g0 (BayesNet): the reference Returns g: best neighbour s: score of best neighbour """ print "Searching for best neighbour" # reference variables n = g0.n r = g0.compute_r(data) s0 = g0.score(data) # best candidate so far g = BayesNet(bn=g0) s = s0 s_eps = s0 found_new = False # working graph g_work = BayesNet(bn=g0) if max_parents is None: max_parents = n - 1 def update_best(mode="add"): """ When called, evaluate the working graph and update best candidate The s update must take place out of the function scope for python limitations """ # if mode == "rem" or not g_work.is_cyclic(): s_new = s0 - s_i + g_work.score_node(i, data, r) # we give a random advantage to the candidate based on previous updates s_eps_new = s_new + self.epsilon * np.random.rand() if s_eps_new > s_eps: print "Found new candidate ({}) at {}".format(mode, s_new) g.copy(g_work) return s_new, s_eps_new, True return s, s_eps, found_new # iterate over node center of the modification for i in xrange(n): parents = g0.parents[i] s_i = g0.score_node(i, data, r) # 1. remove edge for j in parents: g_work.remove_edge(j, i) s, s_eps, found_new = update_best("rem") g_work.add_edge(j, i) # 2. add edge if len(parents) < max_parents: for j_prime in xrange(n): if j_prime not in parents: if g_work.add_edge(j_prime, i): s, s_eps, found_new = update_best("add") g_work.remove_edge(j_prime, i) # 3. reverse direction for j in parents: if len(g0.parents[j]) < max_parents: g_work.remove_edge(j, i) if g_work.add_edge(i, j): s, s_eps, found_new = update_best("rev") g_work.remove_edge(i, j) g_work.add_edge(j, i) self.update_epsilon(s0, s) return g, s, found_new