Comparing BNs
![]() | ![]() |
def dict2html(di1, di2=None): res = "<br/>".join([f"<b>{k:15}</b>:{v}" for k, v in di1.items()]) if di2 is not None: res += "<br/><br/>" res += "<br/>".join([f"<b>{k:15}</b>:{v}" for k, v in di2.items()]) return resimport pyagrum as gumimport pyagrum.lib.notebook as gnbimport pyagrum.lib.bn_vs_bn as gcmHow to compare two BNs
Section titled “How to compare two BNs”PyAgrum allows you to compare BNs in several ways. This notebook show you some of them:
- a graphical diff between the 2 BNs
- some scores form recal and precision
- distance measures (for more, see notebook
26-klForBNsfor more)
Between two different structures
Section titled “Between two different structures”The graphical diff propose to show the different possible structural differences from two structures with the same nodes in the layout of the first BN (the reference of the comparison).
bn1 = gum.fastBN("A->B->C->D->E<-A->F")bn2 = gum.fastBN("A->B<-C->D->E<-A;F->E")gnb.showBNDiff(bn1, bn2)The meaning of the diffent style for the arcs are :
import pyagrum.lib.bn_vs_bn as bnvsbn
bnvsbn.graphDiffLegend()cmp = gcm.GraphicalBNComparator(bn1, bn2)kl = gum.ExactBNdistance(bn1, bn2) # bruteForce is possible car the BNs are smallgnb.sideBySide( bn1, bn2, gnb.getBNDiff(bn1, bn2), dict2html(cmp.scores(), cmp.hamming()), cmp.equivalentBNs(), dict2html(kl.compute()), captions=["bn1", "bn2", "graphical diff", "Scores", "equivalent ?", "distances"], valign="bottom",)The logic for the arcs of the graphical diff is the following. When comparaing bn1 with bn2 (in that order) :
- full black line: the arc is common for both
- full red line: the arc is common but inverted in bn2
- dotted black line: the arc is added in bn2
- dotted red line: the arc is removed in bn2
For the scores :
- precision and recall are computed considering BN1 as the reference
- is the weighted average of Precision and Recall.
- represents the euclidian distance to the ideal(precision=1,recall=1)
EquivalentBN return “OK” if equivalent or a reason for non equivalence
Finally, BruteForceKL compute in the same time several distances : I-projection, M-projection, Hellinger and Bhattacharya. For more complex BNs, there exists a GibbsKL to approximate those distances. Of course, the computation are much slower.
Same structure, different parameters
Section titled “Same structure, different parameters”bn1 = gum.fastBN("A->B->C->D->E<-A->F")bn2 = gum.fastBN("A->B->C->D->E<-A->F")cmp = gcm.GraphicalBNComparator(bn1, bn2)kl = gum.ExactBNdistance(bn1, bn2) # bruteForce is possible car the BNs are smallgnb.sideBySide( bn1, bn2, gnb.getBNDiff(bn1, bn2), dict2html(cmp.scores(), cmp.hamming()), cmp.equivalentBNs(), dict2html(kl.compute()), captions=["bn1", "bn2", "graphical diff", "Scores", "equivalent ?", "distances"], valign="bottom",)identical BNs
Section titled “identical BNs”bn1 = gum.fastBN("A->B->C->D->E<-A->F")bn2 = bn1cmp = gcm.GraphicalBNComparator(bn1, bn2)kl = gum.ExactBNdistance(bn1, bn2) # bruteForce is possible car the BNs are smallgnb.sideBySide( bn1, bn2, gnb.getBNDiff(bn1, bn2), dict2html(cmp.scores(), cmp.hamming()), cmp.equivalentBNs(), dict2html(kl.compute()), captions=["bn1", "bn2", "graphical diff", "Scores", "equivalent ?", "distances"], valign="bottom",)In the notebook Learning_DirichletPriorAndWeightedDatabase, you can find an interresting discussion on how can change those scores and distance.
