<jupyter_start><jupyter_text>Random Bayesian Network GeneratorAuthor: [<NAME>](mailto:<EMAIL>), D3M Lab, MIE, University of TorontoA Bayesian network, Bayes network, belief network, Bayes(ian) model or probabilistic directed acyclic graphical model is a probabilistic graphical model (a type of statistical model) that represents a set of random variables and their conditional dependencies via a directed acyclic graph (DAG).[Cite](https://en.wikipedia.org/wiki/Bayesian_network)This code generates random Bayesian Network in [json format](http://www.json.org/), which corresponding to the import format of python package [libpgm](http://pythonhosted.org/libpgm/). LimitationThe current code only support Bayesian Network with following property:1. Binary Variables(*)2. Multiple Parents nodes3. Single Child node(*)4. Arbitrary number of nodesNote: the stars are big limitation, please if it fits your requirement InstructionCalling this module is very simple. You only need to instantiate one instance of BayesNet class and provide number of variables of the target Bayesian Network.<jupyter_code># bn = BayesNet(20): will generate a random bayes network with 20 variables.
# print bn.stream(): will print the json format on console screen
# bn.writeStream('data/bn/new_bn.txt'): will write json file to the target directory<jupyter_output><empty_output><jupyter_text>PackagesThe following list of packages are more than necessary. We put them here to remind ourselves of possible extension direction. Feel free to remove unnecessary package to lighten your work.<jupyter_code>import os
import json
import sys
import numpy as np
import pandas as pd
import string
import unicodedata
from numpy import genfromtxt
from tqdm import tqdm
import random 
import copy
import itertools

#Load PGM library
from libpgm.nodedata import NodeData
from libpgm.graphskeleton import GraphSkeleton
from libpgm.discretebayesiannetwork import DiscreteBayesianNetwork
from libpgm.lgbayesiannetwork import LGBayesianNetwork
from libpgm.hybayesiannetwork import HyBayesianNetwork
from libpgm.dyndiscbayesiannetwork import DynDiscBayesianNetwork
from libpgm.tablecpdfactorization import TableCPDFactorization
from libpgm.sampleaggregator import SampleAggregator
from libpgm.pgmlearner import PGMLearner<jupyter_output><empty_output><jupyter_text>Node One unit of bayesian network. This class represents the property of single node:1. Parents list2. Children list3. Conditional probabilities<jupyter_code>class Node():
    def __init__(self,name):
        self.name = name
        self.conds = {}
        
    def setParents(self, parents):
        self.parents = parents
        
    def setChild(self,child):
        self.child =child
        
    def setRandConds(self):
        if not self.parents:
            p = round(random.uniform(0.1,0.9), 5)
            self.conds["No_Parents"] = [round(p,5), round(1-p,5)]
        else:
            combinations = ["".join(seq) for seq in itertools.product("01", repeat=len(self.parents))]
            for c in combinations:
                p = round(random.uniform(0.1,0.9), 5)
                self.conds[c] = [round(p,5), round(1-p,5)]
                
    def getParents(self):
        return self.parents
    
    def getChild(self):
        return self.child
    
    def getConds(self):
        return self.conds<jupyter_output><empty_output><jupyter_text>Bayesian NetworkPlease do not modify any of the following code. The libpgm is very picky! Any small changes could cause error in libpgm side.<jupyter_code>class BayesNet():
    def __init__(self, num):
        self.Vdata = []
        self.V = []
        self.E = []
        vars = self._createVariables(num)
        self._createConnections(vars)
        self._createVdata(vars)
        
    def _createVariables(self,num):
        vars = []
        for i in range(num):
            vars.append('Binary_Variable_'+format(i,'03d'))
        self.neighbors = {}
        for v in vars:
            self.neighbors[v] = []
        return vars
        
    def _createConnections(self,vars):
        connected = []
        edges = []
        e = random.sample(vars, 2)
        connected.append(e[0])
        self.neighbors.get(e[0]).append(e[1])
        connected.append(e[1])
        self.neighbors.get(e[1]).append(e[0])
        edges.append(e)
        for v in vars:
            if v not in connected:
                c_index = random.randint(0, len(connected)-1)
                u = connected[c_index]
                edges.append([v,u])
                connected.append(v)
                self.neighbors.get(v).append(u)
                self.neighbors.get(u).append(v)
        
   
    def _createVdata(self,vars):
        todo = copy.deepcopy(vars)
        done = []
        #for i in range(100):
        while len(todo)!=0:
            index = random.randint(0, len(todo)-1)
            v = todo[index]
            parents = list(set(done) & set(self.neighbors[v]))
            child = list(set(self.neighbors[v]).difference(parents))
            if len(child)<=1:
                node = Node(v)
                node.setParents(parents)
                node.setChild(child)
                node.setRandConds()
                todo.remove(v)
                done.append(v)
                self.V.append(v)
                self.Vdata.append(node)
                if parents:
                    for p in parents:
                        self.E.append([p,v])
    
    def printNodes(self):
        for v in self.Vdata:
            print v.name
            print v.conds
            
    def _vertexStream(self):
        return '\t"V": {0}'.format(self.V).replace("'",'"')
    
    def _edgeStream(self):
        return '\t"E": {0}'.format(self.E).replace("'",'"').replace("],","],\n\t\t")
            
    def _nodeStream(self):
        NUMEOUTCOMES = 2 #Binary ONLY
        vnodes = []
        for i,v in enumerate(self.Vdata):
            order = '"ord":{0}'.format(i)
            numoutcomes = '"numoutcomes": {0}'.format(NUMEOUTCOMES)
            outcome = '"vals": ["Neg_{0}", "Pos_{0}"]'.format(v.name)
            if not v.parents:
                parents = '"parents": null'
                cprob = '"cprob":{0}'.format(v.conds.get("No_Parents"))
            else:
                parents = '"parents": '+str(v.parents).replace("'",'"')
                combs = []
                for key in v.conds.keys():
                    key_list =list(key)
                    comb_list = []
                    for j,b in enumerate(key_list):
                        if b == '0':
                            comb_list.append("'Neg_{0}'".format(v.parents[j]))
                        else:
                            comb_list.append("'Pos_{0}'".format(v.parents[j]))
                    comb_name = ', '.join(comb_list)
                    combs.append('"[{0}]":{1}'.format(comb_name,v.conds.get(key)))
                cprob = '"cprob":{{\n\t\t\t\t{0}\n\t\t\t\t}}'.format(',\n\t\t\t\t'.join(combs))
                
            if not v.child:
                children = '"children": null'
            else:
                children = '"children": '+str(v.child).replace("'",'"')
            
            components = [order, numoutcomes, outcome, parents, children, cprob]
            vnodes.append('"{0}":{{\n\t\t\t{1}\n\t\t\t}}'.format(v.name, ",\n\t\t\t".join(components)))
        vdata = '\t"Vdata":{{\n\t\t{0}\n\t\t}}'.format(',\n\t\t'.join(vnodes))
        return vdata
            
    def stream(self):
        vertex = self._vertexStream()
        edge = self._edgeStream()
        node = self._nodeStream()
        components = [vertex,edge,node]
        stream = '{{\n{0}\n}}'.format(',\n'.join(components))
        return stream
    
    def writeStream(self,path):
        with open(path, "w") as text_file:
            text_file.write(self.stream())
        print "Done!"
bn = BayesNet(100)
print bn.stream()
bn.writeStream('data/bn/new_bn.txt')<jupyter_output>Done!
{'fraction_non_alphanumeric': 0.1220492214967353, 'fraction_numerical': 0.008663987945755902, 'mean_word_length': 2.2764294529000413, 'pattern_counts': {'":': 14, '<': 19, '<?xml version=': 0, '>': 18, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '319962', 'license': 'MIT', 'n_tokens_mistral': 2455, 'n_tokens_neox': 2360, 'n_words': 579, 'path': 'Bayesian_Network_Generator.ipynb', 'repo_name': 'wuga214/TOOLBOX-Random-Bayes-Net-Generator', 'size': '7976'}