{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Etude autour du paradoxe de Simpson¶" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "En 1972-1974, à Whickham, une ville du nord-est de l'Angleterre, située à environ 6,5 kilomètres au sud ouest de Newcastle upon Tyne, un sondage d'un sixième des électeurs a été effectué afin d'éclairer des travaux sur les maladies thyroïdiennes et cardiaques (Tunbridge et al. 1977). Une suite de cette étude a été menée vingt ans plus tard (Vanderpump et al. 1995). Certains des résultats avaient trait au tabagisme et à savoir si les individus étaient toujours en vie lors de la seconde étude. Par simplicité, nous nous restreindrons aux femmes et parmi celles-ci aux 1314 qui ont été catégorisées comme \"fumant actuellement\" ou \"n'ayant jamais fumé\". Il y avait relativement peu de femmes dans le sondage initial ayant fumé mais ayant arrêté depuis (162) et très peu pour lesquelles l'information n'était pas disponible (18). La survie à 20 ans a été déterminée pour l'ensemble des femmes du premier sondage.\n", "\n", "L'ensemble de ces données est disponible dans le fichier 'SmokingNotSmokingWomen_InputData.csv'. \n", "Pour info, sur chaque ligne du fichier 'SmokingNotSmokingWomen_InputData.csv', on trouve (Smoker,Status,Age) :\n", "si la personne fume ou non, si elle est vivante ou décédée au moment de la seconde étude, et quel était son âge lors du premier sondage." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## I - Chargement des données et controle si leur contenu est valide + extraction de quelques informations générales :" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "stringC1 = https://gitlab.inria.fr/learninglab/mooc-rr/mooc-rr-ressources/blob/master/module3/Practical_session/Subject6_smoking.csv\n" ] }, { "ename": "ParserError", "evalue": "Error tokenizing data. C error: Expected 1 fields in line 29, saw 25\n", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mParserError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mprint\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m\"stringC1 = \"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstringC1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mOriginalInputData\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstringC1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/opt/conda/lib/python3.6/site-packages/pandas/io/parsers.py\u001b[0m in \u001b[0;36mparser_f\u001b[0;34m(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, escapechar, comment, encoding, dialect, tupleize_cols, error_bad_lines, warn_bad_lines, skipfooter, skip_footer, doublequote, delim_whitespace, as_recarray, compact_ints, use_unsigned, low_memory, buffer_lines, memory_map, float_precision)\u001b[0m\n\u001b[1;32m 707\u001b[0m skip_blank_lines=skip_blank_lines)\n\u001b[1;32m 708\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 709\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0m_read\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilepath_or_buffer\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwds\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 710\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 711\u001b[0m \u001b[0mparser_f\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/opt/conda/lib/python3.6/site-packages/pandas/io/parsers.py\u001b[0m in \u001b[0;36m_read\u001b[0;34m(filepath_or_buffer, kwds)\u001b[0m\n\u001b[1;32m 453\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 454\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 455\u001b[0;31m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnrows\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 456\u001b[0m \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 457\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/opt/conda/lib/python3.6/site-packages/pandas/io/parsers.py\u001b[0m in \u001b[0;36mread\u001b[0;34m(self, nrows)\u001b[0m\n\u001b[1;32m 1067\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'skipfooter not supported for iteration'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1068\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1069\u001b[0;31m \u001b[0mret\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnrows\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1070\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1071\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'as_recarray'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/opt/conda/lib/python3.6/site-packages/pandas/io/parsers.py\u001b[0m in \u001b[0;36mread\u001b[0;34m(self, nrows)\u001b[0m\n\u001b[1;32m 1837\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnrows\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1838\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1839\u001b[0;31m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_reader\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnrows\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1840\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1841\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_first_chunk\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32mpandas/_libs/parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader.read\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader._read_low_memory\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader._read_rows\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader._tokenize_rows\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.raise_parser_error\u001b[0;34m()\u001b[0m\n", "\u001b[0;31mParserError\u001b[0m: Error tokenizing data. C error: Expected 1 fields in line 29, saw 25\n" ] } ], "source": [ "# Chargement du jeu de données originales :\n", "if False :\n", " # Si fichier de données copié localement :\n", " pathToFile=\"../__DataSets/\"\n", " FileName=\"module3_Practical_session_Subject6_smoking.csv\"\n", " stringC1 = pathToFile+FileName\n", "else :\n", " stringC1 = \"https://gitlab.inria.fr/learninglab/mooc-rr/mooc-rr-ressources/blob/master/module3/Practical_session/Subject6_smoking.csv\"\n", "\n", "print (\"stringC1 = \", stringC1)\n", "OriginalInputData = pd.read_csv(stringC1)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'OriginalInputData' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mprint\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m\"le nb d'enregistrements = \"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mOriginalInputData\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\" = (nb_lignes='features-values' , nb_colonnes='features')\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;31m#\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;31m# InputData_index = OriginalInputData.index\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;31m# InputData_columns = OriginalInputData.columns\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;31m# print (\"InputData : indexe des colonnes = \",InputData_columns)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mNameError\u001b[0m: name 'OriginalInputData' is not defined" ] } ], "source": [ "print (\"le nb d'enregistrements = \",OriginalInputData.shape, \" = (nb_lignes='features-values' , nb_colonnes='features')\")\n", "#\n", "# InputData_index = OriginalInputData.index\n", "# InputData_columns = OriginalInputData.columns\n", "# print (\"InputData : indexe des colonnes = \",InputData_columns)\n", "# print (\"InputData : indexe des lignes = \",InputData_index)\n", "#\n", "OriginalInputData.head(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Verification qu'il n'y a pas de points manquants dans ce jeux de données :" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'OriginalInputData' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mOriginalInputData\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mOriginalInputData\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misnull\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0many\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0maxis\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'OriginalInputData' is not defined" ] } ], "source": [ "OriginalInputData[OriginalInputData.isnull().any(axis=1)]" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Toutes les entregistrements sont dans un état valide. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Remarque \n", "## Les donnees peuvent etre triées par valeurs croissantes de l'age , pour les lister aisement par tranches d'age\n", "## Mais ce n'est pas absolument necessaire ! Donc on n'active pas cette option pour la suite :\n", "#sortedData = OriginalInputData.set_index('Age').sort_index()\n", "#sortedData.head(25) # shows the first 25 lines of records" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Affichons quelques informations générales quant à la distribution des ages :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Age = OriginalInputData['Age']\n", "# Soit utiliser la fonction suivante objet.describe() \n", "# Age.describe()\n", "# Ou bien :\n", "AgeMax= np.max(Age); AgeMin= np.min(Age); AgeMoy= np.mean(Age) ; AgeMedian = np.median(Age) ; ecartType=np.std(Age)\n", "print (\" Age min = % 3d\" % AgeMin)\n", "print (\" Age max = % 3d\" % AgeMax)\n", "print (\" Age moyen = % 3d\" % AgeMoy)\n", "print (\" Age median = % 3d\" % AgeMedian)\n", "print (\" Age ecartType = % 4.2f\" %ecartType)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dénombrons les nombres de femmes fumeuses et non fumeuses, de femmes vivantes et de mortes :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Vérifions le contenu de la sous-liste de données qui contient 2 données binaires 'Yes' ou 'No' :\n", "Fumeuse_ou_non = OriginalInputData['Smoker']\n", "Fumeuse_ou_non.describe()" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "On voit que, sur 1314 femmes, il y a 732 specimens du type 'No' ; \n", "donc on peut en déduire qu'il y a 1314-732 = 582 fumeuses" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Vérifions le contenu de la sous-liste de données qui contient 2 données binaires 'Dead' ou 'Alive' :\n", "Vivante_ou_Morte = OriginalInputData['Status']\n", "Vivante_ou_Morte.describe()" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "On voit que, sur 1314 femmes, il y a 945 specimens du type 'Alive' ; \n", "donc on peut en déduire qu'il y a 1314-945=369 femmes decedees, qu'elles aient été fumeuses ou non" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## II - Calculons dans chaque groupe (fumeuses, non fumeuses) le taux de mortalité (le rapport entre le nombre de femmes décédées dans un groupe avec le nombre total de femmes dans ce groupe)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# selection des lignes du DataFrame Fumeuse_ou_non en fonction de la valeur 'Yes' dans la colonne descriptive 'Smoker':\n", "Fumeuses = OriginalInputData.loc[OriginalInputData['Smoker'] == 'Yes']\n", "Fumeuses.head(10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Nb_Fumeuses = Fumeuses.shape[0] # donne le nombre de lignes dans Fumeuses\n", "# print (\"Nb_Fumeuses=\",Nb_Fumeuses)\n", "FumeusesVivantes = OriginalInputData.loc[(OriginalInputData['Smoker'] == 'Yes') & (OriginalInputData['Status'] == 'Alive')]\n", "Nb_FumeusesVivantes = FumeusesVivantes.shape[0] # donne le nombre de lignes dans FumeusesVivantes\n", "# count_col = Fumeuses_Vivantes.shape[1] # donne le nombre de colonnes dans FumeusesVivantes\n", "Nb_FumeusesMortes = Nb_Fumeuses - Nb_FumeusesVivantes\n", "print (\"Nb Fumeuses Mortes=\",Nb_FumeusesMortes,\" ; Nb Fumeuses Vivantes=\",Nb_FumeusesVivantes)" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "On voit que, parmi les 582 femmes fumeuses, 443 sont toujours vivantes à l'issue des 20 ans, 139 sont mortes." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Le taux de mortalité dans le groupe des femmes fumeuses toutes ensemble considérées vaut :\n", "ToutesFumeusesConfonfues_TxMortalite = (Nb_FumeusesMortes)/Nb_Fumeuses * 100\n", "print (\"Toutes FumeusesConfonfues : TxMortalite = % 4.2f \" % ToutesFumeusesConfonfues_TxMortalite)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "NonFumeuses = OriginalInputData.loc[OriginalInputData['Smoker'] == 'No']\n", "Nb_NonFumeuses = NonFumeuses.shape[0] # donne le nombre de lignes dans NonFumeuses\n", "# print (\"Nb_NonFumeuses=\",Nb_NonFumeuses)\n", "NonFumeusesVivantes = OriginalInputData.loc[(OriginalInputData['Smoker'] == 'No') & (OriginalInputData['Status'] == 'Alive')]\n", "Nb_NonFumeusesVivantes = NonFumeusesVivantes.shape[0] # donne le nombre de lignes dans NonFumeusesVivantes\n", "Nb_NonFumeusesMortes = Nb_NonFumeuses - Nb_NonFumeusesVivantes\n", "print (\"Nb NonFumeuses Mortes=\",Nb_NonFumeusesMortes,\" ; Nb NonFumeuses Vivantes=\",Nb_NonFumeusesVivantes)" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "On voit qu'il y a 732 femmes non-fumeuses (on peut vérifier que 732 + 582 = 1314 au total)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Le taux de mortalité dans le groupe des femmes Non fumeuses toutes ensemble considérées vaut :\n", "ToutesNonFumeusesConfonfues_TxMortalite = (Nb_NonFumeusesMortes)/Nb_NonFumeuses * 100\n", "print (\"Toutes Non-Fumeuses Confonfues : TxMortalite = % 4.2f \" % ToutesNonFumeusesConfonfues_TxMortalite)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Résumons les résultats de cette partie II sous forme d'un tableau et d'un graphe :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "table0 = {\"Groupes SANS distinction d'age\": ['Femmes fumeuses', 'Femmes non fumeuses'],\n", " 'Nb_Vivantes': [Nb_FumeusesVivantes, Nb_NonFumeusesVivantes],\n", " 'Nb_Mortes': [Nb_FumeusesMortes, Nb_NonFumeusesMortes],\n", " 'Mortalité en %': [ToutesFumeusesConfonfues_TxMortalite, ToutesNonFumeusesConfonfues_TxMortalite]\n", " }\n", "Resume0 = pd.DataFrame(table0, columns=[\"Groupes SANS distinction d'age\", 'Nb_Vivantes','Nb_Mortes','Mortalité en %'])\n", "print (Resume0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Affichage sous la forme d'un graphe en barres dont la hauteur reflete des taux pour chacun des groupes. \n", "#\n", "# Construire la série des valeurs pour la hauteur des barres :\n", "HauteursDesBarres = [ToutesFumeusesConfonfues_TxMortalite,ToutesNonFumeusesConfonfues_TxMortalite]\n", "# Construire la série des labels pour chacune des barres :\n", "LabelsDesBarres = ('Femmes fumeuses', 'Femmes non fumeuses')\n", "y_pos = np.arange(len(LabelsDesBarres))\n", "# Creation du graphique en barres :\n", "plt.bar(y_pos, HauteursDesBarres, color=['red', 'green'])\n", "\n", "# Mise en forme des labels et marques sur les axes horizontal et vertical :\n", "plt.xticks(y_pos, LabelsDesBarres, color='cyan')\n", "plt.yticks(color='orange')\n", "plt.title('Taux de mortalité', fontdict=None, loc='center', pad=None)\n", "plt.show()" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Ainsi, il apparait que le taux de mortalité est plus élevé chez les femmes non-fumeuses que chez les femmes fumeuses !!??\n", "C'est l'illustration du paradoxe de Simpson que l'on va maintenant analyser. \n", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", "A partir de maintenant, on va prendre en compte une variable qui n'a pas été explicitée jusqu'ici et qui introduit la confusion en influencant le résultat final : il s’agit de l’âge des personnes qui joue lui-aussi sur la mortalité.\n", "Pour ce faire, on va répéter les opérations précédentes mais en opérant par tranches d'age ; \n", "on en choisit 4 : [18:34] ; ]34:54] ; ]54:64] ; >64 ans ." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## III - Pour chaque groupe (fumeuses , non fumeuses), le taux de mortalité est maintenant évalué par tranches d'age" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print (\"On reprend l'analyse en opérant dans la 1ere tranche d'age [AgeMin:34] ans :\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "femmes_TrA1 = OriginalInputData[OriginalInputData[\"Age\"].between(int(AgeMin), 34)]\n", "Nb_femmes_TrA1 = femmes_TrA1.shape[0]\n", "print (\"Nb de femmes dans la tranche d'age [\",int(AgeMin),\":34] = \",Nb_femmes_TrA1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Fumeuses_TrA1 = femmes_TrA1.loc[femmes_TrA1['Smoker'] == 'Yes']\n", "Nb_Fumeuses_TrA1 = Fumeuses_TrA1.shape[0]\n", "Nb_NonFumeuses_TrA1 = Nb_femmes_TrA1 - Nb_Fumeuses_TrA1\n", "print (\"Dans la tranche d'age [\",int(AgeMin),\":34] : Nb Fumeuses=\",Nb_Fumeuses_TrA1,\" vs Nb NonFumeuses=\",Nb_NonFumeuses_TrA1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "FumeusesVivantes_TrA1 = femmes_TrA1.loc[(femmes_TrA1['Smoker'] == 'Yes') & (femmes_TrA1['Status'] == 'Alive')]\n", "Nb_FumeusesVivantes_TrA1 = FumeusesVivantes_TrA1.shape[0]\n", "Nb_FumeusesMortes_TrA1 = Nb_Fumeuses_TrA1 - Nb_FumeusesVivantes_TrA1\n", "print (\"Nb Fumeuses Mortes=\",Nb_FumeusesMortes_TrA1,\" vs Nb Fumeuses Vivantes=\",Nb_FumeusesVivantes_TrA1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "NonFumeusesVivantes_TrA1 = femmes_TrA1.loc[(femmes_TrA1['Smoker'] == 'No') & (femmes_TrA1['Status'] == 'Alive')]\n", "Nb_NonFumeusesVivantes_TrA1 = NonFumeusesVivantes_TrA1.shape[0]\n", "Nb_NonFumeusesMortes_TrA1 = Nb_NonFumeuses_TrA1 - Nb_NonFumeusesVivantes_TrA1\n", "print (\"Nb Non Fumeuses Mortes=\",Nb_NonFumeusesMortes_TrA1,\" vs Nb Non Fumeuses Vivantes=\",Nb_NonFumeusesVivantes_TrA1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Le taux de mortalité dans le groupe des femmes fumeuses dans la la tranche d'age [18:34] vaut :\n", "Fumeuses_TrA1_TxMortalite = (Nb_FumeusesMortes_TrA1)/Nb_Fumeuses_TrA1 * 100\n", "print (\"Dans la tranche d'age [18:34] : le Taux de mortalite des fumeuses = % 4.2f \" % Fumeuses_TrA1_TxMortalite)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Le taux de mortalité dans le groupe des femmes Non fumeuses dans la la tranche d'age [18:34] vaut :\n", "NonFumeuses_TrA1_TxMortalite = (Nb_NonFumeusesMortes_TrA1)/Nb_NonFumeuses_TrA1 * 100\n", "print (\"Dans la tranche d'age [18:34] : le Taux de mortalite des Non fumeuses = % 4.2f \" % NonFumeuses_TrA1_TxMortalite)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "table1 = {\"Dans la tranche d'age [18:34]\": ['Femmes fumeuses', 'Femmes non fumeuses'],\n", " 'Nb_Vivantes': [Nb_FumeusesVivantes_TrA1, Nb_NonFumeusesVivantes_TrA1],\n", " 'Nb_Mortes': [Nb_FumeusesMortes_TrA1, Nb_NonFumeusesMortes_TrA1],\n", " 'Mortalité en %': [Fumeuses_TrA1_TxMortalite, NonFumeuses_TrA1_TxMortalite]\n", " }\n", "Resume1 = pd.DataFrame(table1, columns=[\"Dans la tranche d'age [18:34]\", 'Nb_Vivantes','Nb_Mortes','Mortalité en %'])\n", "print (Resume1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print (\"On reprend l'analyse en opérant dans la 2nde tranche d'age ]34:54] ans :\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "femmes_TrA2 = OriginalInputData[OriginalInputData[\"Age\"].between(float(34)+0.000001, 54)]\n", "Nb_femmes_TrA2 = femmes_TrA2.shape[0]\n", "print (\"Nb de femmes dans la tranche d'age ]34:54] = \",Nb_femmes_TrA2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Fumeuses_TrA2 = femmes_TrA2.loc[femmes_TrA2['Smoker'] == 'Yes']\n", "Nb_Fumeuses_TrA2 = Fumeuses_TrA2.shape[0]\n", "Nb_NonFumeuses_TrA2 = Nb_femmes_TrA2 - Nb_Fumeuses_TrA2\n", "print (\"Dans la tranche d'age ]34:54] : Nb Fumeuses=\",Nb_Fumeuses_TrA2,\" vs Nb NonFumeuses=\",Nb_NonFumeuses_TrA2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "FumeusesVivantes_TrA2 = femmes_TrA2.loc[(femmes_TrA2['Smoker'] == 'Yes') & (femmes_TrA2['Status'] == 'Alive')]\n", "Nb_FumeusesVivantes_TrA2 = FumeusesVivantes_TrA2.shape[0]\n", "Nb_FumeusesMortes_TrA2 = Nb_Fumeuses_TrA2 - Nb_FumeusesVivantes_TrA2\n", "print (\"Nb Fumeuses Mortes=\",Nb_FumeusesMortes_TrA2,\" vs Nb Fumeuses Vivantes=\",Nb_FumeusesVivantes_TrA2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "NonFumeusesVivantes_TrA2 = femmes_TrA2.loc[(femmes_TrA2['Smoker'] == 'No') & (femmes_TrA2['Status'] == 'Alive')]\n", "Nb_NonFumeusesVivantes_TrA2 = NonFumeusesVivantes_TrA2.shape[0]\n", "Nb_NonFumeusesMortes_TrA2 = Nb_NonFumeuses_TrA2 - Nb_NonFumeusesVivantes_TrA2\n", "print (\"Nb Non Fumeuses Mortes=\",Nb_NonFumeusesMortes_TrA2,\" vs Nb Non Fumeuses Vivantes=\",Nb_NonFumeusesVivantes_TrA2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Le taux de mortalité dans le groupe des femmes fumeuses dans la la tranche d'age ]34:54] vaut :\n", "Fumeuses_TrA2_TxMortalite = (Nb_FumeusesMortes_TrA2)/Nb_Fumeuses_TrA2 * 100\n", "print (\"Dans la tranche d'age ]34:54] : le Taux de mortalite des fumeuses = % 4.2f \" % Fumeuses_TrA2_TxMortalite)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Le taux de mortalité dans le groupe des femmes Non fumeuses dans la la tranche d'age ]34:54] vaut :\n", "NonFumeuses_TrA2_TxMortalite = (Nb_NonFumeusesMortes_TrA2)/Nb_NonFumeuses_TrA2 * 100\n", "print (\"Dans la tranche d'age ]34:54] : le Taux de mortalite des Non fumeuses = % 4.2f \" % NonFumeuses_TrA2_TxMortalite)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "table2 = {\"Dans la tranche d'age ]34:54]\": ['Femmes fumeuses', 'Femmes non fumeuses'],\n", " 'Nb_Vivantes': [Nb_FumeusesVivantes_TrA2, Nb_NonFumeusesVivantes_TrA2],\n", " 'Nb_Mortes': [Nb_FumeusesMortes_TrA2, Nb_NonFumeusesMortes_TrA2],\n", " 'Mortalité en %': [Fumeuses_TrA2_TxMortalite, NonFumeuses_TrA2_TxMortalite]\n", " }\n", "Resume2 = pd.DataFrame(table2, columns=[\"Dans la tranche d'age ]34:54]\", 'Nb_Vivantes','Nb_Mortes','Mortalité en %'])\n", "print (Resume2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print (\"On reprend l'analyse en opérant dans la 3eme tranche d'age ]54:64] ans :\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "femmes_TrA3 = OriginalInputData[OriginalInputData[\"Age\"].between(float(54)+0.000001, 64)]\n", "Nb_femmes_TrA3 = femmes_TrA3.shape[0]\n", "print (\"Nb de femmes dans la tranche d'age ]54:64] = \",Nb_femmes_TrA3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Fumeuses_TrA3 = femmes_TrA3.loc[femmes_TrA3['Smoker'] == 'Yes']\n", "Nb_Fumeuses_TrA3 = Fumeuses_TrA3.shape[0]\n", "Nb_NonFumeuses_TrA3 = Nb_femmes_TrA3 - Nb_Fumeuses_TrA3\n", "print (\"Dans la tranche d'age ]54:64] : Nb Fumeuses=\",Nb_Fumeuses_TrA3,\" vs Nb NonFumeuses=\",Nb_NonFumeuses_TrA3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "FumeusesVivantes_TrA3 = femmes_TrA3.loc[(femmes_TrA3['Smoker'] == 'Yes') & (femmes_TrA3['Status'] == 'Alive')]\n", "Nb_FumeusesVivantes_TrA3 = FumeusesVivantes_TrA3.shape[0]\n", "Nb_FumeusesMortes_TrA3 = Nb_Fumeuses_TrA3 - Nb_FumeusesVivantes_TrA3\n", "print (\"Nb Fumeuses Mortes=\",Nb_FumeusesMortes_TrA3,\" vs Nb Fumeuses Vivantes=\",Nb_FumeusesVivantes_TrA3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "NonFumeusesVivantes_TrA3 = femmes_TrA3.loc[(femmes_TrA3['Smoker'] == 'No') & (femmes_TrA3['Status'] == 'Alive')]\n", "Nb_NonFumeusesVivantes_TrA3 = NonFumeusesVivantes_TrA3.shape[0]\n", "Nb_NonFumeusesMortes_TrA3 = Nb_NonFumeuses_TrA3 - Nb_NonFumeusesVivantes_TrA3\n", "print (\"Nb Non Fumeuses Mortes=\",Nb_NonFumeusesMortes_TrA3,\" vs Nb Non Fumeuses Vivantes=\",Nb_NonFumeusesVivantes_TrA3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Le taux de mortalité dans le groupe des femmes fumeuses dans la tranche d'age ]54:64] vaut :\n", "Fumeuses_TrA3_TxMortalite = (Nb_FumeusesMortes_TrA3)/Nb_Fumeuses_TrA3 * 100\n", "print (\"Dans la tranche d'age ]54:64] : le Taux de mortalite des fumeuses = % 4.2f \" % Fumeuses_TrA3_TxMortalite)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "table3 = {\"Dans la tranche d'age ]54:64]\": ['Femmes fumeuses', 'Femmes non fumeuses'],\n", " 'Nb_Vivantes': [Nb_FumeusesVivantes_TrA3, Nb_NonFumeusesVivantes_TrA3],\n", " 'Nb_Mortes': [Nb_FumeusesMortes_TrA3, Nb_NonFumeusesMortes_TrA3],\n", " 'Mortalité en %': [Fumeuses_TrA3_TxMortalite, NonFumeuses_TrA3_TxMortalite]\n", " }\n", "Resume3 = pd.DataFrame(table3, columns=[\"Dans la tranche d'age ]54:64]\", 'Nb_Vivantes','Nb_Mortes','Mortalité en %'])\n", "print (Resume3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print (\"On reprend l'analyse en opérant dans la 4eme tranche d'age ]64:AgeMax] ans :\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "femmes_TrA4 = OriginalInputData[OriginalInputData[\"Age\"].between(float(64)+0.000001, int(AgeMax)+1)]\n", "Nb_femmes_TrA4 = femmes_TrA4.shape[0]\n", "print (\"Nb de femmes dans la tranche d'age ]64:\",int(AgeMax),\"] = \",Nb_femmes_TrA4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Fumeuses_TrA4 = femmes_TrA4.loc[femmes_TrA4['Smoker'] == 'Yes']\n", "Nb_Fumeuses_TrA4 = Fumeuses_TrA4.shape[0]\n", "Nb_NonFumeuses_TrA4 = Nb_femmes_TrA4 - Nb_Fumeuses_TrA4\n", "print (\"Dans la tranche d'age ]64\",int(AgeMax),\"] : Nb Fumeuses=\",Nb_Fumeuses_TrA4,\" vs Nb NonFumeuses=\",Nb_NonFumeuses_TrA4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "FumeusesVivantes_TrA4 = femmes_TrA4.loc[(femmes_TrA4['Smoker'] == 'Yes') & (femmes_TrA4['Status'] == 'Alive')]\n", "Nb_FumeusesVivantes_TrA4 = FumeusesVivantes_TrA4.shape[0]\n", "Nb_FumeusesMortes_TrA4 = Nb_Fumeuses_TrA4 - Nb_FumeusesVivantes_TrA4\n", "print (\"Nb Fumeuses Mortes=\",Nb_FumeusesMortes_TrA4,\" vs Nb Fumeuses Vivantes=\",Nb_FumeusesVivantes_TrA4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "NonFumeusesVivantes_TrA4 = femmes_TrA4.loc[(femmes_TrA4['Smoker'] == 'No') & (femmes_TrA4['Status'] == 'Alive')]\n", "Nb_NonFumeusesVivantes_TrA4 = NonFumeusesVivantes_TrA4.shape[0]\n", "Nb_NonFumeusesMortes_TrA4 = Nb_NonFumeuses_TrA4 - Nb_NonFumeusesVivantes_TrA4\n", "print (\"Nb Non Fumeuses Mortes=\",Nb_NonFumeusesMortes_TrA4,\" vs Nb Non Fumeuses Vivantes=\",Nb_NonFumeusesVivantes_TrA4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Le taux de mortalité dans le groupe des femmes fumeuses dans la tranche d'age ]64:AgeMax] vaut :\n", "Fumeuses_TrA4_TxMortalite = (Nb_FumeusesMortes_TrA4)/Nb_Fumeuses_TrA4 * 100\n", "print (\"Dans la tranche d'age ]64\",int(AgeMax),\"] : le Taux de mortalite des fumeuses = % 4.2f \" % Fumeuses_TrA4_TxMortalite)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Le taux de mortalité dans le groupe des femmes Non fumeuses dans la tranche d'age ]64:AgeMax] vaut :\n", "NonFumeuses_TrA4_TxMortalite = (Nb_NonFumeusesMortes_TrA4)/Nb_NonFumeuses_TrA4 * 100\n", "print (\"Dans la tranche d'age ]64\",int(AgeMax),\"] : le Taux de mortalite des Non fumeuses = % 4.2f \" % NonFumeuses_TrA4_TxMortalite)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "table4 = {\"Dans la tranche d'age ]64:89]\": ['Femmes fumeuses', 'Femmes non fumeuses'],\n", " 'Nb_Vivantes': [Nb_FumeusesVivantes_TrA4, Nb_NonFumeusesVivantes_TrA4],\n", " 'Nb_Mortes': [Nb_FumeusesMortes_TrA4, Nb_NonFumeusesMortes_TrA4],\n", " 'Mortalité en %': [Fumeuses_TrA4_TxMortalite, NonFumeuses_TrA4_TxMortalite]\n", " }\n", "Resume4 = pd.DataFrame(table4, columns=[\"Dans la tranche d'age ]64:89]\", 'Nb_Vivantes','Nb_Mortes','Mortalité en %'])\n", "print (Resume4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Resumons la partie III à l'aide des tableaux 1 à 4, et à l'aide d'un graphe en barres dont la hauteur reflete des taux de mortalité pour chacun des groupes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print (Resume1)\n", "print (Resume2)\n", "print (Resume3)\n", "print (Resume4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Construire la série des valeurs pour la hauteur des barres :\n", "HauteursDesBarres = [Fumeuses_TrA1_TxMortalite,NonFumeuses_TrA1_TxMortalite,\n", " 0,0, # pour écarter les tranches 1 et 2\n", " Fumeuses_TrA2_TxMortalite,NonFumeuses_TrA2_TxMortalite,\n", " 0,0, # pour écarter les tranches 2 et 3\n", " Fumeuses_TrA3_TxMortalite,NonFumeuses_TrA3_TxMortalite,\n", " 0,0, # pour écarter les tranches 3 et 4\n", " Fumeuses_TrA4_TxMortalite,NonFumeuses_TrA4_TxMortalite]\n", "# Construire la série des labels pour chacune des barres :\n", "LabelsDesBarres = ('18-34: Fumeuses', '18-34: non.Fumeuses',\n", " '','', # pour écarter les tranches 1 et 2\n", " '34-54: Fumeuses', '34-54: non.Fumeuses',\n", " '','', # pour écarter les tranches 2 et 3\n", " '54-64: Fumeuses', '54-64: non.Fumeuses',\n", " '','', # pour écarter les tranches 3 et 4\n", " '64-89: Fumeuses', '64-89: non.Fumeuses')\n", "# Choisir la position (? la largeur ?) pour chacune des barres\n", "barres_position = np.arange(len(LabelsDesBarres))\n", "# ??? barres_largeur = [0.1,0.3,3.0,3.5]\n", "#\n", "# Creation du graphique en barres :\n", "plt.bar(barres_position, HauteursDesBarres, color=['red','green','red', 'green','red','green','red','green','red', 'green','red','green','red','green'])\n", "# ??? plt.bar(barres_position, HauteursDesBarres, width=barres_largeur, color=['red','green','red', 'green','red','green','red','green','red', 'green','red','green','red','green'])\n", "#\n", "# Mise en forme des labels et marques sur les axes horizontal et vertical :\n", "plt.xticks(barres_position, LabelsDesBarres, color='black', rotation=60)\n", "plt.yticks(color='orange')\n", "plt.title(\"Taux de mortalité (en %) par tranche d'age\", fontdict=None, loc='center', pad=None, color='orange')\n", "plt.show()" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Les tableaux 'ResumeX' et le graphique montrant le taux de mortalité par tranche d'age permet de conclure que le tabac constitue un facteur de mortalité ." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## IV - Prolongement de l'activité avec une regression logistique " ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Afin d'éviter un biais induit par des regroupements en tranches d'âges arbitraires et non régulières, on peut essayer de réaliser d'autres analyse (par exemple, une régression logistique). \n", "Le but est d'analyser ''la corrrélation'' entre les 2 variables 'Mortalité' et 'Age' pour étudier la probabilité de décès en fonction de l'âge, et ceci selon que l'on considère le groupe des fumeuses ou des non fumeuses. \n", "\n", "Avertissements : \n", "* la régression logistique porte assez mal son nom , car il ne s’agit pas à proprement parler d’une régression au sens classique du terme (on essaye pas d’expliquer une variable quantitative mais de classer des individus dans deux catégories). \n", "* par ailleurs, la fonction LogisticRegression de Scikit Learn ne fournit pas les valeurs p-value et les intervalles de confiance pour les coefficients du modele, meme si cela est theoriquement possible de les avoir si la regression est appliquée sans penalisation ; il faut privilégier l'utilisation de la fonction de la librairie \"statsmodels\"." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.linear_model import LogisticRegression\n", "#\n", "import statsmodels.discrete.discrete_model as sm" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Rappel : OriginalInputData = pd.read_csv(\"../__DataSets/module3_Practical_session_Subject6_smoking.csv\")\n", "OriginalInputData # .head(10) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### IV - A/ Operons une Regression Logistique sur l'ensemble des 2 groupes (fumeuses + non fumeuses)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# a) selection des colonnes \"Smoker\" et \"Age\" (qui seront ''les variables explicatives'' de la mortalite) :\n", "# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", "X = OriginalInputData[['Smoker','Age']]\n", "X.head(5) # pour vérifier le contenu " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Pour convertir les valeurs de la colonne 'Smoker' qui valent 'Yes' ou 'No' en entiers 1 ou 0 \n", "# ( NB pour la suite, stockage dans des DataFrames separes pour les Fumeuses et pour les NonFumeuses )\n", "# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", "X_pourEtudeMortaliteFumeuses = pd.DataFrame() \n", "X_pourEtudeMortaliteNonFumeuses = pd.DataFrame()\n", "Y_pourEtudeMortaliteFumeuses = pd.DataFrame() \n", "Y_pourEtudeMortaliteNonFumeuses = pd.DataFrame()\n", "countF = 0\n", "countNF = 0\n", "taille1Colonne = OriginalInputData['Smoker'].shape[0] # devrait etre egal à 1314\n", "for i in range(taille1Colonne) :\n", " if OriginalInputData.loc[i,'Smoker'] == \"Yes\" : \n", " X.loc[i,'Smoker'] = 1 # conversion en entier\n", " X_pourEtudeMortaliteFumeuses.loc[countF,'Smoker'] = 1 \n", " X_pourEtudeMortaliteFumeuses.loc[countF,'Age'] = OriginalInputData.loc[i,'Age'] \n", " # Y_pourEtudeMortaliteFumeuses.loc[countF,'Status'] = OriginalInputData.loc[i,'Status'] :\n", " if OriginalInputData.loc[i,'Status'] == \"Alive\" :\n", " Y_pourEtudeMortaliteFumeuses.loc[countF,'Status'] = 1\n", " else : \n", " Y_pourEtudeMortaliteFumeuses.loc[countF,'Status'] = 0\n", " countF += 1\n", " else : \n", " X.loc[i,'Smoker'] = 0 # conversion en entier\n", " X_pourEtudeMortaliteNonFumeuses.loc[countNF,'Smoker'] = 0\n", " X_pourEtudeMortaliteNonFumeuses.loc[countNF,'Age'] = OriginalInputData.loc[i,'Age']\n", " # Y_pourEtudeMortaliteNonFumeuses.loc[countNF,'Status'] = OriginalInputData.loc[i,'Status'] :\n", " if OriginalInputData.loc[i,'Status'] == \"Alive\" :\n", " Y_pourEtudeMortaliteNonFumeuses.loc[countNF,'Status'] = 1 \n", " else : \n", " Y_pourEtudeMortaliteNonFumeuses.loc[countNF,'Status'] = 0 \n", " countNF += 1\n", "#print (\"verification : finalement countF=\",X_pourEtudeMortaliteFumeuses.shape[0],\" ? \",Nb_Fumeuses)\n", "#print (\"verification : finalement countNF=\",X_pourEtudeMortaliteNonFumeuses.shape[0],\" ? \",Nb_NonFumeuses)\n", "X_pourEtudeMortaliteFumeuses.describe()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X_pourEtudeMortaliteNonFumeuses.describe()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print (\"verif : somme des valeurs dans la colonne 'Smoker' = \",X['Smoker'].sum())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# b) selection de la colonne \"Status\" (vivante ou morte) qui sera ''la variable mortalité à prédire'' :\n", "Y = OriginalInputData['Status'] # .astype(int) en principe MAIS ValueError: invalid literal for int() with base 10: 'Yes'!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Vérifions le contenu de la sous-liste de données qui contient 2 données binaires 'Dead' ou 'Alive' :\n", "Y.head(5) # pour vérifier le contenu\n", "# Y.describe()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Pour convertir les valeurs de la colonne 'Status' qui valent 'Alive' ou 'Dead' en entiers 1 ou 0 :\n", "# { remarque : Y = pd.to_numeric(OriginalInputData['Status'],errors='coerce') n'a pas marche }\n", "# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", "taille1Colonne = OriginalInputData['Smoker'].shape[0] # devrait etre egal à 1314\n", "for i in range(taille1Colonne) :\n", " if OriginalInputData.loc[i,'Status'] == \"Alive\" : \n", " Y.loc[i] = 1\n", " else :\n", " Y.loc[i] = 0" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Y.head(5) # pour vérifier son contenu converti" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print (\"verif : somme des valeurs dans la colonne Status = \",Y.sum())" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Avertissement : \n", "* SciKit-Learn décide par défaut d’appliquer une régularisation sur le modèle. \n", "* Dans le modèle que l'on va utiliser, on n'applique pas de pénalité et on prend un solver du type Newton qui est le plus classique pour la régression logistique.\n", "* Pour comprendre les coefficients du modèle, SciKit-Learn stocke les informations dans .coef_, \n", " il faut les afficher de manière plus agréable dans un DataFrame avec la constante du modèle ; \n", " mais leur interprétation n'est pas évidente" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### * Appliquons le modele de Regression Logistique de 'scikit learn' sur l'ensemble des 2 groupes Fumeuses et Non Fumeuses :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Rappel : la variable 'Smoker' represente ici A LA FOIS les fumeuses et non-fumeuses !!\n", "if Y.sum() == 0 : # on verifie que Y contient plus de 1 classe\n", " print (\"Probleme : la somme Y.sum() = \",Y.sum(),\" devrait être différente de 0 !\")\n", " print (\" les valeurs de Y ne composent qu'une seule classe !\")\n", "else : # La regression logistique peut être effectuée :\n", " SKL_MRL_A = LogisticRegression(penalty='none',solver='newton-cg')\n", " SKL_MRL_A.fit(X,Y)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Si souhaité, afficher dans un DataFrame les coefficients du modèle , avec la constante :\n", "if False :\n", " pd.DataFrame(np.concatenate([SKL_MRL_A.intercept_.reshape(-1,1),\n", " SKL_MRL_A.coef_],axis=1),\n", " index = [\"coef\"],\n", " columns = [\"constante\"]+list(X.columns)).T" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "score__SKL_MRL_A = SKL_MRL_A.score(X,Y)\n", "print (\"Regression Logistique de SciKitLearn sur l'ensemble des 2 groupes fumeuses + non-fumeuses : score=\",score__SKL_MRL_A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### * Appliquons le modele de Regression Logistique de 'statsmodels' sur l'ensemble des 2 groupes Fumeuses et Non Fumeuses : " ] }, { "cell_type": "raw", "metadata": {}, "source": [ "# Attention : par defaut, le modele de regression logistique de 'statsmodels' n'inclue pas d'interception avec une valeur cte ;\n", "# pour inclure cette option d'interception dans le modele, \n", "# utiliser l'instruction 'statsmodels.tools.add_constant' pour ajouter la constant dans la matrice X" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "MLRavecSM_A = sm.Logit(Y, X).fit()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# MLRavecSM_A.params\n", "MLRavecSM_A.summary()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### IV - B/ Operons une Regression Logistique sur le groupe des fumeuses " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Commencons par vérifier le contenu de X_pourEtudeMortaliteFumeuses et Y_pourEtudeMortaliteFumeuses\n", "X_pourEtudeMortaliteFumeuses.describe()\n", "#X_pourEtudeMortaliteFumeuses.head(10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Y_pourEtudeMortaliteFumeuses.describe()\n", "# Y_pourEtudeMortaliteFumeuses.head(10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "taille1Colonne = X_pourEtudeMortaliteFumeuses['Age'].shape[0] # devrait etre egal à 582\n", "print (\"taille1Colonne=\",taille1Colonne)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# La somme des valeurs de 'Y_pourEtudeMortaliteFumeuses' renvoit le nb de deces chez les fumeuses :\n", "NbDecesChezFumeuses = Y_pourEtudeMortaliteFumeuses.sum()\n", "print (\"verif : Nbre de deces chez les Fumeuses = \",NbDecesChezFumeuses,\" VS Nb_Fumeuses=\",Nb_Fumeuses)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### * Appliquons le modele de Regression Logistique de 'scikit learn' sur le groupe des Fumeuses :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if ( int(NbDecesChezFumeuses) == 0 ): # on verifie que Y_pourEtudeMortaliteFumeuses contient plus de 1 classe\n", " print (\"Probleme : la somme Y_pourEtudeMortaliteFumeuses.sum() devrait être différente de 0 !\")\n", " print (\" les valeurs de Y_pourEtudeMortaliteFumeuses ne composent qu'une seule classe !\")\n", "else : # La regression logistique peut être effectuée :\n", " SKL_MRL_B = LogisticRegression(penalty='none',solver='newton-cg')\n", " SKL_MRL_B.fit(X_pourEtudeMortaliteFumeuses, Y_pourEtudeMortaliteFumeuses)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Si souhaité, afficher dans un DataFrame les coefficients du modèle , avec la constante :\n", "if False :\n", " pd.DataFrame(np.concatenate([SKL_MRL_B.intercept_.reshape(-1,1),\n", " SKL_MRL_B.coef_],axis=1),\n", " index = [\"coef\"],\n", " columns = [\"constante\"]+list(X_pourEtudeMortaliteFumeuses.columns)).T" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "score__SKL_MRL_B = SKL_MRL_B.score(X_pourEtudeMortaliteFumeuses,Y_pourEtudeMortaliteFumeuses)\n", "print (\"Modele de Regression Logistique sur le groupe des Fumeuses : score = \",score__SKL_MRL_B)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### * Appliquons le modele de Regression Logistique de 'statsmodels' sur le groupe des Fumeuses :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "MLRavecSM_B = sm.Logit(Y_pourEtudeMortaliteFumeuses, X_pourEtudeMortaliteFumeuses).fit()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "MLRavecSM_B.summary()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### IV - C/ Operons une Regression Logistique sur le groupe des non fumeuses " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "NbDecesChezNonFumeuses = Y_pourEtudeMortaliteNonFumeuses.sum()\n", "print (\"verif : Nbre de deces chez les Non Fumeuses = \",NbDecesChezNonFumeuses,\" VS Nb_NonFumeuses=\",Nb_NonFumeuses)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### * Appliquons le modele de Regression Logistique de 'scikit learn' sur le groupe des Non Fumeuses :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if ( int(NbDecesChezNonFumeuses) == 0 ): # on verifie que Y_pourEtudeMortaliteNonFumeuses contient plus de 1 classe\n", " print (\"Probleme : la somme Y_pourEtudeMortaliteNonFumeuses.sum() devrait être différente de 0 !\")\n", " print (\" les valeurs de Y_pourEtudeMortaliteNonFumeuses ne composent qu'une seule classe !\")\n", "else : # La regression logistique peut être effectuée :\n", " SKL_MRL_C = LogisticRegression(penalty='none',solver='newton-cg')\n", " SKL_MRL_C.fit(X_pourEtudeMortaliteNonFumeuses,Y_pourEtudeMortaliteNonFumeuses)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Si souhaité, afficher dans un DataFrame les coefficients du modèle , avec la constante :\n", "if False :\n", " pd.DataFrame(np.concatenate([SKL_MRL_C.intercept_.reshape(-1,1),\n", " SKL_MRL_C.coef_],axis=1),\n", " index = [\"coef\"],\n", " columns = [\"constante\"]+list(X_pourEtudeMortaliteNonFumeuses.columns)).T" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "score__SKL_MRL_C = SKL_MRL_C.score(X_pourEtudeMortaliteNonFumeuses,Y_pourEtudeMortaliteNonFumeuses)\n", "print (\"Modele de Regression Logistique sur le groupe des Non Fumeuses : score = \",score__SKL_MRL_C)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### * Appliquons le modele de Regression Logistique de 'statsmodels' sur le groupe des Non Fumeuses :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "MLRavecSM_C = sm.Logit(Y_pourEtudeMortaliteNonFumeuses, X_pourEtudeMortaliteNonFumeuses).fit() # en principe \n", "# Mais erreur de type 'Singular Matrix Error' !\n", "# voir https://stackoverflow.com/questions/20703733/logit-regression-and-singular-matrix-error-in-python\n", "# Pour contourner le probleme, soustraction selon l'explication et l'astuce fournie \n", "# MLRavecSM_C = sm.Logit(Y_pourEtudeMortaliteNonFumeuses, X_pourEtudeMortaliteNonFumeuses-1).fit()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "MLRavecSM_C.summary()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### IV - D/ Résumé des essais de régression logistique :" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Construisons un tableau des observations :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tableMRL = {\"Groupes\": ['femmes fumeuses et non', 'femmes fumeuses', 'femmes non fumeuses'],\n", " 'Nb_Vivantes': [Nb_FumeusesVivantes+Nb_NonFumeusesVivantes, Nb_FumeusesVivantes, Nb_NonFumeusesVivantes],\n", " 'Nb_Mortes': [Nb_FumeusesMortes+Nb_NonFumeusesMortes,Nb_FumeusesMortes, Nb_NonFumeusesMortes],\n", " 'Score_Mod.Regr.Logistique':[score__SKL_MRL_A, score__SKL_MRL_B, score__SKL_MRL_C]\n", " }\n", "ResumeMRL = pd.DataFrame(tableMRL, columns=[\"Groupes\", 'Nb_Vivantes','Nb_Mortes','Score_Mod.Regr.Logistique'])\n", "print (ResumeMRL)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Commentons :" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Commençons par rappeler que le même modele de régression logistique (de base mais très classique, sans inclure d'interception avec une constante, issu des librairies \"scikit learn\" d'une part \"statmodels\" d'autre part) a été utilisé pour les 3 types de groupes, en considérant tous ensemble les différents ages (afin de s'affranchir d'un biais induit par des regroupements en tranches d'âges arbitraires et non régulières) ; et que le score reflète la capacité de ce modèle de régression logistique à prédire la mortalité en fonction de l'age.\n", " \n", "De façon différente mais cohérente avec l'utilisation du modele de Regression Logistique issu de la librairie \"scikit learn\", les performances dans l'optimization (fit) du modele de Regression Logistique issu de la librairie \"statmodels\" terminée avec succes sont rappelées ci-dessous pour les 2 groupes traités séparemment :\n", " * Fumeuses : en 7 itérations : valeur de la fonction = 0.412727 , coef de corrl avec Age = -0.0890 , std err = 0.009\n", " * NonFumeuses : en 3 itérations : valeur de la fonction = 0.687904 , coef de corrl avec Age = -0.1073 , std err = 0.008\n", "(remarque : les coefficients de corrélation entre les variables 'Age' et 'Status' sont normalement négatifs car ils reflètent le fait de tendances opposées: l'augmentation de l'age est corrélée avec la diminution des chances d'être en vie : pour l'intensité de la corrélation, il faut donc considérer la valeur absolue de ce coefficient). \n", "\n", "D'ailleurs, les scores 'TRAINING r_score' (cf la partie V) qui refletent les performances dans l'optimization (fit) du modele de Regression Linéaire confirment les observations et interpretations faites avec les essais de Regression Logistique.\n", "\n", "On observe que le score du modèle (autrement dit, la probabilité de décès en fonction de l'âge) pour le groupe des femmes non fumeuses est plus élevé que le score pour le groupe des fumeuses ; \n", "Ceci s'interprete par le fait que, par-rapport aux femmes non fumeuses, les fumeuses ont une probalité plus grande de mourir en raison d'un autre facteur que l'age ; étant donné que dans cette étude , ne sont pris en compte que 2 facteurs explicatifs de la mortalité: le tabagisme et l'age, ces régressions logistiques permettent de conclure sur la nocivité du tabagisme d'une part. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## V - Prolongement avec un essai de Regression Linéaire séparemment sur les 2 groupes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Creation d'une fonction qui pourra etre appelée plusieurs fois : \n", "def buildLinearRegressionModel(X, Y):\n", " # step_2 = build a LinearRegression model on the subset of TRAINING data , and show its performance-score :\n", " from sklearn.linear_model import LinearRegression\n", " linearModel = LinearRegression(normalize=True).fit(X, Y)\n", " linearModel_trainingScore = linearModel.score(X, Y)\n", " print (\"LinearRegressionModel : TRAINING r_score = \",linearModel_trainingScore)\n", "\n", " return (linearModel_trainingScore)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Testons le modele de Regression lineaire 'Statut Vivante_ou_Morte' VS 'Age' chez les Fumeuses :\n", "linearModel_trainingScore = buildLinearRegressionModel(X_pourEtudeMortaliteFumeuses,Y_pourEtudeMortaliteFumeuses)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Testons le modele de Regression lineaire 'Statut Vivante_ou_Morte' VS 'Age' chez les Non Fumeuses:\n", "linearModel_trainingScore = buildLinearRegressionModel(X_pourEtudeMortaliteNonFumeuses,Y_pourEtudeMortaliteNonFumeuses)" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Sans donner d'explication sur la mise en oeuvre de cet autre modèle qui est appliqué à l'identique aux 2 groupes de femmes,\n", "ni sur la qualité toute relative des scores obtenus, \n", "on retrouve l'observation faite précédemment avec la regression logistique : à savoir, la probabilité de décès en fonction de l'âge pour le groupe des femmes non fumeuses est plus élevée que cette probabilité pour le groupe des fumeuses." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.4" } }, "nbformat": 4, "nbformat_minor": 2 }