Example #1
0
    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
Example #2
0
    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