#+TITLE: Analyse du risque de défaillance des joints toriques de la navette Challenger #+AUTHOR: Arnaud Legrand #+LANGUAGE: fr #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+LATEX_HEADER: \usepackage{a4} #+LATEX_HEADER: \usepackage[french]{babel} # #+PROPERTY: header-args :session :exports both Le 27 Janvier 1986, veille du décollage de la navette /Challenger/, eu lieu une télé-conférence de trois heures entre les ingénieurs de la Morton Thiokol (constructeur d'un des moteurs) et de la NASA. La discussion portait principalement sur les conséquences de la température prévue au moment du décollage de 31°F (juste en dessous de 0°C) sur le succès du vol et en particulier sur la performance des joints toriques utilisés dans les moteurs. En effet, aucun test n'avait été effectué à cette température. L'étude qui suit reprend donc une partie des analyses effectuées cette nuit là et dont l'objectif était d'évaluer l'influence potentielle de la température et de la pression à laquelle sont soumis les joints toriques sur leur probabilité de dysfonctionnement. Pour cela, nous disposons des résultats des expériences réalisées par les ingénieurs de la NASA durant les 6 années précédant le lancement de la navette Challenger. * Chargement des données Nous commençons donc par charger ces données: #+begin_src python :results value :session *python* :exports both import numpy as np import pandas as pd data = pd.read_csv("shuttle.csv") data #+end_src #+RESULTS: #+begin_example Date Count Temperature Pressure Malfunction 0 4/12/81 6 66 50 0 1 11/12/81 6 70 50 1 2 3/22/82 6 69 50 0 3 11/11/82 6 68 50 0 4 4/04/83 6 67 50 0 5 6/18/82 6 72 50 0 6 8/30/83 6 73 100 0 7 11/28/83 6 70 100 0 8 2/03/84 6 57 200 1 9 4/06/84 6 63 200 1 10 8/30/84 6 70 200 1 11 10/05/84 6 78 200 0 12 11/08/84 6 67 200 0 13 1/24/85 6 53 200 2 14 4/12/85 6 67 200 0 15 4/29/85 6 75 200 0 16 6/17/85 6 70 200 0 17 7/29/85 6 81 200 0 18 8/27/85 6 76 200 0 19 10/03/85 6 79 200 0 20 10/30/85 6 75 200 2 21 11/26/85 6 76 200 0 22 1/12/86 6 58 200 1 #+end_example Le jeu de données nous indique la date de l'essai, le nombre de joints toriques mesurés (il y en a 6 sur le lançeur principal), la température (en Fahrenheit) et la pression (en psi), et enfin le nombre de dysfonctionnements relevés. * Inspection graphique des données Très bien, nous avons une variabilité de température importante mais la pression est quasiment toujours égale à 200, ce qui devrait simplifier l'analyse. #+begin_src python :results value :session *python* :exports both data['Pressure'].value_counts() #+end_src #+RESULTS: : 200 15 : 50 6 : 100 2 : Name: Pressure, dtype: int64 Comment la fréquence d'échecs varie-t-elle avec la température ? #+begin_src python :results output file :var matplot_lib_filename="freq_temp_python.png" :exports both :session *python* import matplotlib.pyplot as plt plt.clf() data["Frequency"]=data.Malfunction/data.Count data.plot(x="Temperature",y="Frequency",kind="scatter",ylim=[0,1]) plt.grid(True) plt.savefig(matplot_lib_filename) print(matplot_lib_filename) #+end_src #+RESULTS: [[file:*c* argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with *x* & *y*. Please use the *color* keyword-argument or provide a 2-D array with a single row if you intend to specify the same RGB or RGBA value for all points. freq_temp_python.png]] freq_temp_python.png]] freq_temp_python.png]] À première vue, ce n'est pas flagrant mais bon, essayons quand même d'estimer l'impact de la température $t$ sur la probabilité de dysfonctionnements d'un joint. * Estimation de l'influence de la température Supposons que chacun des 6 joints toriques est endommagé avec la même probabilité et indépendamment des autres et que cette probabilité ne dépend que de la température. Si on note $p(t)$ cette probabilité, le nombre de joints $D$ dysfonctionnant lorsque l'on effectue le vol à température $t$ suit une loi binomiale de paramètre $n=6$ et $p=p(t)$. Pour relier $p(t)$ à $t$, on va donc effectuer une régression logistique. #+begin_src python :results output :session *python* :exports both import statsmodels.api as sm data["Success"]=data.Count-data.Malfunction data["Intercept"]=1 # logit_model=sm.Logit(data["Frequency"],data[["Intercept","Temperature"]]).fit() logmodel=sm.GLM( data['Frequency'], data[['Intercept','Temperature']], family=sm.families.Binomial(), var_weights=data['Count']).fit() print(logmodel.summary()) #+end_src #+RESULTS: #+begin_example Generalized Linear Model Regression Results ============================================================================== Dep. Variable: Frequency No. Observations: 23 Model: GLM Df Residuals: 21 Model Family: Binomial Df Model: 1 Link Function: logit Scale: 1.0000 Method: IRLS Log-Likelihood: -23.526 Date: Thu, 04 Mar 2021 Deviance: 18.086 Time: 15:53:18 Pearson chi2: 30.0 No. Iterations: 6 Covariance Type: nonrobust =============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------- Intercept 5.0850 3.052 1.666 0.096 -0.898 11.068 Temperature -0.1156 0.047 -2.458 0.014 -0.208 -0.023 =============================================================================== #+end_example L'estimateur le plus probable du paramètre de température est -0.1156 et l'erreur standard de cet estimateur est de 0.115 * Estimation de la probabilité de dysfonctionnant des joints toriques La température prévue le jour du décollage est de 31°F. Essayons d'estimer la probabilité de dysfonctionnement des joints toriques à cette température à partir du modèle que nous venons de construire: #+begin_src python :results output file :var matplot_lib_filename="proba_estimate_python.png" :exports both :session *python* import matplotlib.pyplot as plt data_pred = pd.DataFrame({'Temperature': np.linspace(start=30, stop=90, num=121), 'Intercept': 1}) data_pred['Frequency'] = logmodel.predict(data_pred[['Intercept','Temperature']]) data_pred.plot(x="Temperature",y="Frequency",kind="line",ylim=[0,1]) plt.scatter(x=data["Temperature"],y=data["Frequency"]) plt.grid(True) plt.savefig(matplot_lib_filename) print(matplot_lib_filename) #+end_src #+RESULTS: [[file:proba_estimate_python.png]] On voit donc que la température semble avoir un impact direct sur la probabilité d'échec des joints toriques. Utilisons ce modèle pour estimer la probabilité de défaillance des joints toriques dans les conditions du jour J: #+begin_src python :results output file :var matplot_lib_filename="prediction_with_ci.png" :session *python* :exports both import seaborn as sns #data = data.append([{'Temperature': t} for t in np.linspace(start=30, stop=90, num=121)], ignore_index=True) fig = plt.figure() ax = fig.add_subplot(111) sns.set(color_codes=True) ax.set_xlim(30,90) ax.set_ylim(0,1) sns.regplot(x='Temperature', y='Frequency', data=data, logistic=True, ax=ax) plt.savefig(matplot_lib_filename) print(matplot_lib_filename) #+end_src #+RESULTS: [[file:prediction_with_ci.png]] Cette probabilité est donc d'environ $p=1$, le décollage ne doit donc pas avoir lieu demain comme il était prévu. Seulement, le lendemain, la navette Challenger explosera et emportera avec elle ses sept membres d'équipages. L'opinion publique est fortement touchée et lors de l'enquête qui suivra, la fiabilité des joints toriques sera directement mise en cause. Au delà des problèmes de communication interne à la NASA qui sont pour beaucoup dans ce fiasco, l'analyse précédente comporte (au moins) un petit problème... Saurez-vous le trouver ? Vous êtes libre de modifier cette analyse et de regarder ce jeu de données sous tous les angles afin d'expliquer ce qui ne va pas.