Smoking, Cancer and causality

Creative Commons License

aGrUM

interactive online version

This notebook follows the famous example from Causality (Pearl, 2009).

A correlation has been observed between Smoking and Cancer, represented by this Bayesian network :

In [1]:
from IPython.display import display, Math, Latex,HTML

import pyAgrum as gum
import pyAgrum.lib.notebook as gnb
import pyAgrum.causal as csl
import pyAgrum.causal.notebook as cslnb



obs1 = gum.fastBN("Smoking->Cancer")

obs1.cpt("Smoking")[:]=[0.6,0.4]
obs1.cpt("Cancer")[{"Smoking":0}]=[0.9,0.1]
obs1.cpt("Cancer")[{"Smoking":1}]=[0.7,0.3]

gnb.flow.row(obs1,obs1.cpt("Smoking")*obs1.cpt("Cancer"),obs1.cpt("Smoking"),obs1.cpt("Cancer"),
               captions=["the BN","the joint distribution","the marginal for $smoking$","the CPT for $cancer$"])

G Smoking Smoking Cancer Cancer Smoking->Cancer
the BN
Smoking
Cancer
0
1
0
0.54000.2800
1
0.06000.1200

the joint distribution
Smoking
0
1
0.60000.4000

the marginal for $smoking$
Cancer
Smoking
0
1
0
0.90000.1000
1
0.70000.3000

the CPT for $cancer$

Direct causality between Smoking and Cancer

The very strong observed correlation between smoking and lung cancer suggests a causal relationship as the Surgeon General asserts in 1964, then, the proposed model is as follows :

In [2]:
# the Bayesian network is causal
modele1=csl.CausalModel(obs1)

cslnb.showCausalImpact(modele1,"Cancer", "Smoking", values={"Smoking":1})

G Smoking Smoking Cancer Cancer Smoking->Cancer
Causal Model
$$\begin{equation*}P( Cancer \mid \hookrightarrow\mkern-6.5muSmoking) = P\left(Cancer\mid Smoking\right)\end{equation*}$$
Explanation : Do-calculus computations
Cancer
0
1
0.70000.3000

Impact

Latent confounder between Smoking and Cancer

This model is highly contested by the tobacco industry which answers by proposing a different model in which Smoking and Cancer are simultaneously provoked by a common factor, the Genotype (or other latent variable) :

In [3]:
# a latent varible exists between Smoking and Cancer in the causal model
modele2 = csl.CausalModel(obs1, [("Genotype", ["Smoking","Cancer"])])

cslnb.showCausalImpact(modele2, "Cancer", "Smoking",values={"Smoking":1})

G Genotype Smoking Smoking Genotype->Smoking Cancer Cancer Genotype->Cancer
Causal Model
$$\begin{equation*}P( Cancer \mid \hookrightarrow\mkern-6.5muSmoking) = P\left(Cancer\right)\end{equation*}$$
Explanation : No causal effect of X on Y, because they are d-separated (conditioning on the observed variables if any).
Cancer
0
1
0.82000.1800

Impact
In [4]:
# just check P(Cancer) in the bn `obs1`
(obs1.cpt("Smoking")*obs1.cpt("Cancer")).margSumIn(["Cancer"])

Out[4]:
Cancer
0
1
0.82000.1800

Confounder and direct causality

In a diplomatic effort, both parts agree that there must be some truth in both models :

In [5]:
# a latent variable exists between Smoking and Cancer but the direct causal relation exists also
modele3 = csl.CausalModel(obs1, [("Genotype", ["Smoking","Cancer"])], True)

cslnb.showCausalImpact(modele3, "Cancer", "Smoking",values={"Smoking":1})

G Genotype Smoking Smoking Genotype->Smoking Cancer Cancer Genotype->Cancer Smoking->Cancer
Causal Model
Hedge Error: G={'Smoking', 'Cancer'}, G[S]={'Cancer'}
Impossible
No result
Impact

Smoking’s causal effect on Cancer becomes uncomputable in such a model because we can’t distinguish both causes’ impact from the observations.

A intermediary observed variable

We introduce an auxilary factor between Smoking and Cancer, tobacco causes cancer because of the tar deposits in the lungs.

In [6]:
obs2 = gum.fastBN("Smoking->Tar->Cancer;Smoking->Cancer")

obs2.cpt("Smoking")[:] = [0.6, 0.4]
obs2.cpt("Tar")[{"Smoking": 0}] = [0.9, 0.1]
obs2.cpt("Tar")[{"Smoking": 1}] = [0.7, 0.3]
obs2.cpt("Cancer")[{"Tar": 0, "Smoking": 0}] = [0.9, 0.1]
obs2.cpt("Cancer")[{"Tar": 1, "Smoking": 0}] = [0.8, 0.2]
obs2.cpt("Cancer")[{"Tar": 0, "Smoking": 1}] = [0.7, 0.3]
obs2.cpt("Cancer")[{"Tar": 1, "Smoking": 1}] = [0.6, 0.4]

gnb.flow.row(obs2,obs2.cpt("Smoking"),obs2.cpt("Tar"),obs2.cpt("Cancer"),
               captions=["","$P(Smoking)$","$P(Tar|Smoking)$","$P(Cancer|Tar,Smoking)$"])

