DEV Community

Cover image for Walking through the bayes theorm to update our belief systematically.
Rama Reksotinoyo
Rama Reksotinoyo

Posted on

Walking through the bayes theorm to update our belief systematically.

I have heard about a quote from ancient Greek that goes, and this quote bellow is related to Bayes' theorem.

"Always leave room for uncertainty so that we remain open to new things and survive."

Bayes' theorem is a statistical method used to calculate the uncertainty or probability of an event based on past assumptions that may be related to the event. Inspired by this, I decided to delve deeper (with my limited brain capacity, of course) into Bayes' theorem, which I tried to implement in program code.

I attempted to implement the probability of someone, let's call them X, having HIV and actually being HIV positive. I wanted to determine the probability that X truly has HIV.

Here is the formula for Bayes' theorem:

Image description

With my zero of medical knowledge, I assumed that out of a population of 5000 people who took an HIV test, only 3% of the population actually had HIV, considering that I rarely come across people with HIV in my current environment.

After reading some papers and hearing opinions from HIV specialists and HIV researchers, I found that if X were to take the test now, the probability of them having HIV would be 95%. This can be referred to as sensitivity. If X does not have HIV, the probability of them truly not having HIV is 98%. This can be referred to as specificity.

Therefore:
P(HIV) = prior = 0.3
P(diagnosed|HIV) = likelihood = 0.95
P(diagnosed) = evidence
P(HIV|diagnosed) = posterior
P(not HIV|not diagnosed) = 0.98

Thus, the confusion matrix table is as follows, where the horizontal axis represents the actual values and the vertical axis represents the predicted values.

Please note that the translation provided may not precisely match the terminology used in statistical literature, but it conveys the general meaning.

Confusion Matrix:
Image description

Since the evidence is unknown in this case, I am trying to calculate it using the equation from the law of total probability, which is P(B) = Σ[P(B|Aᵢ)P(Aᵢ)]. Here, I am implementing it using the Go programming language:

const (
    PDiagnosedGivenHIV      = 0.95 // P(D|S)
    PNotDiagnosedGivenNoHIV = 0.98 // P(-D|-S)
    PDiagnosedGivenNoHIV    = 0.02 // P(D|¬S)
    PNotDetectedGivenSpam   = 0.05 // P(-D|S)
)

func TotalProbability(prior *float64) float64 {
    // using law of total probability.
    // P(D) = P(D|S)P(S) + P(D|¬S)P(¬S)
    PNoHIV := 1 - *prior
    return (PDiagnosedGivenHIV * *prior) + (PDiagnosedGivenNoHIV * PNoHIV)
}
Enter fullscreen mode Exit fullscreen mode

With the obtained evidence of 0.0479, I just need to substitute the above evidence with the known data into the following equation.

Image description

Here is the complete code along with the test cases:

package main

import "fmt"

type Probability struct {
    PriorProb       float64
    ConditionalProb float64
    EvidenceProb    float64
}

func (p *Probability) CalculatePosteriorProb() float64 {
    // Menghitung posterior probability menggunakan rumus Bayes
    posteriorProb := (p.ConditionalProb * p.PriorProb) / p.EvidenceProb
    return posteriorProb
}

const (
    PDiagnosedGivenHIV      = 0.95 // P(D|S)
    PNotDiagnosedGivenNoHIV = 0.98 // P(-D|-S)
    PDiagnosedGivenNoHIV    = 0.02 // P(D|¬S)
    PNotDetectedGivenSpam   = 0.05 // P(-D|S)
)

func TotalProbability(prior *float64) float64 {
    // using law of total probability.
    // P(D) = P(D|S)P(S) + P(D|¬S)P(¬S)
    PNoHIV := 1 - *prior
    return (PDiagnosedGivenHIV * *prior) + (PDiagnosedGivenNoHIV * PNoHIV)
}

func main() {
    prior := 0.03
    evidence := TotalProbability(&prior)

    prob := Probability{
        PriorProb:       prior,    // Probabilitas prior
        ConditionalProb: 0.95,     // Probabilitas kondisional
        EvidenceProb:    evidence, // Probabilitas evidence
    }

    // Menghitung posterior probability menggunakan Bayes' Rule
    posteriorProb := prob.CalculatePosteriorProb()

    fmt.Printf("Posterior Probability: %.2f\n", posteriorProb)
    fmt.Println(" ")

}

Enter fullscreen mode Exit fullscreen mode
package main

import (
    "math"
    "testing"
)

const epsilon = 0.00000001 // Toleransi kesalahan

func TestCalculatePosteriorProb(t *testing.T) {
    prob := Probability{
        PriorProb:       0.1,  // Probabilitas prior
        ConditionalProb: 0.75, // Probabilitas kondisional
        EvidenceProb:    0.1,  // Probabilitas evidence
    }

    expectedPosteriorProb := 0.75

    actualPosteriorProb := prob.CalculatePosteriorProb()

    if math.Abs(actualPosteriorProb-expectedPosteriorProb) > epsilon {
        t.Errorf("Wrong answer! it should be %.8f", expectedPosteriorProb)
    }
}

func TestTotalProbability(t *testing.T) {

    const (
        PDetectedGivenSpam       = 0.95 // P(D|S)
        PNotDetectedGivenNonSpam = 0.98 // P(-D|-S)
        PDetectedGivenNonSpam    = 0.02 // P(D|¬S)
        PNotDetectedGivenSpam    = 0.05 // P(-D|S)
    )

    e := 0.0001
    prior := 0.2

    expectedTotalProb := 0.2060
    actualTotalProb := TotalProbability(&prior)

    if math.Abs(actualTotalProb-expectedTotalProb) > e {
        t.Errorf("Wrong answer! It should be %.4f but %.4f", expectedTotalProb, actualTotalProb)
    }
}

Enter fullscreen mode Exit fullscreen mode

Image description

In the next articel , I will talk about how to update our level of confidence or prior, which will demonstrate that the likelihood of someone being affected by HIV is directly proportional to the magnitude of our prior or initial assumption. Testing and implementation of the narrative "to update our belief systematically" will be in the next section. See you soon.

Reference:
Wikipedia

Zenius

StatQuest

Top comments (0)