Let's consider a dumb spam filter BN (see figure below) for which I've already calculated the a posteriori parameter distributions (see normalized table values).

I want to predict if next email without the "book" word (Y1=F) and with the "free" word (Y2=T) is spam (X=T) or not spam (X=F).

I guess the question can be written as P(X=T | Y1=F, Y2=T) ... you may confirm ...

Here Y1 and Y2 are independant, I've been playing around with Bayes and Chain rules to get the right formulae for computation, without success.

P(X|Y1,Y2) = P(Y1,Y2|X) P(X) / P(Y1, Y2)

           = P(Y1|X) P(Y2|Y1,X) P(X) / P(Y1|Y2)P(Y2)

           = P(Y1|X) P(Y2|X) P(X) / P(Y1)P(Y2)

The R script below says that this probability is 0.3034. Is this P(X=T | Y1=F, Y2=T) even though the function parameter "type=marginal" is used ?.

Note: displayed conditional probability tables are not normalized (sum is not 1).


X <- cptable(~ isSpam, values=c(0.33, 0.67),
             levels=c("true", "false"))

Y1 <- cptable(~ hasBook|isSpam, 
              values=c(0.335, 0.165, 0.25, 0.25),
              levels=c("true", "false"))

Y2 <- cptable(~ hasFree|isSpam, 
              values=c(0.335, 0.165, 0.25, 0.25),
              levels=c("true", "false"))

plist <- compileCPT(list(X, Y1, Y2))

pn <- grain(plist)

# true false 
# 0.33  0.67 

#       isSpam
#hasBook true false
#  true  0.67   0.5
#  false 0.33   0.5

#hasFree true false
#  true  0.67   0.5
#  false 0.33   0.5

pn1 <- setEvidence(pn, evidence = list(hasBook = "false", hasFree = "true"))

# type = "marginal": marginal distribution for each node in nodes;
(marginal.isSpam <- querygrain(pn1, nodes = "isSpam", type = "marginal"))
# isSpam
# true     false 
# 0.3034271 0.6965729 

enter image description here


1 Answer 1


The joint distribution of the network is given by

$$ P(X) P(Y1 \mid X) P(Y2 \mid X)$$

We want

$$ P(X \mid Y1=false, Y2=true) $$

This is equal to

$$ \frac{P(X) P(Y1 = false \mid X) P(Y2 = true \mid X)} {P(Y1 = false, Y2=true)} $$

We actually do not need to calculate the denominator in the expression above, as we can normalise the values that are returned in the numerator.

So now we can just plug in the values from your CPT's in to the numerator

For P(X = true): $$P(X=true) P(Y1 = false \mid X=true) P(Y2 = true \mid X=true) $$

  0.33* 0.33* 0.67

And for For P(X = false): $$ P(X=false) P(Y1 = false \mid X=false) P(Y2 = true \mid X=false) $$

0.67* 0.5* 0.5

We convert these to actual probabilities by normalising

So for P(X=true)

0.072963 / (0.072963 + 0.1675) 

and similarly for P(x=false).

So these agree with the results from your gRain query


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.