G Tar Tar Cancer Cancer Tar->Cancer Smoking Smoking Smoking->Tar Smoking->Cancer
Smoking
0
1
0.60000.4000

$P(Smoking)$
Tar
Smoking
0
1
0
0.90000.1000
1
0.70000.3000

$P(Tar|Smoking)$
Cancer
Smoking
Tar
0
1
0
0
0.90000.1000
1
0.80000.2000
1
0
0.70000.3000
1
0.60000.4000

$P(Cancer|Tar,Smoking)$
In [7]:
modele4 = csl.CausalModel(obs2, [("Genotype", ["Smoking","Cancer"])])
print(modele4)
<pyAgrum.causal._CausalModel.CausalModel object at 0x116968590>
In [8]:
cslnb.showCausalModel(modele4)
../_images/notebooks_61-Causality_Tobacco_18_0.svg
In [9]:
cslnb.showCausalImpact(modele4, "Cancer", "Smoking",values={"Smoking":1})
G Genotype Smoking Smoking Genotype->Smoking Cancer Cancer Genotype->Cancer Tar Tar Smoking->Tar Tar->Cancer
Causal Model
$$\begin{equation*}P( Cancer \mid \hookrightarrow\mkern-6.5muSmoking) = \sum_{Tar}{P\left(Tar\mid Smoking\right) \cdot \left(\sum_{Smoking'}{P\left(Cancer\mid Smoking',Tar\right) \cdot P\left(Smoking'\right)}\right)}\end{equation*}$$
Explanation : frontdoor ['Tar'] found.
Cancer
0
1
0.79000.2100

Impact

In this model, we are, again, able to calculate the causal impact of Smoking on Cancer thanks to the verification of the Frontdoor criterion by the Tar relatively to the couple (Smoking, Cancer)

In [10]:
# just check P(Cancer|do(smoking)) in the bn `obs2`
((obs2.cpt("Cancer")*obs2.cpt("Smoking")).margSumOut(["Smoking"])*obs2.cpt("Tar")).margSumOut(['Tar']).putFirst("Cancer")

Out[10]:
Cancer
Smoking
0
1
0
0.81000.1900
1
0.79000.2100

Other causal impacts for this last model

In [11]:
cslnb.showCausalImpact(modele4, "Smoking", doing="Cancer",knowing={"Tar"}, values={"Cancer":1,"Tar":1})

G Genotype Smoking Smoking Genotype->Smoking Cancer Cancer Genotype->Cancer Tar Tar Smoking->Tar Tar->Cancer
Causal Model
$$\begin{equation*}P( Smoking \mid \hookrightarrow\mkern-6.5muCancer, Tar) = P\left(Smoking\mid Tar\right)\end{equation*}$$
Explanation : No causal effect of X on Y, because they are d-separated (conditioning on the observed variables if any).
Smoking
0
1
0.33330.6667

Impact
In [12]:
cslnb.showCausalImpact(modele4, "Smoking", doing="Cancer",values={"Cancer":1})

G Genotype Smoking Smoking Genotype->Smoking Cancer Cancer Genotype->Cancer Tar Tar Smoking->Tar Tar->Cancer
Causal Model
$$\begin{equation*}P( Smoking \mid \hookrightarrow\mkern-6.5muCancer) = P\left(Smoking\right)\end{equation*}$$
Explanation : Do-calculus computations
Smoking
0
1
0.60000.4000

Impact
In [13]:
cslnb.showCausalImpact(modele4, "Smoking", doing={"Cancer","Tar"},values={"Cancer":1,"Tar":1})

G Genotype Smoking Smoking Genotype->Smoking Cancer Cancer Genotype->Cancer Tar Tar Smoking->Tar Tar->Cancer
Causal Model
$$\begin{equation*}P( Smoking \mid \hookrightarrow\mkern-6.5muTar,\hookrightarrow\mkern-6.5muCancer) = P\left(Smoking\right)\end{equation*}$$
Explanation : Do-calculus computations
Smoking
0
1
0.60000.4000

Impact
In [14]:
cslnb.showCausalImpact(modele4, "Tar", doing={"Cancer","Smoking"},values={"Cancer":1,"Smoking":1})

G Genotype Smoking Smoking Genotype->Smoking Cancer Cancer Genotype->Cancer Tar Tar Smoking->Tar Tar->Cancer
Causal Model
$$\begin{equation*}P( Tar \mid \hookrightarrow\mkern-6.5muSmoking,\hookrightarrow\mkern-6.5muCancer) = P\left(Tar\mid Smoking\right)\end{equation*}$$
Explanation : Do-calculus computations
Tar
0
1
0.70000.3000

Impact

Four causal models for the same observational data

In [15]:
gnb.flow.row(modele1,modele2,modele3,modele4)

G Smoking Smoking Cancer Cancer Smoking->Cancer
G Genotype Smoking Smoking Genotype->Smoking Cancer Cancer Genotype->Cancer
G Genotype Smoking Smoking Genotype->Smoking Cancer Cancer Genotype->Cancer Smoking->Cancer
G Genotype Smoking Smoking Genotype->Smoking Cancer Cancer Genotype->Cancer Tar Tar Smoking->Tar Tar->Cancer
In [ ]: