From af7792ee430fc3e5b2a98c727c913d6301fdd744 Mon Sep 17 00:00:00 2001 From: 68d6b36d6dfa73b2f7f25db9fb7770c1 <68d6b36d6dfa73b2f7f25db9fb7770c1@app-learninglab.inria.fr> Date: Thu, 14 Oct 2021 08:10:52 +0000 Subject: [PATCH] Upload .org file --- .../document_computationnel.org | 642 ++++++++++++++++++ 1 file changed, 642 insertions(+) create mode 100644 module3/Paradoxe de Simpson/document_computationnel.org diff --git a/module3/Paradoxe de Simpson/document_computationnel.org b/module3/Paradoxe de Simpson/document_computationnel.org new file mode 100644 index 0000000..dac1afd --- /dev/null +++ b/module3/Paradoxe de Simpson/document_computationnel.org @@ -0,0 +1,642 @@ +#+TITLE: Etude de la nocivité du tabac chez les femmes +#+AUTHOR: Victor +#+EMAIL:vtrltz@e.email + +* Préface :noexport: +** Propriétés du document +#+LANGUAGE: French +#+PROPERTY: header-args :session :exports both +#+EXPORT_SELECT_TAGS: export +#+EXPORT_EXCLUDE_TAGS: noexport +#+bibliography: references.bib +#+cite_export: basic author author-year +** Paramètres d'export +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +** Prérequis à l'utilisation de ce document +Afin d'exécuter le document computationnel suivant, il convient de +disposer des logiciels suivants : + +*** Emacs avec org-mode +Afin d'exécuter les fragments de codes de ce document computationnel +il convient d'utiliser une version d'Emacs intégrant Org-mode. + +*** Python = 3 + +#+BEGIN_SRC python :results output :exports both +from sys import version_info +if version_info.major < 3: + print("Veuillez utiliser Python 3.") +#+END_SRC + +#+RESULTS: + +#+BEGIN_SRC emacs-lisp :results output :exports both +(unless (featurep 'ob-python) + (print "Veuillez activer python dans org-babel (org-babel-do-languages) !")) +#+END_SRC + +#+RESULTS: + +* Préambule +** Contexte de l'exercice +Dans le cadre du [[https://www.fun-mooc.fr/fr/cours/recherche-reproductible-principes-methodologiques-pour-une-science-transparente/][/MOOC/ de l'INRIA sur la recherche reproductible]], je +réalise un travail pratique évalué par les pairs. Ce travail pratique +intervient au cours du module 3. Le sujet choisi est le numéro 6, +intitulé : /Autour du Paradoxe de Simpson/. + +** Origine des données +Nous utilisons les données mises à disposition pour l'exercice par +l'équipe pédagogique du MOOC. Ces données sont un extrait de celles +d'études de l'incidence des pathologies de la thyroïde au sein de la +population britannique. Furent exclus du jeu de donnée +complet : +- les hommes (n = 1285) ; +- les femmes ayant arrêté de fumer (n = 162) +- les femmes dont les données n'étaient pas disponibles (n = 18). + +URL des données : +#+NAME: data-url +https://gitlab.inria.fr/learninglab/mooc-rr/mooc-rr-ressources/-/raw/master/module3/Practical_session/Subject6_smoking.csv?inline=false + +Nous téléchargeons le jeu de donnée de l'exercice au format =.csv=. Dans +ce jeu de données, chaque ligne correspond aux données d'une +participante lors des études originales. Nous disposons des +informations suivantes : + +| Nom de colonne | Description de la variable dépendante | +|----------------+--------------------------------------------------------------------------------| +| Smoker | Si la personne fume ou non. | +| Status | Si la personne est vivante ou décédée. | +| Age | L'âge de la personne si elle est vivante, l'âge à sa mort si elle est décédée. | + +** Bibliothèques et fonctions utilisées +Pour la suite des manipulations de données, nous faisons l'usage de +plusieurs fonctions disponibles dans des bibliothèques Python. + +#+begin_src python :results output :exports code +from os.path import exists +from pandas import read_csv +from matplotlib import pyplot as plt, rc +from seaborn import histplot, kdeplot, lmplot +from urllib import request +from numbers import Real +from numpy import nan, arange +#+end_src + +#+RESULTS: + +** Paramètres communs des graphiques +Nous souhaitons que les graphiques soient réalisés avec TeX. + +#+begin_src python :results output :exports code +# Draw in LaTeX +rc('font', **{'family': 'serif', 'serif': ['Courier New']}) +plt.rcParams['text.usetex'] = True +#+end_src + +#+RESULTS: + +** Import des données +Dans le cas où une copie locale n'est pas présente, nous téléchargeons +le jeu de données complet depuis son adresse de dépôt. + +#+begin_src python :results output :exports both :var data_url=data-url +data_file = "Subject6_smoking.csv" + +if not exists(data_file): + request.urlretrieve(data_url, data_file) + print('Data set downloaded. \n') + +data = read_csv(filepath_or_buffer='Subject6_smoking.csv') + +data.info(verbose=True) +print('\n', data.head()) +#+end_src + +#+RESULTS: +#+begin_example + +RangeIndex: 1314 entries, 0 to 1313 +Data columns (total 3 columns): +Smoker 1314 non-null object +Status 1314 non-null object +Age 1314 non-null float64 +dtypes: float64(1), object(2) +memory usage: 30.9+ KB + + Smoker Status Age +0 Yes Alive 21.0 +1 Yes Alive 19.3 +2 No Dead 57.5 +3 No Alive 47.1 +4 Yes Alive 81.4 +#+end_example + +** Vérifications automatiques des données +Vérifions le jeu de données : +- nous ne devons avoir que les valeurs /Yes/ et /No/ dans la colonne + /Smoker/ ; +- seules les catégories /ALive/ et /Dead/ doivent être présentent dans la + colonne /Status/ ; +- l'âge doit être un réel entre 0 et 123 (le record de longévité + attesté étant de moins de 123 ans). + +En cas de valeur incorrecte, nous remplaçons ladite valeur par =nan= +(/Not a number/). + +#+begin_src python :results output :exports code +for row in data.iterrows(): + if row[1][0] != 'Yes' and row[1][0] != 'No': + print(f"Uncorrect value in 'Smoker' column: {row[1][0]} (index = {row[0]})") + data['Smoker'].iat[row[0]] = nan + if row[1][1] != 'Alive' and row[1][1] != 'Dead': + print(f"Uncorrect value in 'Status' column: {row[1][1]} (index = {row[0]})") + data['Status'].iat[row[0]] = nan + if not isinstance(row[1][2], Real) and not 0 <= row[1][2] <= 123: + print(f"Uncorrect value in 'Age' column: {row[1][2]} (index = {row[0]})") + data['Age'].iat[row[0]] = nan +#+end_src + +#+RESULTS: + +** Visualisations des données brutes +*** Distribution des âges des participantes +Nous souhaitons visualiser les distributions des âges selon les +habitudes de tabagisme. + +#+begin_src python :results output file :exports none +fig, ax = plt.subplots() +kdeplot(data=data, x=data['Age'], hue=data['Smoker']) +plt.savefig("group_ages_kde.png") +plt.close() +#+end_src + +#+RESULTS: +[[file:]] + +#+CAPTION: Distribution des âges des participantes selon les habitudes de tabagisme (estimation par noyau) +#+NAME: fig:age-kde +[[./group_ages_kde.png]] + +Constatons que les distributions en âge des participantes selon les +habitudes de tabagisme ne correspondent pas : les femmes de plus de 60 +ans sont davantage présentes dans le groupe des non-fumeuses. + +* Analyses de la nocivité du tabagisme chez les femmes +Dans les analyses suivantes, nous souhaitons évaluer la nocivité du +tabagisme chez les femmes. Dans le cadre de notre exercice, nous +utilisons trois approches différentes. + +Notre hypothèse est que le tabac est nocif chez les femmes. + +** Approche 1 | Taux de mortalité des fumeuses et non-fumeuses +Nous cherchons à déterminer les taux de mortalité des deux groupes de +notre étude. Nous souhaitons associer ces taux de mortalité à des +intervalles de confiance à 95%. + +*** Calcul des paramètres +Commençons par séparer les deux groupes. Le nombre de participantes +mortes dans un groupe ramené à l'effectif total du groupe nous donne +le taux de mortalité dudit groupe. + +#+begin_src python :results output :exports code +rounding = 1 + +smokers = data[(data['Smoker'] == 'Yes')] +nonsmokers = data[(data['Smoker'] == 'No')] + +dead_smokers = smokers[(smokers['Status'] == 'Dead')] +dead_nonsmokers = nonsmokers[(nonsmokers['Status'] == 'Dead')] + +smokers_death_rate = round(dead_smokers.shape[0] / smokers.shape[0] * 100, rounding) +nonsmokers_death_rate = round(dead_nonsmokers.shape[0] / nonsmokers.shape[0] * 100, rounding) +#+end_src + +#+RESULTS: + +Nous déterminons l'intervalle de confiance à 95% avec la formule +suivante : + +#+begin_latex +$\text{IC}_{95} = \frac{100}{n} d \pm 1.96 \sqrt{d}$ +#+end_latex + +Où =n= correspond à l'effectif du groupe considéré et =d= au nombre +d'individus décédés au sein du même groupe. Voici le code que nous +avons utilisé pour réaliser le calcul des intervalles de confiance : + +#+begin_src python :results output :exports code +def death_rate_ci95(sample_size: int, + deads: int, + per_people: int = 100) -> tuple: + """Compute the 95% confidence interval upper and lower limits of a mortality rate in a sample. + + :param sample_size: number of people in the sample. + :param deads: number of deads people in the sample. + :param per_people: standardisation number: deads for per_people people. + """ + from math import sqrt + + + upper = per_people / sample_size * (deads + 1.96 * sqrt(deads)) + lower = per_people / sample_size * (deads - 1.96 * sqrt(deads)) + + return lower, upper + +smokers_dr_95ic = death_rate_ci95(smokers.shape[0], dead_smokers.shape[0]) +nonsmokers_dr_95ic = death_rate_ci95(nonsmokers.shape[0], dead_nonsmokers.shape[0]) +#+end_src + +#+RESULTS: + +*** Résultats +#+begin_src python :results output table raw :exports results +print(f"|Tabagisme|Effectif total|Individus décédés|Taux de mortalité (%)|IC95%|\n" + f"|-+-+-+-+-|\n" + f"|Fumeuses|{smokers.shape[0]}|{dead_smokers.shape[0]}|{smokers_death_rate}|[{round(smokers_dr_95ic[0], rounding)};{round(smokers_dr_95ic[1], rounding)}]|\n" + f"|Non fumeuses|{nonsmokers.shape[0]}|{dead_nonsmokers.shape[0]}|{nonsmokers_death_rate}|[{round(nonsmokers_dr_95ic[0], rounding)};{round(nonsmokers_dr_95ic[1], rounding)}]|") +#+end_src + +#+RESULTS: +| Tabagisme | Effectif total | Individus décédés | Taux de mortalité (%) | IC95% | +|--------------+----------------+-------------------+-----------------------+-------------| +| Fumeuses | 582 | 139 | 23.9 | [19.9;27.9] | +| Non fumeuses | 732 | 230 | 31.4 | [27.4;35.5] | + +#+begin_src python :results output file :exports none +fig, ax = plt.subplots(nrows=1, ncols=2, sharex=True) +histplot(data=data, x='Smoker', hue='Status', + multiple='stack', shrink=0.8, ax=ax[0]) +ax[1].bar(x=[0, 1], + height=[smokers_death_rate, nonsmokers_death_rate], + yerr=[smokers_dr_95ic[1] - smokers_death_rate, nonsmokers_dr_95ic[1] - nonsmokers_death_rate], + color='grey', edgecolor='k', + error_kw=dict(lolims=True)) + +# In order to modify the default lolims error bars shape +for ch in ax[1].get_children(): + if str(ch).startswith('Line2D'): + ch.set_marker('_') + ch.set_markersize(6) + +ax[1].set_ylabel(r'Death rate (\%)') +ax[1].set_xlabel('Smoker') +plt.tight_layout() +plt.savefig("groups_death_rate.png") +#+end_src + +#+RESULTS: +[[file:]] + +#+CAPTION: Effectifs et taux de mortalité parmi les fumeuses et les non fumeuses. +#+NAME: fig:effectifs-mortalite +[[./groups_death_rate.png]] + +Pour le jeu de donnée considéré, le taux de mortalité des fumeuses est +de src_python[:exports results]{smokers_death_rate} {{{results(=23.88=)}}} contre +src_python[:exports results]{nonsmokers_death_rate} {{{results(=31.42=)}}} +pour celui observé chez les non-fumeuses. Ce qui va à l'encontre de +notre hypothèse initiale. Il est possible que l'hétérogénéité +constatée dans la distribution des âges explique ce résultat contre +intuitif. + +** Approche 2 | Taux de mortalité des fumeuses et non-fumeuses selon la classe d'âge +Nous étudions désormais le taux de mortalité selon les habitudes de +tabagisme et selon la classe d'âge. Nous considérons quatre classes : +- [18 ; 34[ +- [34 ; 54[ +- [54 ; 64[ +- [64 ; 123[ + +*** Calcul des paramètres et résultats +Premièrement nous devons séparer le jeu de donnée selon les classes +d'âge. Puis nous procédons de la même manière que précédemment : nous +identifions les effectifs de chaque groupe, le nombre de décès au sein +des sous-groupes et nous calculons le taux de mortalité associé à son +intervalle de confiance à 95%. + +#+begin_src python :results output table raw :exports both +categories = [(18, 34), (34, 54), (54, 64), (64, 123)] + +death_rates = [] # plotting purpose +dr_uncertainties = [] # plotting purpose + +print(f"|Classe d'âge|Tabagisme|Effectif total|Individus décédés|\ + Taux de mortalité (%)|IC95%|\n" + f"|-+-+-+-+-+-|") + +for category in categories: + for smoker in data['Smoker'].unique(): + + alive, dead = nan, nan + + if smoker == 'Yes': + smoke = 'Fumeuses' + else: + smoke = 'Non-fumeuses' + + for status in data['Status'].unique(): + + subset = data[(data['Age'] >= category[0]) + & (data['Age'] < category[1]) + & (data['Smoker'] == smoker) + & (data['Status'] == status)] + + if status == 'Alive': + alive = subset.shape[0] + else: + dead = subset.shape[0] + + death_rate = dead / (alive + dead) * 100 + death_rates.append(death_rate) + + dr_ci95 = death_rate_ci95(alive + dead, dead) + dr_uncertainties.append(dr_ci95[1] - death_rate) + + rounded_dr_ci95 = list(dr_ci95) + rounded_dr_ci95[0] = round(rounded_dr_ci95[0], rounding) + rounded_dr_ci95[1] = round(rounded_dr_ci95[1], rounding) + r_dr_ci95 = tuple(rounded_dr_ci95) + + print(f"|[{category[0]};{category[1]}[|{smoke}|{alive + dead}|\ + {dead}|{round(death_rate, rounding)}|{r_dr_ci95}|") +#+end_src + +#+RESULTS: +| Classe d'âge | Tabagisme | Effectifs total | Individus décédés | Taux de mortalité (%) | IC95% | +|--------------+--------------+-----------------+-------------------+-----------------------+---------------| +| [18;34[ | Fumeuses | 179 | 5 | 2.8 | (0.3, 5.2) | +| [18;34[ | Non fumeuses | 219 | 6 | 2.7 | (0.5, 4.9) | +| [34;54[ | Fumeuses | 239 | 41 | 17.2 | (11.9, 22.4) | +| [34;54[ | Non fumeuses | 199 | 19 | 9.5 | (5.3, 13.8) | +| [54;64[ | Fumeuses | 115 | 51 | 44.3 | (32.2, 56.5) | +| [54;64[ | Non fumeuses | 119 | 39 | 32.8 | (22.5, 43.1) | +| [64;123[ | Fumeuses | 49 | 42 | 85.7 | (59.8, 111.6) | +| [64;123[ | Non fumeuses | 195 | 166 | 85.1 | (72.2, 98.1) | + +#+begin_src python :results output file :exports both +fig, ax = plt.subplots() + +x_pos = arange(len(categories)) +width = 0.35 + +xlabels = list(map(str, categories)) +for x_l, xlabel in enumerate(xlabels): + head, _, tail = xlabel.partition(',') + xlabels[x_l] = '[' + head[1:] + ';' + tail[:-1] + '[' + +plt.bar(x=x_pos - width / 2, + height=death_rates[0:len(death_rates):2], + yerr=dr_uncertainties[0:len(death_rates):2], + label='Smoker', width=width, edgecolor='k', + error_kw=dict(lolims=True)) + +plt.bar(x=x_pos + width / 2, + height=death_rates[1:len(death_rates):2], + yerr=dr_uncertainties[1:len(death_rates):2], + label='Nonsmoker', width=width, edgecolor='k', + error_kw=dict(lolims=True)) + +# In order to modify the default lolims error bars shape +for ch in ax.get_children(): + if str(ch).startswith('Line2D'): + ch.set_marker('_') + ch.set_markersize(6) + +plt.ylabel('Death rate (%)') +plt.xlabel('Age category') +plt.xticks(x_pos) +ax.set_xticklabels(xlabels) +plt.legend() +plt.tight_layout() +plt.savefig("age_categories_death_rate.png") +#+end_src + +#+RESULTS: +[[file:]] + +#+CAPTION: Taux de mortalité et IC95% selon les habitudes de tabagisme et la classe d'âge +#+NAME: fig:mortalite-classe-age +[[./age_categories_death_rate.png]] + +Pour chacune de nos classes d'âge, les résultats indiquent que le taux +de mortalité des fumeuses est supérieur à celui des non-fumeuses ; +soit une interprétation des données en contradiction avec la première +analyse sans prise en compte de l'âge. + +Outre un biais potentiel lié aux distributions des âges hétérogènes, +d'autres biais sont susceptibles d'exister dans les analyses +précédentes : +- un biais lié à la non prise en compte de l'âge dans le calcul des + taux de mortalité ; +- un biais lié aux choix de catégorisation. +En somme au moins trois biais peuvent se combiner dans nos études +précédentes et fausser nos interprétations. + +Enfin, notons que l'âge semble avoir un effet supérieur au tabac sur +le taux de mortalité puisque l'amplitude des différences entre les +classes d'âge est supérieure à celle entre les habitudes de +tabagisme. En somme : le tabac tue, mais vieillir tue davantage. + +** Approche 3 | Probabilité de décès des fumeuses et non-fumeuses selon l'âge +Evitons les deux derniers biais en passant du calcul du taux de +mortalité au calcul de la probabilité de décès selon l'âge et les +habitudes de tabagisme. Pour ce faire nous pouvons utiliser la +régression logistique. + +*** Manipulation des données +Plutôt que de disposer des status =Alive= et =Dead=, nous voulons qu'ils +soient respectivement codés avec =0= et =1=. Nous souhaitons à nouveau +disposer de jeux de données spécifiques à chaque groupe : fumeuses et +non fumeuses. + +#+begin_src python :results output :exports both +deaths = [] + +for status in data['Status']: + if status == 'Alive': + deaths.append(0) + else: + deaths.append(1) + +data['Death'] = deaths + +smokers = data[(data['Smoker'] == 'Yes')] +nonsmokers = data[(data['Smoker'] == 'No')] +print(smokers.head(), '\n', '\n', nonsmokers.head()) +#+end_src + +#+RESULTS: +#+begin_example + Smoker Status Age Death +0 Yes Alive 21.0 0 +1 Yes Alive 19.3 0 +4 Yes Alive 81.4 0 +7 Yes Dead 57.5 1 +8 Yes Alive 24.8 0 + + Smoker Status Age Death +2 No Dead 57.5 1 +3 No Alive 47.1 0 +5 No Alive 36.8 0 +6 No Alive 23.8 0 +11 No Dead 66.0 1 +#+end_example + +*** Régressions logistiques +**** Réglages et code de la modélisation +Pour effectuer la régression logistique, nous utilisons la +bibliothèque =statsmodels=. Nous laissons les paramètres par défaut : le +modèle est le logit, la méthode est celle du maximum de vraisemblance +(/Maximum Likelyhood Estimation/). + +#+begin_src python :results output :exports code +def logistic_regression(independent_variable: list, + dependent_variable: list) -> object: + """Logisitic regression with Logit model and MLE method. + + :param independent_variable: the independent variable + :param dependent_variable: the dependent variable + + :return fitted_model: the logisitc regression fitted model. + """ + import statsmodels.api as sm + + model = sm.Logit(dependent_variable, sm.add_constant(independent_variable)) + fitted_model = model.fit() + + print('\n', fitted_model.summary()) + + return fitted_model +#+end_src + +#+RESULTS: + +**** Cas des fumeuses + +#+begin_src python :results output :exports both +proba_smokers, model_smokers = logistic_regression(smokers['Age'], + smokers['Death']) +#+end_src + +#+RESULTS: +#+begin_example +/usr/lib/python3/dist-packages/numpy/core/fromnumeric.py:2495: FutureWarning: Method .ptp is deprecated and will be removed in a future version. Use numpy.ptp instead. + return ptp(axis=axis, out=out, **kwargs) +Optimization terminated successfully. + Current function value: 0.412727 + Iterations 7 + + Logit Regression Results +============================================================================== +Dep. Variable: Death No. Observations: 582 +Model: Logit Df Residuals: 580 +Method: MLE Df Model: 1 +Date: jeu., 14 oct. 2021 Pseudo R-squ.: 0.2492 +Time: 05:32:17 Log-Likelihood: -240.21 +converged: True LL-Null: -319.94 +Covariance Type: nonrobust LLR p-value: 1.477e-36 +============================================================================== + coef std err z P>|z| [0.025 0.975] +------------------------------------------------------------------------------ +const -5.5081 0.466 -11.814 0.000 -6.422 -4.594 +Age 0.0890 0.009 10.203 0.000 0.072 0.106 +============================================================================== +#+end_example + +**** Cas des non-fumeuses + +#+begin_src python :results output :exports both +proba_nonsmokers, model_nonsmokers = logistic_regression(nonsmokers['Age'], + nonsmokers['Death']) +#+end_src + +#+RESULTS: +#+begin_example +/usr/lib/python3/dist-packages/numpy/core/fromnumeric.py:2495: FutureWarning: Method .ptp is deprecated and will be removed in a future version. Use numpy.ptp instead. + return ptp(axis=axis, out=out, **kwargs) +Optimization terminated successfully. + Current function value: 0.354560 + Iterations 7 + + Logit Regression Results +============================================================================== +Dep. Variable: Death No. Observations: 732 +Model: Logit Df Residuals: 730 +Method: MLE Df Model: 1 +Date: jeu., 14 oct. 2021 Pseudo R-squ.: 0.4304 +Time: 05:32:21 Log-Likelihood: -259.54 +converged: True LL-Null: -455.62 +Covariance Type: nonrobust LLR p-value: 2.808e-87 +============================================================================== + coef std err z P>|z| [0.025 0.975] +------------------------------------------------------------------------------ +const -6.7955 0.479 -14.174 0.000 -7.735 -5.856 +Age 0.1073 0.008 13.742 0.000 0.092 0.123 +============================================================================== +#+end_example + +*** Visualisation des résultats + +#+begin_src python :results output file :exports both +fig, ax = plt.subplots() +ax.set_xlim(15, 100) +ax.set_ylabel('Death probability') +ax.set_xlabel('Age') + +lmplot(data=data, x='Age', y='Death', hue='Smoker', + logistic=True, y_jitter=0.01, truncate=False, + markers=['o', 'x'], scatter_kws=dict(alpha=0.3)) + +plt.tight_layout() + +plt.savefig('death_probabilities.png') +#+end_src + +#+RESULTS: +[[file:]] + +#+CAPTION: Estimation des probabilités de décès selon l'âge et les habitudes de tabagisme. +#+NAME: fig:proba-deces +[[./death_probabilities.png]] + +L'analyse graphique des résultats semble indiquer une plus forte +probabilité de décès des femmes fumeuses avant 55 ans. Après cet âge, +les probabilités de décès ne paraissent plus influencées par les +habitudes de tabagisme. Le tabac chez les femmes est donc nocif, +surtout avant 55 ans. +* Paradoxe de Simpson +Nous sommes face à un paradoxe de Simpson quand la tendance observée +au sein de sous-groupes disparaît ou est inversée quand les +sous-groupes sont combinés. + +** Qu'en est-il du paradoxe de Simpson dans notre cas ? +Lors de notre première approche, les résultats indiquent que le taux +de mortalité est supérieur chez les non-fumeuses (src_python[:exports +results]{nonsmokers_death_rate} {{{results(=31.42=)}}} contre +src_python[:exports +results]{smokers_death_rate}{{{results(=23.88=)}}}). Lors de la deuxième +approche, lors de la prise en compte de l'âge, les résultats indiquent +l'inverse : le taux de mortalité est supérieur chez les +fumeuses. Nous sommes face à un paradoxe de Simpson : la prise en +compte ou non de la variable =Age= inverse les interprétations que nous +pouvons faire des effets du tabagisme chez les femmes. + +** Quelles sont les explications dans notre cas ? +Il est probable que le paradoxe observé dans le cadre de cet exercice +s'explique en partie par les faits suivants : +- il existe une différence de src_python[:exports + results]{nonsmokers.shape[0] - smokers.shape[0]} {{{results(=150=)}}} individus entre les + effectifs des fumeuses et des non fumeuses, soit environ + src_python[:exports results]{round((nonsmokers.shape[0] - + smokers.shape[0])/(nonsmokers.shape[0] + smokers.shape[0]) * 100, + 0)} {{{results(=11.0=)}}} % de l'effectif total, ce qui n'est pas négligeable ; +- les distributions en âge au sein des groupes (selon les habitudes de + tabagisme) ne coïncident pas ; +- l'âge a un effet supérieur au tabac sur le taux de mortalité. + -- 2.18.1