Walking through the bayes theorm to update our belief systematically.
Tags: datascience, math, bayes, programming
Published: 2023-05-28 17:29:20

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2euhwq3nm1fo27np5lvk.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbxpocq77xp8uax1zaql.png)

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:

``` go
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)
}
```
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ialwexb7z2i5ozurtc1m.png)

Here is the complete code along with the test cases:

```go
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(" ")

}

```

```go
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)
	}
}

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ieecd3ld32eid6k907ya.PNG)

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](https://en.wikipedia.org/wiki/Bayes%27_theorem)

[Zenius](https://www.zenius.net/blog/teorema-bayes)

[StatQuest](https://www.youtube.com/watch?v=9wCnvr7Xw4E)