Année académique 2024 - 2025 Simulation numérique Classes Préparatoires aux Ecoles d’Ingénieur (CPEI) MP & PC : Semestre 4 Volume horaire : 18 H Cours Théorique: 12 H, TD/TP: 06 H Cours de : Cheick Amed Diloma Gabriel T RAORÉ [email protected] Sommaire I Python pour le calcul numérique 5 1 Manipulez des tableaux avec NumPy 1.1 Différenciez les arrays des listes classiques . . . . . . . . . . . . . . . . . . . 1.1.1 Les arrays NumPy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.2 Créez un array NumPy . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Sélectionnez des éléments au sein d’un array . . . . . . . . . . . . . . . . . . . 1.2.1 Accédez à un seul élément . . . . . . . . . . . . . . . . . . . . . . . . 1.2.2 Accédez à plusieurs éléments contigus . . . . . . . . . . . . . . . . . . 1.2.3 Accédez à plusieurs éléments selon une condition . . . . . . . . . . . . 1.3 Utilisez les méthodes d’array . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 7 9 10 10 10 11 12 2 Transformez vos données en tableaux 2.1 Créez un tableau avec NumPy . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Analogie entre les arrays et les matrices . . . . . . . . . . . . . . . . . . . . . 2.2.1 Définissez des matrices non aléatoire et aléatoire en NumPy . . . . . . 2.2.2 Réalisez des opérations d’algèbre sur des ndarray . . . . . . . . . . . . 2.3 Accéder au éléments d’un ndarray . . . . . . . . . . . . . . . . . . . . . . . . 2.3.1 Accédez à un ou plusieurs éléments d’un ndarray : slicing et conditions imbriquées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3.2 Sélectionnez des éléments au sein d’un ndarray . . . . . . . . . . . . . 2.3.3 Extension de Numpy par SciPy . . . . . . . . . . . . . . . . . . . . . 2.4 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4.1 Exercice d’application de fin de chapitre . . . . . . . . . . . . . . . . . 2.4.2 Exercices complémentaires . . . . . . . . . . . . . . . . . . . . . . . . 14 14 16 17 19 21 21 21 22 23 23 24 3 Créez votre premier data frame avec Pandas 3.1 Générez un data frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Créer votre data frame à partir de fichier(s) préexistant(s) . . . . . . . . 3.1.2 Créer un data frame à partir de données que vous avez . . . . . . . . . 3.2 Identifiez les caractéristiques de votre data frame . . . . . . . . . . . . . . . . 3.2.1 Aperçu du data frame . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.2 Caractéristiques globales d’un data frame . . . . . . . . . . . . . . . . 26 28 28 29 30 30 31 4 Manipulez un data frame 33 i ii 4.1 4.2 4.3 Naviguez dans un data frame . . . . . . . . . . . . . . . . . . . . . . . . . . . Découvrez l’objet Series de Pandas . . . . . . . . . . . . . . . . . . . . . . . . Manipulez les colonnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.1 Modifiez une colonne existante . . . . . . . . . . . . . . . . . . . . . 4.3.2 Créer et supprimez une colonne . . . . . . . . . . . . . . . . . . . . . 4.3.3 Renommez une colonne . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.4 Changez le type d’une colonne . . . . . . . . . . . . . . . . . . . . . . 4.3.5 Triez un data frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 34 36 36 37 38 39 39 5 Filtrez les données du data frame 5.1 Appliquez la sélection via des indices . . . . . . . . . . . . . . . . . . . . . . 5.2 Utilisez la sélection via des conditions . . . . . . . . . . . . . . . . . . . . . . 5.3 Modifiez une sélection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 41 42 45 6 Maîtrisez les bonnes pratiques de la data visualisation 6.1 Importance de la représentation graphique . . . . . . . . . . . . . . . . . . . . 6.2 Identifiez le graphique adapté . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.1 Présentez une évolution dans le temps . . . . . . . . . . . . . . . . . . 6.2.2 Comparez différents groupes . . . . . . . . . . . . . . . . . . . . . . . 6.2.3 Représentez une distribution . . . . . . . . . . . . . . . . . . . . . . . 6.2.4 Représentez la relation entre deux variables numériques . . . . . . . . 6.3 Bonnes pratiques de la visualisation des données . . . . . . . . . . . . . . . . 6.3.1 Privilégiez la simplicité . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3.2 Clarifiez votre graphique . . . . . . . . . . . . . . . . . . . . . . . . . 6.3.3 Choisissez le graphique adéquat . . . . . . . . . . . . . . . . . . . . . 47 47 48 48 49 50 51 51 52 53 54 7 Tracez des graphiques avec Matplotlib 7.1 Découvrez Matplotlib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 Tracez vos premiers graphiques . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2.1 Nuage de points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2.2 Diagramme circulaire . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2.3 Diagramme à barres . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2.4 Histogramme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2.5 Courbes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3 Créez plusieurs graphiques sur une même fenêtre . . . . . . . . . . . . . . . . 7.3.1 Créez plusieurs graphiques dans une figure . . . . . . . . . . . . . . . 7.3.2 Créez plusieurs sous figures dans une même figure : subplot . . . . . . 56 56 56 56 58 59 60 60 62 62 63 8 Personnalisez vos graphiques avec Matplotlib 8.1 Modifiez les éléments extérieurs . . . . . . . . . . . . . . . . . . . . . . . . . 8.2 Modifiez les éléments intérieurs . . . . . . . . . . . . . . . . . . . . . . . . . 65 65 67 II Calcul numérique 69 9 Calcul numérique approché 9.1 Erreurs absolue et relative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.1.1 Erreur absolue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.1.2 Erreur relative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.2 Incertitudes absolue et relative . . . . . . . . . . . . . . . . . . . . . . . . . . 9.3 Représentation décimale d’un nombre approché . . . . . . . . . . . . . . . . . 70 70 70 70 71 71 iii 9.3.1 Représentation décimale d’un nombre approché . . . . . . . . . . . . . Chiffres significatifs exacts d’un nombre approché . . . . . . . . . . . . . . . Troncature et arrondissement d’un nombre . . . . . . . . . . . . . . . . . . . . Exercices d’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 73 73 74 10 Equations non linéaires 10.1 Racines d’équations non linéaires . . . . . . . . . . . . . . . . . . . . . . . . 10.1.1 Séparation des racines . . . . . . . . . . . . . . . . . . . . . . . . . . 10.1.2 Méthode graphique . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.1.3 Méthode de balayage . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.2 Approximation des racines : Méthodes itératives . . . . . . . . . . . . . . . . . 10.2.1 Méthode de Newton-Raphson . . . . . . . . . . . . . . . . . . . . . . 10.2.2 Convergence de la méthode de Newton Raphson . . . . . . . . . . . . 75 75 75 75 76 77 77 79 11 Dérivation et intégration numérique 82 12 Equations différentielles ordinaires 83 Bibliographie 84 9.4 9.5 9.6 Introduction et installation de l'environnement de simulation La simulation numérique, ou plus largement le calcul numérique, est un domaine des mathématiques appliquées qui se concentre sur l’utilisation d’algorithmes et de méthodes numériques pour résoudre des problèmes mathématiques difficilement résolubles à la main. Ces problèmes, souvent impossibles ou très difficiles à résoudre analytiquement, impliquent généralement des équations différentielles, des intégrales ou des systèmes d’équations non linéaires. Le calcul numérique repose sur des approximations et des simulations permettant de fournir des solutions pratiques, même si elles ne sont pas exactes. Pourquoi l'enseigner ? Le calcul numérique est une passerelle entre la théorie mathématique et le monde réel. L’enseigner permet de doter les étudiants d’outils et de compétences nécessaires pour relever les défis scientifiques et technologiques modernes. Ci-dessous nous énumérons quelques raisons d’enseigner les simulations numériques. Résolution de problèmes complexes Dans de nombreux domaines scientifiques et d’ingénierie, les problèmes réels sont souvent trop compliqués pour être résolus de manière exacte. Les méthodes numériques offrent une solution efficace et pragmatique pour relever ces défis. Applications interdisciplinaires Le calcul numérique est essentiel dans diverses disciplines, notamment la physique, la chimie, la biologie, l’économie, la finance, la sociologie et l’intelligence artificielle. Il permet de modéliser des phénomènes naturels, de prévoir des comportements ou d’optimiser des systèmes. 1 2 Développement des compétences techniques Enseigner le calcul numérique initie les étudiants à l’utilisation d’outils modernes tels que les logiciels de programmation, les bibliothèques numériques et les plateformes de simulation, devenus indispensables dans le monde professionnel. Approche pratique des mathématiques Contrairement aux mathématiques purement théoriques, le calcul numérique met l’accent sur l’application pratique des concepts, ce qui motive et engage davantage les apprenants. Formation à la pensée algorithmique Les étudiants apprennent à décomposer des problèmes complexes en étapes claires et à concevoir des solutions précises, des compétences précieuses dans des domaines tels que l’informatique et la gestion de projets. À propos de ce cours Ce cours est destiné aux étudiants de 2ème année des classes préparatoires de l’École Polytechnique de Ouagadougou (EPO). Son objectif principal est de fournir une variété d’outils numériques permettant de résoudre efficacement un large éventail de problèmes scientifiques. Grâce à une approche pédagogique combinant Cours Magistraux (CM), Travaux Dirigés (TD) et Travaux Pratiques (TP), les étudiants développeront des compétences pratiques et théoriques adaptées aux défis scientifiques modernes. Pour rendre l’apprentissage concret et accessible, chaque chapitre du cours sera accompagné d’exemples illustratifs et d’une série d’exercices. Ces activités renforceront leur compréhension et faciliteront l’application des techniques enseignées. Prérequis Une bonne maîtrise des concepts fondamentaux suivants est indispensable : équations différentielles, méthodes d’intégration, algèbre linéaire. Objectifs pédagogiques Au terme du cours, l’apprenant devra être capable de : • développer une expertise dans l’utilisation de bibliothèques Python spécialisées, notamment numpy, scipy, matplotlib et pandas ; • acquérir des compétences pratiques pour résoudre des problèmes scientifiques complexes grâce aux techniques de simulation numérique ; • maîtriser la visualisation et l’analyse des données à l’aide d’outils graphiques. 3 Évaluation Le cours sera évalué à travers un devoir sur table et un TP, permettant de valider les acquis théoriques et pratiques. Instructions pour les travaux de laboratoire (simulation) Mise en place de l'environnement de travail Mise en place : Nous utiliserons des Notebooks (bloc-notes) Jupyter avec un noyau Python pour le travail de laboratoire (simulation). Cela signifie que vous devez installer Python (version 3.12 ou supérieure) sur votre ordinateur et installer une application Jupyter Notebooks 1 . Pour travailler sur les tâches de programmation, vous devez installer les paquets Python suivants : numpy, scipy, seaborn, pandas et matplotlib. Ceux qui souhaite se familiariser avec jupyter notebook peuvent suivre la vidéo : https://youtu.be/-QVRPvuq9LM?si=iaCn0qxiZsjwzKll. Remarque 0.1 (Aide : installer jupyter notebook en ligne de commande). Pour installer jupyter notebook en ligne de commande, vous pouvez suivre les instruction suivante : 1. Ouvrez l’invite de commandes : appuyez sur la touche Windows, tapez « cmd » et appuyez sur Entrée. 2. Installez Jupyter Notebook : dans l’invite de commandes, tapez la commande suivante et appuyez sur Entrée : pip install jupyter notebook 3. Lancez Jupyter Notebook : une fois l’installation terminée, tapez la commande suivante et appuyez sur Entrée : jupyter notebook Jupyter Notebook s’ouvrira dans votre navigateur web par défaut. Si vous avez un message d’erreur (peut-être parce que vous avez anaconda sur votre machine), utilisez la commande : python -m notebook Un des atouts majeurs du notebook réside dans sa capacité à combiner code et texte. En effet, il permet non seulement de programmer, mais aussi de rédiger du texte enrichi grâce au langage de formatage Markdown. Voici ci-dessous quelques exemples d’instructions en Markdown. 1. en ligne de commande https://www.pythoniaformation.com/blog/articles-sur-python/ tutoriels-installation-python/installer-jupyter-notebook ; https://jupyter.org/install ou via anaconda : https://www.anaconda.com/download (suivez les liens en pied de page. Bien que vous ayez deux possibilités pour installer jupyter notebook, je vous recommande d’utiliser la ligne de commande). Si vous avez besoin d’aide suivez la vidéo : https://www.youtube.com/watch?v=HLD-Ll_-IT4 4 Aide-mémoire Markdown Un titre de niveau 1 : # Titre Un titre de niveau 2 : ## Subtitle Un titre de niveau 3 : ### Sous-soustitre Texte en gras: **bold text** Texte en italique: *italic text* Une formule mathématique: Pythagoras' theorem is $a^2+b^2=c^2$. Une liste ordonée: 1. First item 2. Second item 3. Third item Une liste non ordonnée: * First item * Second item * Third item Tâches Les travaux pratiques sont destinés à compléter les cours magistraux et à vous faire appliquer la théorie que vous avez apprise dans les cours magistraux. Les exercices seront résolus à la fois avec du papier-crayon (pour la formulation mathématiques et les preuves analytiques) et de la programmation (pour la simulation). Conclusion Nous espérons que ce programme vous enthousiasmera et vous donnera les outils nécessaires pour aborder les défis scientifiques de manière innovante et efficace ! Première partie Python pour le calcul numérique 5 6 Bonjour et bienvenue dans cette partie consacrée aux librairies Python pour la Data Science, plus précisément pour le calcul numérique. Dans cette partie, vous allez découvrir les bonnes pratiques et les connaissances fondamentales qui vous aideront à effectuer vos analyses de données ou calculs scientifiques à l’aide de librairies Python. Vous verrez comment utiliser des librairies Python comme NumPy, Pandas, Matplotlib ou encore Seaborn pour explorer vos données et les analyser. D’autre part pour sauvegarder ou présenter vos résultats( sous forme de graphiques). À l’issue de cette partie, vous saurez : • manipuler des tableaux avec NumPy ; • créer des data frames avec Pandas ; • construire des data visualisations avec Matplotlib et Seaborn. Python possède de nombreuses librairies, utilisées dans tous les domaines. Pour pouvoir traiter une grande quantité de données, il est essentiel d’observer quelques règles de base, que vous allez découvrir dans ce cours. Dans la première partie, vous prendrez en main NumPy à travers la création d’arrays et de tableaux de données. Ensuite, dans la seconde partie du cours, vous créerez vos premiers data frames grâce à Pandas, et vous les manipulerez grâce à différentes fonctions. Pour finir, dans le dernier chapitre, vous construirez des data visualisations grâce aux librairies Matplotlib et Seaborn. Contexte du travail pratique : des données réelles sur le revenu Tout au long du cours de cette partie, vous allez vous mettre dans la peau d’une personne travaillant dans un service data au sein d’une banque. Plus précisément, vous travaillez pour la filière gérant les différents prêts. L’objectif sera d’utiliser les connaissances acquises sur les librairies Python pour aider l’agence dans différentes tâches. Les exercices de fin de chapitres pourront porter sur d’autres thématiques. Pour ce faire, vous pourrez pratiquer dans des notebooks créés pour l’occasion. Afin de trouver les solutions justes, je vous recommande : 1. raisonner sur des feuilles de papier ; 2. résoudre mathématiquement les exercices sur vos feuilles ; 3. traduire vous solutions en algorithmes ; 4. simuler vos algorithmes c’est-à-dire traduire vos algorithmes en Python. Dans cette première partie du cours, nous nous appuierons sur des fondations solides, largement inspirées par les éclairages pertinents et la structure pédagogique du remarquable travail de Benjamin Marlé et Nicolas Rangeon pour openclassroom.com. Leur approche constitue une base précieuse pour appréhender ces concepts initiaux. 1 Manipulez des tableaux avec NumPy Les Data Analysts, les Data Scientists ou Mathématiciens ont au quotidien à manipuler des données en grande quantité et de sources très variées. Celles-ci sont généralement représentées sous la forme de listes ou tableaux de nombres. Cependant, les objets natifs de Python sont assez limités pour les manipuler correctement. Considérons par exemple la liste suivante, représentant le revenu mensuel de cinq clients de notre banque : revenus = [1800, 1500, 2200, 3000, 2172] Si on souhaite calculer la moyenne des éléments de cette liste, il n’y a pas de fonction Python existante par défaut permettant de le faire : il faudrait la recoder soi-même ! C’est encore plus compliqué si on souhaite avoir une information plus spécifique, comme la médiane. C’est là que la librairie NumPy intervient ! Diminutif de Numerical Python, Numpy elle fournit un ensemble de fonctions pour effectuer efficacement des opérations sur les données, mais propose également un objet qui est au cœur de presque tout l’écosystème data en Python : l’array. Découvrons un peu plus en détail cette librairie, et pourquoi elle est aussi réputée dans l’environnement data Python aujourd’hui ! Remarque 1.1. Si Numpy n’est pas installé dans votre ordinateur, vous pouvez l’intaller en ligne de commande via l’instruction : pip install numpy . 1.1 Diérenciez les arrays des listes classiques 1.1.1 Les arrays NumPy Le tableau NumPy, ou array, en anglais, est d’une certaine manière similaire à une liste Python. Quel est son avantage ? Il permet d’effectuer simplement et rapidement de nombreuses opérations complexes telle que celles d’algèbre linéaire, en plus de faciliter le stockage et la 7 1.1. DIFFÉRENCIEZ LES ARRAYS DES LISTES CLASSIQUES 8 manipulation des données. Reprenons notre exemple de calcul de la moyenne présenté ci-dessus. Dans les faits, la fonction n’est pas très complexe. Elle pourrait s’écrire : def moyenne(liste): return sum(liste)/len(liste) moyenne(revenus) # => 2134.4 Mais NumPy donne directement accès à une fonction existante. import numpy as np # importation de la librairie Numpy np.mean(revenus) # calcul de la moyenne de la liste revenus OK ça a l’air bien ... mais je ne vois pas non plus la révolution annoncée ? C’est tout à fait logique, car la vraie révolution vient avec les arrays NumPy ! On estime qu’à mesure que la taille du tableau augmente, des opérations via array NumPy deviennent environ 30 fois plus rapides que via une liste Python classique. Cette différence aussi importante s’explique par le fait que les arrays NumPy ne peuvent contenir qu’un seul et même type. En effet, contrairement à une liste classique où l’on peut stocker tous types d’objets, NumPy n’acceptera qu’un seul type en entrée. De plus, NumPy donne également accès à de nombreuses autres fonctions mathématiques indispensables, applicables à des arrays ou même à des listes : Quelques fonctions accéssibles grâce à NumPy x = [-2, -1, 1, 2] print("La valeur absolue: ", np.abs(x)) print("Exponentielle: ", np.exp(x)) print("Logarithme: ", np.log(np.abs(x))) Il existe encore de nombreuses autres fonctions, que je vous invite à découvrir dans la documentation de NumPy. A présent, allons créer notre premier array. 0. Le lien est : https://docs.scipy.org/doc/numpy-1.13.0/user/index.html 1.1. DIFFÉRENCIEZ LES ARRAYS DES LISTES CLASSIQUES 9 1.1.2 Créez un array NumPy Vous pouvez créer un array de différentes façons, mais la plus simple est de le faire ... à partir d’une liste Python classique : Création d’une liste array revenus_array = np.array(revenus) revenus_array # array([1800, 1500, 2200, 3000, 2172]) Remarque 1.2. Dans un array : • Si dans la liste de départ il y a des données de types différents, NumPy essaiera de tous les convertir au type le plus général. Par exemple, si un tableau contient des entiers (int) et des nombres décimaux (float), tous ses éléments seront convertis en nombres décimaux (float) ; • vous pouvez accéder au type des éléments d’un array via la méthode .dtype. Type des éléments d’un array revenus_array.dtype # dtype('int32') Les types en NumPy seront toujours présentés via deux informations : • le type (ici int) ; • la précision (ici 32). Cette dernière correspond au nombre de bits sur lesquels sont codés les nombres, définissant ainsi les différentes valeurs possibles. Par exemple, un int8 (entier codé sur 8 bits) pourra prendre des valeurs de -128 à 127 ! Pour plus d’informations sur les types NumPy, consultez la page Data types de la documentation officielle. https://numpy.org/doc/stable/user/basics.types.html Il existe également des fonctions NumPy permettant de créer des arrays selon un certain pattern ou une spécification particulière. Les plus couramment utilisées sont : np.zeros(n) : permet de créer un array de n éléments contenant que des 0 ; np.ones(n) : permet de créer un array de n éléments contenant que des 1 ; np.arange(i, j, p) : permet de créer un array rempli avec une séquence linéaire, qui ira de i à j, par pas de p ; np.linspace(i, j, n) : permet de créer un array de n valeurs espacées uniformément entre i et j. Voyons à présent comment sélectionner des éléments au sein d’un array NumPy. 1.2. SÉLECTIONNEZ DES ÉLÉMENTS AU SEIN D’UN ARRAY 10 1.2 Sélectionnez des éléments au sein d'un array Comment accéder à un ou plusieurs éléments d’un array ? Tout comme avec une liste classique, nous pouvons faire cela via l’indice de ces derniers. 1.2.1 Accédez à un seul élément L’accès à un élément spécifique d’un array se fait via la syntaxe : nom_array[indice]. Accédez à un élément d’un array ou modifiez sa valeur revenus_array[4] # pour accéder au 5ème élement revenus_array[-1] # pour accéder au dernier élément revenus_array[1] = 1900 # pour modifier la valeur du 2ème élément 1.2.2 Accédez à plusieurs éléments contigus Nous pouvons accéder à un ensemble d’éléments contigus en combinant [] et :. La syntaxe suit une règle simple : nom_array[i:j:p], avec : • i : l’indice du début ; • j : l’indice de fin ; • p : le pas. permettant de sélectionner tous les éléments compris entre l’indice i inclus, jusqu’à j-1, l’élément d’indice j est exclu. La ligne : revenus_array[0:3] permet de sélectionner, au sein de notre array revenus_array, l’ensemble des éléments de l’indice 0 (soit le premier élément) jusqu’à celui d’indice 2 (soit le troisième). L’élément d’indice 3 n’est pas inclus ! Si vous souhaitez également le sélectionner, il faudra ajouter 1 à l’indice de fin : revenus_array[0:4]. Remarque 1.3. Lors d’un slicing, le début peut être omis si on veut commencer au début de la liste (c’est-à-dire si début = 0). La fin peut être omise si on veut aller jusqu’au bout de la liste (c’est-à-dire fin = -1 ou fin = len(liste)). Le pas, ainsi que le dernier :, peuvent être omis si le pas est de 1 (-1 si la fin est inférieure au début). Slicing print(revenus_array[:3]) # Les 3 premiers éléments (de l'indice 0 à 2) print(revenus_array[2:]) # Les éléments à partir de l'indice 2 print(revenus_array[::2]) # Un élément sur deux Si le pas est négatif, le début et la fin du slice sont inversés. On peut utiliser cette propriété 1.2. SÉLECTIONNEZ DES ÉLÉMENTS AU SEIN D’UN ARRAY 11 pour inverser un tableau. Par exemple, l’instruction : revenus_array[::-1] inverse notre tableau. 1.2.3 Accédez à plusieurs éléments selon une condition On peut aller plus loin dans l’accès aux différents éléments. En effet, lors d’une étude de données ou de calculs mathématiques on est régulièrement amené à devoir sélectionner une partie de nos données, selon un critère (ex. un genre spécifique) ou une condition (ex. toutes les personnes en dessous d’un certain âge). Les arrays NumPy permettent de faire cela ! En effet, de la même façon qu’il est possible de sélectionner des éléments via leur indice, il est possible avec les arrays NumPy de renseigner la condition selon laquelle on souhaite sélectionner les éléments du tableau, avec l’écriture nom_array[condition de sélection]. Voilà par exemple comment sélectionner uniquement les valeurs supérieures à 2 000 : Sélection conditionnelle d’éléments d’un array revenus_array[revenus_array > 2000] # array([2200, 3000, 2172]) Détaillons le fonctionnement de ce processus de sélection : • Tout d’abord, on cite explicitement le nom de l’array avant les crochets, pour spécifier dans quel array on souhaite effectuer la sélection ; • Ensuite, on spécifie à l’intérieur des crochets la condition. Le résultat de ce qui est à l’intérieur des crochets doit forcément être un array ou une liste de booléens ! Ici, si on exécute uniquement la condition : revenus_array > 2 000. Vous verrez que vous aurez simplement un array contenant uniquement des booléens, avec True lorsque la valeur satisfait la condition, False sinon. Remarque 1.4. On pourrait naïvement exécuter revenus_array[ > 2000] en pensant que Python comprendra qu’on souhaite appliquer la condition à l’array qui est cité juste avant. Le résultat sera une erreur. Il faut bien considérer que l’array dans lequel on sélectionne, et la condition à appliquer, sont deux choses différentes. Même si cela concerne le même array, il est nécessaire de le spécifier également dans la condition ! Il est naturellement possible de complexifier cela, avec plusieurs conditions : Sélection conditionnelle imbriquée d’élément d’un array revenus_array[(revenus_array > 2000) & (revenus_array < 3000)] # array([2200, 2172]) Le et logique (respectivement ou logique) n’est pas matérialisé par le mot clé and (respectivement or) comme dans une structure conditionnelle if classique, mais par le symbole & (respectivement |). De plus, chaque condition doit être absolument délimitée par des parenthèses, sous peine de rencontrer une erreur. Cette écriture s’explique par le fait qu’on ne 1.3. UTILISEZ LES MÉTHODES D’ARRAY 12 compare pas des booléens, mais des arrays de booléens, terme à terme. Remarque 1.5. La syntaxe de sélection conditionnelle imbriquée ne permet pas uniquement de sélectionner des éléments, mais qu’elle peut également être utilisée pour modifier des éléments au sein d’un array. En effet, si vous exécutez : • revenus_array[3] = 1790, cela signifie que vous remplacez le 4e élément de notre array par 1790 ; • revenus_array[revenus_array > 2000] = 0, vous remplacerez tous les éléments supérieurs à 2000 au sein de notre array par 0. Il faut donc être vigilant en utilisant cette syntaxe, pour ne pas remplacer des valeurs qu’il n’aurait pas été souhaitable de remplacer. Découvrons à présent, quelques-unes des nombreuses méthodes applicables à des arrays. 1.3 Utilisez les méthodes d'array Nous avons d’ores et déjà vu comment obtenir le type d’un array à partir de la méthode .dtype. De la même façon, on peut accéder facilement aux dimensions de notre array via la méthode : .shape. Taille d’une liste array revenus_array.shape # (5,) on a array contenant 5 éléments Le résultat nous indique qu’on a un array contenant 5 éléments (nous verrons ultérieurement la raison de la virgule après le 5). Aux arrays, on peut également appliquer de nombreuses opérations mathématiques grâce à des fonctions intégrées (dont certaines sont programmées par des scientifiques comme vous et moi). Quelques fonctions intégrées de NumPy applicable à une liste array # calculer la moyenne revenus_array.mean() # calculer le maximum (ou le minimum) : revenus_array.max() revenus_array.min() # accéder à l'indice de l'élement minimum (ou maximum) : revenus_array.argmin() revenus_array.argmax() 1.3. UTILISEZ LES MÉTHODES D’ARRAY 13 # ordonner (trier) par ordre croissant : revenus_array.sort() print(revenus_array) # calculer la somme : revenus_array.sum() Cette liste est naturellement non exhaustive ! Vous pouvez trouver la liste de l’ensemble des méthodes applicables à un array directement dans la documentation officielle. Exercice d’application 1.1 (Consignes). Pour cette première tâche, nous avons à notre disposition les revenus de 10 clients de notre banque. Vous aurez à utiliser les différentes manipulations présentées dans ce chapitre pour sélectionner certains revenus selon une condition spécifique, et effectuer diverses opérations. Je vous invite à lire le notebook préparé à cet effet et a compléter les portions de code dans les cellules correspondantes. Ce notebook est disponible au lien : https: // colab. research. google. com/ drive/ 1R2-Yjt-yGiSb5QL9BTjK6eH8kAAAGyJ2? usp= sharing 2 Transformez vos données en tableaux 2.1 Créez un tableau avec NumPy Jusque-là, nous n’avons vu que des tableaux/arrays à une dimension, mais on ne travaille que très rarement avec une seule colonne 1 . Prenons un exemple : vous travaillez dans le milieu bancaire et vous avez besoin de créer un tableau où vous retrouveriez, en plus des revenus de vos clients, leurs mensualités de remboursement de prêt, le nombre d’enfants à charge, et toute autre information susceptible de vous être utile. Considérons les clients suivants : • Hugo, un jeune homme de 21 ans, gagnant 1 400 par mois et n’ayant aucun enfant ; • Richard, un homme de 54 ans, gagnant 2800 par mois et ayant 2 enfants ; • Émilie, une femme de 27 ans gagnant 3 700 et ayant 3 enfants. Nos données peuvent être représentées via ce tableau : Nom Âge Revenus Nombre d’enfants Hugo 21 1400 0 Richard 54 2800 2 Émilie 27 3700 3 Et voici comment pourrait se matérialiser ce tableau en Python, en utilisant des listes : Créer un tableau en Python hugo = [21, 1400, 0] richard = [54, 2800, 2] emilie = [27, 3700, 3] tableau = [hugo, richard, emilie] print(tableau) # afin d'afficher le tableau 1. Notons que la dimension d’un tableau réfère principalement au nombre de colonnes du tableau. En effet, les variables que nous étudions ou créons au besoin sont principalement stockées dans les colonnes des tableaux. 14 2.1. CRÉEZ UN TABLEAU AVEC NUMPY 15 Décortiquons cela ensemble : • Dans un premier temps, nous créons une liste pour chaque personne dans notre banque, contenant l’ensemble des informations à disposition sur cette personne ; • Enfin, nous créons une liste tableau dans laquelle nous stockons l’ensemble des différentes listes créées précédemment. La liste tableau contient donc 3 éléments, qui sont eux-mêmes des listes de 3 éléments : c’est donc une liste de listes. Nous avons néanmoins toujours l’ensemble des limitations liées aux listes, avec cette façon de faire. Comment pourrions-nous faire alors ? Vous vous en doutez très certainement, mais oui, encore une fois la réponse se trouve du côté de NumPy et des arrays ! En effet, un array est un objet multidimensionnel, c’est-à-dire qu’il est possible de créer des arrays de toutes dimensions, et que l’ensemble des méthodes d’array prennent en compte ce côté multidimensionnel. La façon la plus simple de créer un tableau est de le faire à partir d’une liste de listes Python, comme avec une liste classique. Il suffira d’exécuter np.array(tableau) pour transformer notre liste de listes en array NumPy de 3 lignes et 3 colonnes. Voyons quelques autres exemples ensemble pour bien comprendre cette notion : Créer un tableau d’array avec NumPy tab1 = np.array([[1, 2], [3, 4], [5, 6]]) tab2 = np.array([[1, 2, 3], [4, 5, 6]]) Ces quelques lignes de code permettent de créer : • un array tab1 de 3 lignes et 2 colonnes ; • et un array tab2 de 2 lignes et 3 colonnes. Remarque 2.1. Il est possible de créer des tableaux de plus de 2 dimensions. Par exemple, pour un tableau en 3D il suffira d’utiliser une liste de listes de listes. Voyons quelques autres exemples ensemble pour bien comprendre cette notion : Créer un tableau d’array avec NumPy matrix_3D = np.array([ [[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]] ]) matrix.shape # nous donne les dimensions (axes de la matrice) 2.2. ANALOGIE ENTRE LES ARRAYS ET LES MATRICES 16 Dans NumPy, chaque dimension d’un tableau est appelée un axe. La matrice que vous avez vue précédemment possède trois axes. Les tableaux à trois axes sont également appelés tableaux tridimensionnels (3D). Pour accéder à un élément du tableau ci-dessus, vous devez fournir trois indices : # Accéder à l'élément à la position (3,4) de la première dimension matrix[0][2][3] # ou matrix[0, 2, 3] Exercice 2.1. Créer un tableau NumPy de dimension 3 contenant 2 ligne et 4 colonnes. Vous pouvez remplir le tableau avec n’importe quel nombre. Comme précédemment, nous pouvons également utiliser des fonctions NumPy pour créer des tableaux plus ou moins complexes. Voici quelques exemples de fonctions couramment utilisées : Quelques ndarray particuliers # un tableau de nxp rempli de 1 np.ones((n, p)) # un tableau de n lignes et de p colonnes contenant que des 0 np.zeros((n, p)) # une matrice identité de taille nxn np.eye(n) # matrice diagonale comportant les éléments: [1, 2, 3, 4] np.diag([1, 2, 3, 4]) # un tableau de nxp rempli de valeurs aléatoires comprises entre 0 et 1 np.random.random((n, p)) Reprenez ces fonctions et exécuter les dans votre propre environnement en changeant certaines valeurs, pour bien appréhender leur fonctionnement. 2.2 Analogie entre les arrays et les matrices Vous vous souvenez que j’ai évoqué le fait que NumPy était une librairie Python dessinée pour les calculs scientifiques ? Les tableaux que nous avons vus ensemble jusqu’ici, matérialisés par des arrays NumPy, portent le nom de matrices, en mathématiques. Le but premier de NumPy, avant même toutes ses applications dans le domaine de la data, est de proposer des outils pour manipuler ces matrices et effectuer ce qu’on appelle des calculs matriciels. 2.2. ANALOGIE ENTRE LES ARRAYS ET LES MATRICES 17 Remarque 2.2. Les matrices sont une composante essentielle de l’algèbre linéaire. Vous allez forcément être amené à croiser à nouveau leur chemin si vous poursuivez dans l’analyse de données ou le calcul numérique, car elles sont la base même de nombreuses méthodes de modélisation. 2.2.1 Dénissez des matrices non aléatoire et aléatoire en NumPy En NumPy une matrice est un array d’array c’est-à-dire un tableau de tableau ou un vecteur de vecteur. Considérons les matrices A et B suivantes : " # " # 1 2 5 10 A= , B= . 3 4 215 20 Matrices non aléatoires en NumPy A = np.array([[1, 2], [3, 4]]) B = np.array([[5, 10], [15, 20]]) On peut également définir une matrice selon des conditions sur ces vecteurs. Matrices non aléatoires en NumPy espacée selon un nombre de points connus num_points = 1000 D = np.array([np.linspace(-100, 150, num_points) for i in range(3)]) display(D) # print(D) marche également mais est moins esthétique Explication du code : • Définition du nombre de points : num_points = 1 000 définit le nombre de points dans chaque ligne du tableau. Ici, nous avons choisi 1 000 points. • np.linspace(-100, 100, num_points) génère une séquence de num_points valeurs uniformément espacées entre −100 et 100. [np.linspace(-100, 150, num_points) pour i in range(3)] crée une liste de trois lignes, chacune contenant num_points valeurs. • np.array(...) convertit cette liste en un tableau NumPy. • Affichage du tableau : print(D) affiche le tableau D afin qu’on vérifie si l’on a ce que l’on veut. En résumé, ce code crée un tableau NumPy de trois lignes, chaque ligne contenant 1 000 points uniformément espacés entre −100 et 150, puis affiche ce tableau. 2.2. ANALOGIE ENTRE LES ARRAYS ET LES MATRICES 18 Matrices non aléatoires en NumPy espacée selon un pas # Pas entre les points step = 0.5 # Par exemple, un pas de 0.5 # Créer les points en utilisant np.arange pour un espacement spécifique E = np.array([np.arange(-100, 100 + step, step) pour i in range(4)]) display(E) Explication du code : 1. Définition du pas : step = 0.5 définit le pas entre chaque point. Vous pouvez ajuster cette valeur selon vos besoins. 2. Création du tableau avec un espacement spécifique : • E = np.array([np.arange(-100, 100 + step, step) pour i in range(3)]) crée un tableau NumPy. • np.arange(-100, 100 + step, step) génère une séquence de valeurs allant de -100 à 100 (inclus) avec un espacement de step. • [np.arange(-100, 100 + step, step) pour i in range(3)] crée une liste de trois lignes, chacune contenant des valeurs espacées selon step. • np.array(...) convertit cette liste en un tableau NumPy. Remarque 2.3. En Numpy, les vecteurs des matrices sont des vecteurs lignes. Ainsi lors de la définition de matrice, il faudra avoir en tête que, par défaut, les vecteurs sont ajoutés ligne après ligne. Une matrice aléatoire est une matrice dont les cellules contiennent des valeurs aléatoires. En Numpy, une matrice aléatoire peut-être vue comme un vecteur de vecteur(s) aléatoire(s). Matrices aléatoires en NumPy # matrice 3x3 avec des valeurs suivant une distribution exponentielle S = np.random.exponential(scale=1.0, size=(3, 3)) # matrice 4x4 avec des valeurs suivant une distribution binomiale (nombre # de succès pour 10 essais avec une probabilité de succès de 0.5). T = np.random.binomial(n=10, p=0.5, size=(4, 4)) # matrice aléatoire 3x3 dont chaque cellule contient un élément # sélectionné aléatoirement dans la liste [1, 2, 3, 4, 5] U = np.random.choice([1, 2, 3, 4, 5], size=(7, 7)) # matrice 4x5 avec des valeurs aléatoires entières sur [0,10[ 2.2. ANALOGIE ENTRE LES ARRAYS ET LES MATRICES 19 V = np.random.randint(0, 10, size=(4, 5)) # matrice aléatoire de 3 lignes 2 colonnes suivant la loi uniforme sur [0,1[ W=np.random.rand(0, 10, size=(3,2)) # matrice aléatoire de 3 lignes 2 colonnes suivant la loi uniforme sur [0,10] X = np.random.uniforme(0, 10, size=(3,3)) # matrice aléatoire 5x6 suivant une distribution normale de moyenne 4, # d'écart type 0.75 Y = np.random.normal(4, 0.75, size=(5,6)) # matrice aléatoire 4x5 suivant une distribution de Poisson de paramètre 2.1 Z = np.random.poisson(2.1, size=(4,5)) Ces fonctions de génération de matrices aléatoires ne sont pas exhaustives, il en existe d’autres ! ! ! 2.2.2 Réalisez des opérations d'algèbre sur des ndarray Considérons les matrices A, B et C suivantes : " # 1 2 A= , 3 4 " # 5 10 B= , 215 20 " # 2 4 6 C= . 8 10 12 La méthode .shape() qui retourne le couple (n, m) correspondant au format de la matrice. Format de matrice (array) A.shape B.shape C.shape La méthode .reshape() permet de modifier le format d’une matrice tout en conservant tous les éléments de la matrice. Par exemple : A.reshape(1,4) . Comme elles sont de même dimension (même nombre de lignes et de colonnes), on peut calculer la somme (ou la différence) de la matrice A et de la matrice B, en additionnant terme à terme chaque élément : " # " # 1 + 5 2 + 10 6 12 A+B = = . 3 + 15 4 + 20 18 24 2.2. ANALOGIE ENTRE LES ARRAYS ET LES MATRICES 20 Addition et soustraction terme à terme de matrices A+B A-B Il est également possible de faire une multiplication terme à terme via l’opérateur *, comme avec une multiplication normale : A*B, cela s’appelle la multiplication élément par élément. Cependant, lorsqu’on effectue des calculs matriciels, on utilise beaucoup plus ce qu’on appelle le produit matriciel. C’est un calcul assez fastidieux à faire à la main –d’autant plus avec des matrices de grande dimension– mais qu’un ordinateur n’a en revanche aucun problème à réaliser. Avec NumPy, le produit matriciel se fait via l’opérateur @ : A @ C. Cependant, cet opérateur n’est disponible que depuis Python 3.5. Avant cela, le produit matriciel se faisait via la fonction dot de NumPy : AC = np.dot(A, C). Cette dernière fonctionne toujours aujourd’hui, les deux syntaxes sont donc possibles ! Dans NumPy, il existe une bibliothèque dédiée à l’algèbre linéaire et à la résolution matricielle de problèmes mathématiques. Cette sous-bibliothèque s’appelle numpy.linalg. Pour l’importer, il suffit d’ajouter l’une des instructions suivante : import numpy.linalg as linalg from numpy import linalg Ci-dessous quelques instructions Numpy permettant de faire de l’algèbre linéaire. Quelques opérations d’algèbre linéaire avec des array # Transposé d'une matrice G = np.transpose(A) print("Transposée de A:\n", G) # déterminant d'une matrice det_A = linalg.det(A) print("Déterminant de A:", det_A) # calcul du l'inverse d'une matrice inv_A = linalg.inv(A) print("Inverse de A:\n", inv_A) # valeurs propres et vecteurs propres eigenvalues, eigenvectors = linalg.eig(A) display("Valeurs propres de A:", eigenvalues) print("Vecteurs propres de A:\n", eigenvectors) 2.3. ACCÉDER AU ÉLÉMENTS D’UN NDARRAY 21 2.3 Accéder au éléments d'un ndarray Vous vous souvenez lorsque je vous ai dit que l’ensemble des méthodes d’array prenaient en compte l’aspect multidimensionnel des arrays ? Je vous propose d’approfondir cela ensemble dans les lignes ci-dessous. Nous verrons notamment : • comment modifier un array existant ; • comment accéder aux différents éléments d’un array via leurs indices ; • quelques méthodes qui sauront se montrer utiles lors de calculs scientifiques. 2.3.1 Accédez à un ou plusieurs éléments d'un ndarray : slicing et conditions imbriquées Nous allons travaillez sur les données de 10 clients voulant un financement de notre banque. Sur ces clients, nous avons trois informations : le revenu, la mensualité, l’âge. import nupy as np # revenu, mensualite, age hugo = [1_300, 400, 23] richard = [1_700, 560, 24] emilie = [2_500, 900, 30] gaspard = [3_000, 1_000, 22] yohann = [2_400, 700, 34] cloe = [3_000, 700, 34] luc = [4_000, 1_200, 33] rachel = [3_300, 950, 27] maude = [1_850, 600, 25] # creation du tableau python tableau = [hugo, richard, emilie, gaspard, yohann, cloe, luc, rachel, maude] tableau # affichage de nos donnees afin de vérifier leurs conformites data = np.array(tableau) # creation du ndarray data 2.3.2 Sélectionnez des éléments au sein d'un ndarray Une fois les données obtenues, on peut sélectionner les éléments que l’on souhaite. 2.3. ACCÉDER AU ÉLÉMENTS D’UN NDARRAY 22 Slicing # selection du premier element du tableau data[0,0] # selection de la premiere ligne data[0,:] # ':' permet de signifier qu'on selectionne toute les colonnes # selection de la troisieme colonne ie tous les ages dans nos donnees data[:,2] # ':' permet de signifier qu'on selectionne toute les lignes Sélections conditionnées # selection de tous les clients dont l'age est inférieur à 25 data[data[:,2]<= 25] # selection des individus ayant un revenu strictement superieur à 2000 data[data[:, 0]> 2000] # selection d'individus de moins de 25 ans avec un revenu de plus de 2000 data[data[:,2]<= 25 & data[:, 0]> 2000] Ajouter des ligne ou des colonnes à un ndarray Plusieurs fonctions permettent d’ajouter des lignes ou des colonnes à des ndarray, les plus utilisées sont : vstack pour ajouter, à la fin du tableau existant, des lignes c’est à dire des individus ; column_stack pour ajouter, à la fin du tableau existant, des colonnes c’est à dire des variables. # ajout d'un client fred = [1_750, 700, 27] np.vstack((data, fred)) #ajout de la ligne # ajout d'une variable sur la solvabilite. # 1: solvable; 0: insolvable solvability = np.random.randint(0,2, size=11) np.column_stack((data, solvability)) # ajout de la colonne 2.3.3 Extension de Numpy par SciPy Pour le calcul scientifique, NumPy est une excellente bibliothèque, mais il existe également d’autres bibliothèques puissantes en Python. SciPy est une bibliothèque qui étend les fonction- 2.4. EXERCICES 23 nalités de NumPy avec des modules pour l’optimisation, l’intégration, l’interpolation, l’algèbre linéaire, les statistiques, etc. Par exemple : Il existe d’autres opérations liées aux matrices, dans la sous-bibliothèque linalg de SciPy : expm : exponentielle d’une matrice ; logm : logarithme d’une matrice ; sinm, cosm, tanm : fonctions trigonométriques sur des matrices ; sqrtm : racine carrée. Z 1 Pour calculer x2 dx : 0 from scipy.integrate import quad def integrand(x): return x**2 result, error = quad(integrand, 0, 1) print("Résultat de l'intégration:", result) Remarque 2.4. Afin de programmer, nous même les algorithmes de résolutions de nos problèmes nous utiliserons peu SciPy. Cela, permettra une grande maîtrise des concepts de programmation mathématique. Nous pourrons utiliser SciPy, en seconde option, pour l’initiation à l’usage de fonctions de calcul scientifique dédiées. 2.4 Exercices Tous les exercices sont à traiter dans un notebook. Afin de trouver les solutions justes, je vous recommande : 1. raisonner sur des feuilles de papier ; 2. résoudre mathématiquement les exercices sur vos feuilles ; 3. traduire vous solutions en algorithmes ; 4. simuler vos algorithmes c’est-à-dire traduire vos algorithmes en Python. 2.4.1 Exercice d'application de n de chapitre Exercice d’application 2.1. Pour cette seconde tâche, nous travaillons toujours sur les mêmes 10 clients, mais nous avons cette fois trois informations à disposition sur chacun d’eux : • le revenu mensuel ; • l’âge du client ; 2.4. EXERCICES 24 • le nombre d’enfants à charge. L’objectif va être de créer un tableau NumPy à partir de ces informations, et de répondre aux différentes demandes formulées par notre service Prêt, en manipulant ce tableau avec les différentes techniques présentées tout au long de ce chapitre. Je vous invite à suivre ce lien pour retrouver l’exercice : https: // colab. research. google. com/ drive/ 1MNhJ5rcO68nI4XcLkdoiAAigLbICpH3t? usp= sharing 2.4.2 Exercices complémentaires Nous passerons du temps à jouer à Lights Out !, un jeu électronique des années 1990 (qui peut encore être joué en ligne à ce lien 2 ) où l’objectif est d’éteindre toutes les lumières en appuyant dessus (ce qui modifie également l’état des lumières voisines). Bien que le jeu puisse paraître simple, le résoudre nécessite la résolution d’un système linéaire [1]. Lors de simulations Python, nous programmerons le jeu en utilisant des matrices. Cela inclura à la fois la programmation du jeu et celle d’un solveur. Nous aborderons les questions suivantes : • Peut-on toujours gagner à partir de n’importe quelle configuration initiale ? • Si une solution existe, est-elle unique ? • S’il existe plusieurs solutions, comment trouver celle avec le nombre minimal de mouvements ? Les exercices ci-dessous ont pour but de créer le jeu Lights out (Exercices 2 à 4) puis de savoir dans quelles dimensions le jeu a toujours une solution (Exercice 6) puis de créer un solutionneur (Exercices 5 à 8). Exercice 2.2 (Création des matrices croix). Créer une fonction Croix(i, j, n) qui crée la matrice Ci, j de taille n2 avec des 1 seulement en (i, j) et les voisins verticaux et horizontaux. Il y aura des zéros aux autres positions. 2. Le jeu peut-être joué sur : https://daattali.com/shiny/lightsout/ 2.4. EXERCICES 25 Les exercices suivants ne sont pas indépendants ! ! ! Je vous invites à lire tous les énoncés avant de débuter leur résolution. Exercice 2.3 (Jeu 3×3). Dans cette question, on demande de créer une fonction Lights_Out() sans variable d’entrée qui lance le jeu avec les indications : 1. Phrase d’accueil dans le jeu, 2. Tirage d’une configuration aléatoire avec la commande random.randint() de Numpy, 3. Affichage de la configuration initiale, 4. Demande de la case où le joueur veut jouer, 5. Récupération du numéro de ligne et de colonne avec la commande input(), 6. Mise à jour de la configuration et affichage de celle-ci. 7. On continue jusqu’à ce que le joueur éteigne toutes les lampes et dans ce cas, on affiche un message de félicitations et on sort du jeu. Exercice 2.4 (Matrice de passage). Créer une fonction Matrice_Passage(n) qui prend en entrée la dimension n et retourne la matrice dont les vecteurs sont les Ci, j exprimés dans la base canonique de Mn (F2 ). On prendra les Ci, j dans le même ordre que les vecteurs Ei, j de la base canonique. Exercice 2.5. On veut déterminer pour quelles dimensions le jeu a toujours une solution. 1. Écrire une boucle qui calcule pour n = 2 à 11, le déterminant de Matrice_Passage(n). On rappelle que ce déterminant est un nombre dans F2 , c’est-à-dire 0 ou 1. Comme Python fait les calculs avec des nombres à virgule flottante, il pourra être utile d’utiliser les commandes round(), int() et ajouter %2 pour avoir le reste dans la division euclidienne par 2. 2. Donner la liste des dimensions inférieures à 11 pour lesquelles le jeu possède une solution unique pour toute configuration initiale Exercice 2.6 (Inverse de la matrice de passage en dimension 3). Grâce à Python, calculer l’inverse de la matrice de passage en dimension 3. On pourra soit : • faire les calculs avec la commande linalg.inv() de Numpy, se ramener aux entiers puis réduire modulo 2 ou charger le package Scipy ; • changer le type de la matrice avec Matrix() et calculer l’inverse dans M(F2 ) avec la méthode .inv_mod(2). Exercice 2.7 (Solutionneur en dimension 3). Écrire une fonction Solution(A) qui prend en entrée une configuration initiale sous forme d’une matrice A de format 3 × 3 et retourne une matrice solution S (qui contient des 1 pour les cases où il faut appuyer et des 0 ailleurs). Exercice 2.8 (Bonus). Créer une interface graphique pour le jeu grâce à la bibliothèque Pygame. On pourra le faire en dimension 3 puis laisser le choix de la dimension au joueur, ajouter un bouton pour afficher la solution (Dans ce cas, on tirera la solution au hasard et la configuration initiale sera son image par la matrice de passage) ... 3 Créez votre premier data frame avec Pandas Comme nous avons pu le voir, les arrays NumPy sont particulièrement efficaces pour traiter des valeurs numériques. Mais les données, dans la réalité, ne sont pas composées uniquement de chiffres et de nombres. En effet, on retrouve aussi : • des catégories ; • des labels ; • des dates ; • du texte brut. De plus, ces données ont généralement un format prédéfini en analyse de données, où chaque ligne va correspondre à un individu (au sens statistique du terme), et chaque colonne va être une caractéristique spécifique des individus. C’est ce que l’on appelle une variable. Voici quelques exemples pour illustrer cela : • dans le milieu automobile, chaque individu sera une voiture, et on pourra avoir comme caractéristiques la puissance du moteur, les dimensions du véhicule, la marque, le modèle, la couleur, etc. ; • dans une étude de grande distribution, chaque individu pourra être un produit sur lequel on aurait plusieurs informations (le prix, la catégorie, etc.) ; • dans le milieu bancaire enfin, chaque individu sera une personne, sur laquelle on aurait enregistré le salaire moyen, le genre, ses mensualités de remboursement de prêt, etc. ; Voilà par exemple à quoi pourrait ressembler ce dernier cas. F IGURE 3.1 – Base de données au format excel 26 27 Excel est encore pour beaucoup d’entreprises un format très utilisé pour stocker et déplacer des données. Mais ce n’est pas le seul, les données peuvent être stockées sous bien des formats différents. Par exemple, on retrouve régulièrement des fichiers texte ou des fichiers CSV (pour comma-separated values). Ce sont simplement des fichiers contenant l’ensemble des données brutes, séparées par un délimiteur. Voici un exemple avec un jeu de données automobiles, dont le délimiteur est le point-virgule : La base de données peut également être sous la forme de fichier JSON. Le JavaScript Object F IGURE 3.2 – Base de données au format CSV Notation (JSON) est un format standard utilisé pour représenter des données structurées. Cela ressemble à un gros dictionnaire Python pouvant contenir lui-même d’autres dictionnaires et/ou listes. C’est une description un peu "réductrice", mais une image vaut mieux que mille mots : Nous n’aurons malheureusement pas l’occasion d’approfondir le format JSON dans le cadre de F IGURE 3.3 – Base de données au format JSON ce cours, mais il existe de nombreuses ressources qui traitent le sujet en détail. Le JSON est un format très standard dans le monde informatique ! Remarque 3.1. Nous n’avons ici vu que les formats texte, JSON et CSV, mais la liste n’est naturellement pas exhaustive. De plus, plutôt que de stocker les données dans des fichiers, on a 3.1. GÉNÉREZ UN DATA FRAME 28 plutôt l’habitude de le faire dans des bases de données SQL. Dans ce chapitre nous recherchons un outils qui nous permette de représenter les données avec le format souhaité (individus/variables), de manipuler différents types de données, et de lire les données provenant de différentes sources. Cet outil n’est autre que la librairie Pandas, et plus particulièrement les objets data frame. Le data frame est un objet Python permettant de représenter les données sous forme de tableau, où chaque colonne est explicitement nommée. Il reprend les mêmes paradigmes que l’array NumPy : chaque colonne peut naturellement être d’un type différent, mais une colonne ne peut contenir qu’un seul type ! Cette organisation simplifie l’accès aux variables, et permet de nombreuses manipulations de données plus ou moins complexes. Question : quel est l’intérêt de la librairie NumPy si Pandas permet de faire mieux ? Reponse : au fur et à mesure de ce cours, et plus globalement de vos futures modélisations, que vous serez régulièrement amené à jongler entre les deux. Il est assez courant que certaines méthodes appliquées à des data frames retournent des arrays, et qu’on ait besoin de retransformer ces arrays en data frames à postériori. C’est pourquoi il est nécessaire de maîtriser les deux librairies, pour être parfaitement armé avant de plonger dans une modélisation. 3.1 Générez un data frame Nous allons explorer les différentes méthodes permettant de créer un data frame. On peut créer un data frame à partir : • de fichier(s) préexistant(s) dans divers formats tels que Excel, CSV, JSON, etc. ; • de données contenues dans des arrays ou des dictionnaires. La capacité de convertir des données en data frames est essentielle pour faciliter leur manipulation et analyse dans des contextes variés. 3.1.1 Créer votre data frame à partir de chier(s) préexistant(s) Nous allons créer un data frame à partir des formats cités ci-dessus ; je vous propose d’importer le même jeu de données sous 3 formats différents : Excel, CSV et JSON. Vous trouverez les trois fichiers dans ce dossier compressé :https://course.oc-static. com/courses/7771531/Ressources+t%C3%A9l%C3%A9chargeables/P2C1_clients.zip. Création d’un data frame à partir de fichiers préexistant import pandas as pd # Importation du fichier csv qu'on stocke dans une variable data_csv = pd.read_csv('clients.csv') 3.1. GÉNÉREZ UN DATA FRAME 29 data_csv.head() # afin d'afficher les 5 premières lignes du dataset # Importation du fichier json qu'on stocke dans une variable data_json = pd.read_json('clients.json') data_json.head() # Importation du fichier excel qu'on stocke dans une variable data_excel = pd.read_excel('clients.xlsx') data_excel.head() # .tail() permet d'afficher les 5 derniers éléments Il est important de décompresser le dossier .zip et de placer les fichiers csv dans le même dossier que le notebook jupyter pour en faciliter l’importation ! Sinon vous devrez utilisez leurs adresses. Une fois le data frame importé, commence alors le travail principal : la manipulation de données. Et avant toute manipulation, il est nécessaire de connaître son jeu de données (dataset en anglais). 3.1.2 Créer un data frame à partir de données que vous avez Il existe plusieurs méthodes pour créer un DataFrame à partir de données en Python, notamment en utilisant la fonction DataFrame de la bibliothèque pandas. Ci-dessous quelques-unes des méthodes les plus courantes. À partir d'un dictionnaire data = { 'Nom': ['Alice', 'Kouraogo', 'Alphonse'], 'Âge': [25, 30, 35], 'Ville': ['Paris', 'Lyon', 'Marseille'] } df_dict = pd.DataFrame(data) df_dict.head() L’index par défaut est une séquence numérique commençant à 0. Les colonnes du DataFrame sont directement définies par les clés du dictionnaire. Cela n’est pas le cas quand le data frame est créé à partir d’une liste. À partir d'une liste de listes 3.2. IDENTIFIEZ LES CARACTÉRISTIQUES DE VOTRE DATA FRAME 30 data = [ ['Alice', 25, 'Paris'], ['Kouraogo', 30, 'Lyon'], ['Alphonse', 35, 'Marseille'] ] df_liste = pd.DataFrame(data, columns=['Nom', 'Âge', 'Ville']) df_liste.head() L’index par défaut est une séquence numérique commençant à 0. Les noms des colonnes du data frame doivent être définies à l’aide de l’argument columns. 3.2 Identiez les caractéristiques de votre data frame Pandas met à notre disposition plusieurs méthodes afin qu’on puisse analyser notre data frame. 3.2.1 Aperçu du data frame Comme effectué ci-dessus, un bon réflexe à adopter après l’importation, et après toute transformation, est de visualiser le dataset, ou du moins quelques lignes, afin de vérifier que tout s’est correctement déroulé. Pour cela, il existe deux méthodes principales : • la méthode .head() permettant de sélectionner par défaut les 5 premières lignes du data frame. Il est possible de préciser entre parenthèses le nombre de lignes à afficher ; • la méthode .tail() permettant de sélectionner par défaut les 5 dernières lignes du data frame. Il est également possible de préciser entre parenthèses le nombre de lignes à afficher. Remarque 3.2. Il n’est pas possible (par défaut) d’afficher plus de 60 lignes d’un data frame, afin de ne pas surcharger inutilement le notebook. De façon globale, chercher à visualiser l’ensemble d’un data frame n’est généralement pas une bonne pratique. Si cela est tout à fait envisageable avec quelques dizaines de lignes, ça devient vite impossible avec plusieurs millions de lignes ! Si vous cherchez à afficher plus de 60 lignes, vous aurez finalement comme résultat les 5 premières et dernières lignes du data frame. Exemple # chargement du fichier import pandas as pd data = pd.read_csv("clients.csv") # afficher les 5 premières lignes data.head() 3.2. IDENTIFIEZ LES CARACTÉRISTIQUES DE VOTRE DATA FRAME 31 # afficher les 2 dernières lignes data.tail(2) # afficher les 5 premières et dernières lignes data On peut également accéder aux caractéristiques globales d’un data frame. 3.2.2 Caractéristiques globales d'un data frame Lorsqu’on parle de caractéristiques globales, il est question ici des attributs, des informations générales qu’on retrouve sur tous les data frames, et dont on aura besoin régulièrement. En premier lieu viennent les dimensions d’un data frame. Combien d’individus (de lignes) ou de variables (de colonnes) comportent un data frame ? Et combien de colonnes ? Tout comme avec les arrays NumPy, il est possible de répondre à ces questions via l’attribut .shape : Caractéristique globale d’un data frame data.shape Le résultat sera un tuple dont le premier élément correspond au nombre de lignes, et le second au nombre de colonnes. On peut naturellement stocker le résultat de cet attribut dans une variable pour réutiliser ces éléments ultérieurement : size = data.shape print(size[0]) # 228 print(size[1]) # 4 Au-delà du nombre de ligne et de colonnes, on peut avoir envie de connaître les types de chacune de nos variables. On peut accéder à cela très simplement à partir de l’attribut .dtypes : data.dtypes Vous observez que le type des variables e-mail, nom et genre est objet, alors que nous avons pourtant des chaînes de caractères. Cela est dû au fait que le type objet de Pandas correspond en fait à une colonne de type chaîne de caractères (ou string). Enfin, nous avons évoqué précédemment le lien qui peut exister entre Pandas et NumPy. Je vous propose dès à présent de matérialiser ce lien en transformant notre data frame en array : De Pandas à Numpy clients_array = data.values display(clients_array) Nous avons à présent un array NumPy en lieu et place d’un data frame. 3.2. IDENTIFIEZ LES CARACTÉRISTIQUES DE VOTRE DATA FRAME 32 Maintenant que nous sommes au point sur les informations générales d’un data frame. Dans le chapitre suivant, nous allons découvrir un peu plus en détail ce que Pandas nous permet de faire en termes de manipulation de data frame. 4 Manipulez un data frame Dans le chapitre précédent, nous avons importé notre premier data frame mais c’est loin d’être le dernier. Une fois nos données correctement importées, la suite logique va être de les manipuler à notre guise. Voici un cas concret : nous souhaitons accéder à la liste de tous les e-mails des clients ayant contracté un prêt dans la banque, à partir du data frame clients importé lors du chapitre précédent, pour créer une liste de diffusion pour des offres commerciales préférentielles. Comment faire cela avec Pandas ? C’est ce que je vous propose de voir à présent ! 4.1 Naviguez dans un data frame Dans un data frame, chaque colonne est explicitement nommée, rendant la compréhension de cette dernière plus claire, et permettant d’accéder à une colonne spécifique à partir de son nom ! Pour accéder à une colonne d’un data frame, il suffit d’utiliser la syntaxe : nom_dataframe[nom_colonne]. Accéder à une variable (colonne) d’un data frame Pour accéder à la liste des e-mails du data framedata importé dans le chapitre précédent : data['email'] On peut même décider de stocker cette variable email (au sens des données) dans une autre variable (au sens informatique, cette fois !) pour les besoins de la liste de diffusion présentée ci-dessus. Ici, je crée une variable email dans laquelle je stocke tous les e-mails de ma base clients : email = data['email'] Question : comment accéder à plusieurs colonnes ? 33 4.2. DÉCOUVREZ L’OBJET SERIES DE PANDAS 34 Réponse : il suffit de stocker l’ensemble des noms des colonnes auxquelles vous souhaitez accéder dans une liste. Voilà par exemple comment accéder aux colonnes : nom et l’e-mail : Accéder à plusieurs variables (colonnes) d’un data frame variables = ['nom', 'email'] data[variables] Dans le code précédent : 1. On souhaite accéder au nom et à l’e-mail de nos clients. On crée donc dans un premier temps une liste que l’on nomme variables, dans laquelle nous stockons l’ensemble des noms des variables. 2. On utilise la même syntaxe que vu précédemment, pour sélectionner dans notre data frame la liste des variables définie. Vous pouvez réaliser ces deux étapes en une fois avec : data[['nom', 'email']]. Vous noterez que les variables s’affichent dans l’ordre dans lequel nous l’avons spécifié (ici : le nom avec l’e-mail) et non comme elles sont disposées initialement (l’e-mail est avant le nom dans notre data frame data). Et si vous vérifiez le data frame initial, vous verrez que l’ordre initial est bien conservé. Ainsi, le processus de sélection nous permet de réorganiser l’ordre des colonnes comme on le souhaite, sans modifier le data frame initial. 4.2 Découvrez l'objet Series de Pandas Vous commencez à bien connaître l’objet data frame, mais une colonne d’un data frame n’est plus un data frame ! En effet, il est temps de vous présenter le second objet de Pandas que vous allez énormément utiliser, et qui est intimement lié au data frame : la Series. En effet, chaque colonne de votre data frame est de type Series. Vous pouvez vérifier cela par vous-même via la fonction type : type(data['email']). On obtient le résultat : pandas.core.series.Series. Il est important de différencier le data frame et la Series. Même s’ils partagent de nombreuses méthodes, certaines sont néanmoins exclusives à l’un ou l ?autre, et cela peut être une source d’erreur lors de l’implémentation d’analyse de données avec Python. Remarque 4.1. Une différence évidente, mais que je me permets tout de même de noter : un data frame a 2 dimensions avec plusieurs colonnes, alors que la Series n’a qu’une seule dimension. Cela peut fortement vous aider lorsque vous utiliserez certaines méthodes, car vous pourrez savoir à quel type d’objet vous faites face, en vous basant sur l’affichage que vous avez de ce dernier (encore une raison d’utiliser la méthode .head). Regardons la Figure 4.1. 4.2. DÉCOUVREZ L’OBJET SERIES DE PANDAS (a) Exemple de data frame 35 (b) Exemple de Series F IGURE 4.1 – Différence d’affichage entre un data frame et un Series La Figure 4.1a est relativement « jolie », avec une organisation en tableau, où chaque colonne (une ici) est explicitement nommée : c’est un data frame. De plus, les informations affichées en bas sont le nombre de lignes et de colonnes. C’est finalement assez logique, car nous avons sélectionné ici 1 colonne. Vous noterez que la Figure 4.1b est un peu plus austère et surtout, que les informations affichées en bas ne sont pas les mêmes : c’est une Series. En information, vous avez notamment le nom de la Series, la longueur (ou le nombre de lignes), et enfin le type de la colonne (entier, chaîne de caractères, etc.). Une Series ne peut contenir qu’un seul type, alors qu’un data frame, qui est finalement une collection de Series, peut contenir des colonnes de types différents : une colonne d’entiers, une colonne de nombres décimaux, etc. Il est important de garder ces notions en tête lors de vos futures analyses de données. De nombreuses méthodes sont communes à ces deux objets, alors que d’autres sont spécifiques. Par exemple, l’ensemble des attributs vus au chapitre précédent (shape, head, dtypes) existent pour des Series. Mais certaines méthodes, notamment certaines que nous verrons un peu plus tard dans ce cours, sont exclusives aux data frames, à cause de leur aspect multidimensionnel. Voyons, à présent, quelques manipulations possibles avec des Series. 4.3. MANIPULEZ LES COLONNES 36 4.3 Manipulez les colonnes Manipuler un data frame revient à manipuler ses lignes ou ses colonnes. Dans cette section, je vous propose de voir quelques manipulations indispensables sur les colonnes (variables) d’un data frame : • créer ou supprimer une colonne ; • renommer une colonne ; • changer le type d ?une colonne ; • trier un data frame selon une ou plusieurs colonnes. 4.3.1 Modiez une colonne existante Avant de voir comment créer une colonne, voyons comment en modifier une déjà existante. Reprenons la syntaxe vue précédemment, nom_dataframe[nom_colonne]. Cette dernière permet d ?accéder à une colonne d’un data frame sans modifier ce dernier. Ce que vous ne savez pas encore, c’est qu’elle permet également de modifier un data frame existant. Considérons une variable informatique a déjà existante : • on peut y accéder en l’appelant, lui appliquer plusieurs fonctions différentes (comme print(a) pour l’afficher) sans modifier sa valeur ; • mais on peut également définir ou changer sa valeur (a=4 qui stockera l’entier 4 dans notre variable a). C’est exactement la même chose avec une colonne d’un data frame : • on peut y accéder et appliquer plusieurs fonctions et/ou méthodes : c’est ce que nous avons fait jusque-là ; • on peut également changer les valeurs qui se trouvent à l’intérieur. Par exemple, si j’exécute : data['nom'] = 1 Cela aura deux effets : cela va modifier la variable nom existante en remplaçant toutes les valeurs par 1, et cela transforme également le type de la variable, comme vous pourrez le constater si vous regardez la Figure 4.2 : nom était de type object avant la transformation (Figure 4.2a) ; elle est à présent de type integer car 1 est un entier (Figure 4.2b). Ainsi, si on le remplace par une valeur fixe (comme c’est le cas ici), cela aura pour effet de remplacer l’ensemble des valeurs de notre colonne par cette valeur fixe, et changera le type de la colonne dans le type de la valeur fixe spécifiée, qu’elle soit numérique ou non. On peut également remplacer une colonne par un objet de même dimension. Comprenez par là une liste, un array ou une series comprenant l’exact même nombre d’éléments. Par exemple, si 4.3. MANIPULEZ LES COLONNES (a) Avant la transformation 37 (b) Après la transformation F IGURE 4.2 – Transformation d’une colonne du type object vers le type integer je souhaite modifier la colonne identifiant par elle-même multipliée par 100, je peux le faire de la façon suivante : Modifiez une colonne du data frame data['identifiant'] = data['identifiant']*100 On peut ainsi décider de remplacer les données de la colonne par des valeurs aléatoires suivant la loi de Poisson de paramètre 5 : import numpy as np data['identifiant'] = np.random.poisson(5,data.shape[0]) Vous noterez que l’array généré pour remplacer les valeurs a strictement la même dimension que la colonne qu’il remplace. Vous aurez une erreur si ce n’est pas le cas, donc soyez vigilant sur cet aspect ! Si vous souhaitez revenir à vos valeurs originales après avoir modifié la colonne nom, vous ne pouvez pas compter sur Pandas pour conserver un historique des data frames. À la place, vous pouvez recharger les données originales en utilisant pd.read_csv. Remarque 4.2. En pratique, on ne modifiera une colonne que lorsqu’on est vraiment sûr de nous, afin justement de ne pas supprimer par mégarde des données dont on aurait besoin. 4.3.2 Créer et supprimez une colonne Pour créer une colonne, on procède de la même façon que pour modifier une. Cette nouvelle colonne est créer à la fin du data frame. 4.3. MANIPULEZ LES COLONNES 38 Créez une colonne dans le data frame Dans notre data frame, on souhaite créer une colonne nommée id. # Méthode 1 data['id'] = 100 # création de la colonne data.head() #affichage du data frame # Méthode 2: à partir d'une colonne préexistante data['id'] = data['identifiant'] + 1000 data.head() Pour résumer, que ce soit pour modifier ou créer une colonne col, la syntaxe sera : mon_dataframe['col'] = x où x représente soit une valeur fixe, soit un objet de même dimension que la colonne qu’on souhaite modifier/créer. Pour supprimer une colonne dans un data frame, il existe (à ce jour) trois méthodes : .drop, .del, .pop. Supprimez une colonne dans un data frame Dans notre data frame, on souhaite créer une colonne nommée id. # Méthode 1: .drop data.drop(columns = 'id') Contrairement aux deux options suivantes, la méthode .drop ne modifie pas le data frame existant, elle renvoie juste une sorte de copie du data frame en y ayant appliqué les modifications, ici supprimer la colonne id. Vous aurez besoin de remplacer votre data frame pour pallier cela : data_suppresion_definitive = data.drop(columns='id', inplace=True) pour supprimer définitivement la colonne. # Méthode 2: .del del data['id'] data.head() # Méthode 3: .pop data.pop('id') data.head() L’utilisation de l’une ou l’autre de ces méthodes dépendra de votre préférence. 4.3.3 Renommez une colonne La méthode pour renommer une colonne est .rename. On peut ainsi renommer une ou plusieurs colonnes via les syntaxes : • mon_dataframe.rename(columns = {'ancien_nom': 'nouveau_nom'}) ; 4.3. MANIPULEZ LES COLONNES 39 • mon_dataframe.rename(columns={'ancien_nom1': 'nouveau_nom1', 'ancien_nom2': 'nouveau_nom2', . . . , 'ancien_nomN': 'nouveau_nomN'}) Renommez une ou plusieurs colonnes dans un data frame Renommer la colonne nom en youre : data.rename(columns = {'nom': 'youre'}) Renommer les colonnes genre et email en sexe et mail : data.rename(columns = {'genre': 'sexe', 'email': 'mail'}) Remarque 4.3. la méthode rename ne modifie pas le data frame existant. Il existe cependant un argument pour cette méthode (et pour toutes les méthodes similaires) nommé inplace, qu’il suffit de fixer à Vrai (True) pour pallier cela. Ainsi, data.rename(columns={'sexe': 'genre'}, inplace=False) est strictement équivalent à data = data.rename(columns={'sexe': 'genre'}). 4.3.4 Changez le type d'une colonne La méthode .astype permet de changer le type d ?une colonne. Par exemple, si on souhaite transformer la colonne identifiant, initialement composée d’entiers, en nombres décimaux, on peut le faire de la façon suivante : data['identifiant'].astype(float) 4.3.5 Triez un data frame En analyse de données, on a régulièrement besoin de trier des données selon une ou plusieurs colonnes. Pandas met à disposition la méthode .sort_values pour faire cela très aisément. Il suffit de préciser entre parenthèses la ou les colonnes selon lesquelles il faut trier. Voici quelques exemples : # trier selon l'identifiant, par ordre croissant : data.sort_values('identifiant') #trier selon l'identifiant par ordre décroissant : data.sort_values('identifiant', ascending = False) # trier selon le genre puis le nom, par ordre croissant : data.sort_values(['genre', 'nom']) 4.3. MANIPULEZ LES COLONNES 40 Le mot clé ascending permet de définir si on souhaite trier par ordre croissant ou décroissant. Question : Comment procéder si on souhaite avoir l ?un par ordre croissant et l ?autre par ordre décroissant ? Réponse : il faudra donner une liste de paramètres (True ou False) à ascending. Voici par exemple comment trier par sexe en ordre croissant et par youre en ordre décroissant : data.sort_values(['sexe', 'youre'], ascending = [True, False]) Maintenant que nous sommes au point avec ces outils, mettons ce que nous avons appris en pratique ! Exercice d’application 4.1. Nous allons travailler à présent sur notre fichier de prêts immobiliers. Chaque ligne du fichier correspond à un prêt qui a été accordé à un de nos clients. Chaque client est identifié par : son identifiant ! Nous avons les informations suivantes : • la ville et le code postal de l’agence où le client a contracté le prêt ; • le revenu mensuel du client ; • les mensualités remboursées par le client ; • la durée du prêt contracté, en nombre de mois ; • le type de prêt ; • et enfin le taux d’intérêt. Votre rôle cette fois-ci va être de modifier ce jeu de données pour calculer différentes variables nécessaires pour identifier les clients à la limite de leur capacité de remboursement, et déterminer les bénéfices réalisés par la banque. Voici un exercice pour vous entraîner à manipuler un data frame : https: // colab. research. google. com/ drive/ 1S3FkSdeckSNuuuoiGphc7piPfxgGMZyt? usp= sharing 5 Filtrez les données du data frame Imaginons les situations suivantes : • pour une offre commerciale spécifique, on cherche à ne sélectionner que les hommes de notre data frame ; • on souhaite identifier les hauts revenus parmi notre clientèle. Pour cela, on souhaite sélectionner tout ceux gagnant mensuellement plus de x ; • on souhaite identifier les clients dits "risqués", c’est-à-dire ceux qui ont un taux d’endettement supérieur aux 35% légaux. Jusqu’à présent, nous avons été capables de sélectionner des colonnes spécifiques et de les manipuler à notre guise. Mais les exemples précédents ne peuvent être satisfaits avec de simples manipulations de colonnes : il faut appliquer une condition spécifique pour ne sélectionner que les lignes pertinentes. Cette opération est ce qu’on appelle une restriction, ou un filtrage. Naturellement, Pandas permet de faire cela, pour avoir un contrôle total sur nos données. 5.1 Appliquez la sélection via des indices Le premier type de sélection est réalisé via des indices. Il se fait via la méthode .iloc. La méthode .iloc suit la syntaxe suivante : mon_dataframe.iloc[indice_ligne, indice_colonne]. Exemple 5.1 (Sélection d’un élément). on souhaite sélectionner le nom du premier client de notre base de données. Comme c’est le premier client, son indice de ligne sera 0. Nous souhaitons sélectionner son nom ; la variable nom est la 3ème variable de notre data frame, l’indice de sa colonne sera donc 2. Le code de sélection serait donc : mon_dataframe.iloc[0, 2] 'Laurent Dagenais' 41 5.2. UTILISEZ LA SÉLECTION VIA DES CONDITIONS 42 Question : Maintenant, admettons que je souhaite sélectionner le nom des 10 premiers clients, comment procéder ? Réponse : Comme avec les arrays, nous pouvons utiliser l’opérateur : pour sélectionner la plage souhaitée. Sélection de plusieurs éléments avec .iloc # sélectionner le nom des 10 premiers clients : clients.iloc[:10, 2] # sélectionner le genre des 10 premiers clients : clients.iloc[:10, 3] # sélectionner toutes les colonnes des 10 premiers clients : clients.iloc[:10, :] # sélectionner l'email et le nom des 10 clients à 20: clients.iloc[10:20, 1:3] # sélectionner l'e-mail et le genre des 10 derniers clients : clients.iloc[-10:, [1, 3]] # On sélectionne les colonnes 1 et 3 La méthode .iloc peut être utile dans certains cas, mais elle est finalement assez limitée. En effet, elle n’est pas adaptée si on souhaite sélectionner selon une certaine condition (par exemple tous les revenus supérieurs à x), et il faut absolument connaître l’indice des différentes colonnes. Cela reste jouable avec 5 − 6 colonnes, mais devient beaucoup plus compliqué lorsqu’on est en présence de dizaines de colonnes. Il existe une autre méthode, qui est similaire à .iloc mais qui permet de pallier l’ensemble de ces inconvénients : la méthode .loc. 5.2 Utilisez la sélection via des conditions Les data frames possèdent de nombreuses méthodes, comme vous avez pu commencer à vous en rendre compte. Mais de toutes, il y en a certainement une que vous allez utiliser et réutiliser à outrance : c’est la méthode .loc ! Celle-ci suit la syntaxe suivante : mon_dataframe.loc[condition sur les lignes, colonne(s)]. C’est à première vue très simple, mais nous allons voir que cette syntaxe peut en pratique devenir vite complexe, et peut permettre en même temps une grande flexibilité. 5.2. UTILISEZ LA SÉLECTION VIA DES CONDITIONS 43 Sélection de plusieurs éléments avec .loc On va travailler avec le fichier pret.cvs. import pandas as pd data = pd.read_csv('prets.csv') data.head() # Sélection des prêts de type automobile data.loc[data['type'] == 'automobile', :] # Sélection des personnes ayant un revenu > 4_000 data.loc[data['revenu'] > 4_000, :] # Sélection des personnes ayant un revenu > 4_000 et un prêt automobile data.loc[(data['revenu'] > 4_000) & (data['type'] == 'automobile'), :] # Sélection des personnes ayant un revenu > 4_000 ou un prêt automobile data.loc[(data['revenu'] > 4_000) | (data['type'] == 'automobile'), :] --------------------------------------------------------------------------# sélection des identifiants des personnes ayant contractés # un prêt automobile data.loc[data['type'] == 'automobile', 'identifiant'] # sélection des identifiants et revenus des personnes ayant # contractés un prêt automobile data.loc[data['type'] == 'automobile', ['identifiant', 'revenu']] Une autre option de la méthode .loc est la sélection par index. Avant d’aller plus loin sur cet aspect, laissez-moi redéfinir la différence entre des index et des indices ! Les indices sont la position intrinsèque d’un élément au sein d’un tableau. Les index, en revanche, correspondent à une valeur qui est associée à chaque ligne. C’est ce que vous voyez sur la gauche de votre data frame : Par défaut, les index correspondent aux indices ! Mais ils peuvent ne pas être numériques ; on pourrait par exemple fixer le nom de la personne comme index, si on est sûr qu’il n’y aura pas de doublons. Faisons un simple tri pour bien comprendre la différence entre l’indice et l’index (Figure 5.2) : Cette situation est intéressante, car si on regarde notre première ligne, son index est 13. Pourtant, c ?est bel et bien la première ligne, donc son indice est 0 ! ! ! Je pense que vous commencez à comprendre la différence : un indice est relatif aux opérations 5.2. UTILISEZ LA SÉLECTION VIA DES CONDITIONS 44 F IGURE 5.1 – Localisation de l’index dans le data frame : colonne en rouge F IGURE 5.2 – Différence entre index et indice réalisées. Un individu peut avoir le premier indice à un moment, et un tout autre indice en fonction du tri effectué. En revanche, l’index est intrinsèque aux lignes au sein d’un data frame. Peu importe les opérations effectuées, que ce soit un tri, une suppression, etc., l’index sera toujours le même ! La seule condition, c’est que chaque ligne doit avoir un index unique : c’està-dire qu’il ne doit pas y avoir deux fois la même valeur au sein d’un index ; on ne pourra par exemple pas avoir 2 fois l’index 0. Question : Pourquoi parler de tout cela ? Réponse : Parce qu’il est possible de faire une sélection au sein d ?un data frame selon les index, avec la méthode .loc. Sélection selon les index avec .loc On va travailler avec le fichier clients.cvs. display(clients.loc[0:10, :]) display(clients.iloc[0:10, :]) Remarque 5.1. Il est possible d’accéder à la liste des index d’un data frame via l’attribut .index. Par exemple, clients.index nous renverra l’ensemble des index du data frame. 5.3. MODIFIEZ UNE SÉLECTION 45 5.3 Modiez une sélection Comme avec les colonnes, on peut utiliser les méthodes .iloc ou .loc pour modifier les lignes d’un data frame existant. C’est même encore plus intéressant que ce que nous avions vu jusquelà, car il est possible de modifier précisément une partie d’un data frame. Modification d’une sélection On va travailler avec le fichier prets.cvs. Mettons nous dans les situation où l’on veut accorder une remise : • à nos trois premiers clients à un taux de 1.05% ; • à l’ensemble des personne de la région parisienne ; • en ajoutant 0.05 au taux des individus de la région marseillaise import pandas as pd data = pd.read_csv('prets.csv') data.head() #%accès et modification de la valeur du taux des 3 premiers clients data.iloc[:3, 7] = 1.05 data.head() # Pour les individus de la région parisienne data.loc[data['ville'] == 'PARIS', 'taux'] = 1.05 data.head(15) # taux + 0.05 pour les marseillais mask = data['ville'] == 'MARSEILLE' data.loc[mask, 'taux'] = data.loc[mask, 'taux'] + 0.05 data.head(15) Un mask à l’intérêt de pouvoir être réutiliser ainsi que celui d’améliorer la lisibilité du code Exercice d’application 5.1. Certaines demandes ont été spécifiquement formulées par le responsable du service Prêt de notre établissement. Il souhaite que vous puissiez appliquer les traitements nécessaires pour lui donner des réponses précises. Vous allez devoir mettre en application l’ensemble des processus de sélection présentés cidessus, pour répondre à ces différentes demandes : • Le taux d’endettement autorisé est de 35 %. Pourriez-vous me communiquer le nombre de personnes ayant dépassé ce seuil ? 5.3. MODIFIEZ UNE SÉLECTION 46 • Même question, mais cette fois-ci uniquement sur l’agence parisienne. • Pour faciliter le traitement d’éventuelles futures demandes de prêts, pourriez-vous ajouter une variable nommée risque, qui nous permettrait d’identifier facilement les clients à risque ? • Combien de prêts automobiles ont été accordés ? Quel est le coût total moyen de ceux-ci ? • Quel est le bénéfice mensuel total réalisé par l’agence toulousaine ? Voici un exercice pour vous entraîner à filtrer des données dans un data frame : https: // colab. research. google. com/ drive/ 1JCqeRTFxsCFpUlyNSUn1hNYpKgou82rn? usp= sharing 6 Maîtrisez les bonnes pratiques de la data visualisation 6.1 Importance de la représentation graphique Aujourd’hui, les entreprises du monde entier génèrent un volume de données extrêmement important : plusieurs dizaines de zettaoctets (milliards de téraoctets) selon les dernières estimations. Et ce chiffre ne fait qu’augmenter exponentiellement au fur et à mesure que les technologies de stockage évoluent. Il devient donc indispensable pour une entreprise d’avoir des outils pour analyser ces données, afin d’en tirer des enseignements exploitables au niveau business (des tendances d’achat selon les périodes, par exemple) et plus globalement, de pouvoir surveiller les différentes activités de l’entreprise afin d’identifier d’éventuels problèmes. Toutes les librairies vues jusqu’à présent font partie de ces outils, mais demandent une certaine technicité, au moins en programmation. Or, la plupart des personnes en charge de la stratégie au sein d’une entreprise (ceux qu’on appelle les décideurs) n’ont généralement pas ce bagage. Solution : il faut un outil permettant de rendre la donnée accessible à ces personnes ? Tout à fait ! C’est ce qu’on appelle la data visualisation (ou dataviz). La data visualisation est un ensemble de techniques utilisées pour communiquer des informations clés sur un gros volume de données, afin d’en faciliter la compréhension et la lecture pour tous. Ce domaine s’est vraiment démocratisé en entreprise dans les années 80, lorsque les entreprises ont pris conscience que l’analyse de leurs données pourrait aider grandement à la prise de décision ! Remarque 6.1 (Selon Confucius : « Une image vaut mille mots. »). Cette citation résume assez bien l’idée de la data visualisation. Car finalement, peu importe le choix du graphique ou de la représentation, l’objectif final reste de résumer une information de façon visuelle, de sorte à ce que quiconque puisse la comprendre et se l’approprier. Lorsqu’il est question de représentation ou de graphique, de nombreux choix s’offrent à nous. 47 6.2. IDENTIFIEZ LE GRAPHIQUE ADAPTÉ 48 On peut citer de façon non exhaustive : • les courbes pour représenter une évolution d’une caractéristique (comme la démographie d’un pays) dans le temps ; • les graphiques circulaires (ou graphiques camemberts) pour représenter une répartition ; • des cartes lorsqu’on souhaite afficher une information géographique. Il en existe bien d’autres, découvrons à présent de découvrir en détail les principales. 6.2 Identiez le graphique adapté Le choix d’un graphique va énormément dépendre des différentes variables qu’on cherche à représenter, et de l’information dont on dispose. 6.2.1 Présentez une évolution dans le temps Ce cas se présente lorsqu’on souhaite représenter une variable numérique qui évolue dans le temps : la notion d’évolution implique qu’on ne peut avoir qu’une valeur numérique par pas de temps choisi – par mois, par année, etc. F IGURE 6.1 – Data frame à expliciter en graphique Pour représenter une évolution dans le temps, on peut utiliser : • des diagrammes en ligne, ou en courbes ; • des diagrammes à barres ou en bâtons. F IGURE 6.2 – Exemple de diagramme en ligne 6.2. IDENTIFIEZ LE GRAPHIQUE ADAPTÉ 49 F IGURE 6.3 – Exemple de diagramme en barres 6.2.2 Comparez diérents groupes On utilise ce type de graphique généralement lorsqu’on a des données agrégées sur une variable non numérique. On a ainsi une valeur numérique agrégée par groupe ou par catégorie : F IGURE 6.4 – Data frame à valeur numérique agrégée par quantité Afin de représenter ces données, on peut utiliser des diagrammes circulaires, encore appelés des camemberts. F IGURE 6.5 – Exemple de diagramme circulaire Mais l’idéal reste tout de même les diagrammes à barres. 6.2. IDENTIFIEZ LE GRAPHIQUE ADAPTÉ 50 F IGURE 6.6 – Autre exemple de diagramme à barres 6.2.3 Représentez une distribution Ce type de graphique est particulièrement utile lors d’une analyse préliminaire, lorsqu’on souhaite comprendre les données à disposition, et la façon dont chaque variable se répartit. Il y a deux cas possibles : une variable numérique et une variable non numérique. Dans le cas d’une variable numérique, on utilise généralement un histogramme : F IGURE 6.7 – Exemple d’histogramme Il existe aussi une variante de l’histogramme, appelée diagramme à densité. Le diagramme à densité est très utilisé pour représenter des variables quantitatives continue. Dans le cas d’une variable non numérique, techniquement, c’est une visualisation que nous avons déjà rencontrée. Car la première étape est d’agréger les données pour compter le nombre d’occurrences au sein de notre variable, par catégorie ou groupe. Ensuite, on se retrouve simplement dans le cas de comparaison cité ci-dessus : on peut utiliser un diagramme circulaire ou un diagramme à barres. 6.3. BONNES PRATIQUES DE LA VISUALISATION DES DONNÉES 51 F IGURE 6.8 – Exemple de diagramme à densité 6.2.4 Représentez la relation entre deux variables numériques Le dernier cas, que nous n’avons pas traité mais qui est couramment rencontré, est le choix du graphique lorsqu’on souhaite représenter la relation entre deux variables numériques. Le jeu de données contient dans ce cas plusieurs lignes, exprimées sur (au moins) deux variables numériques. F IGURE 6.9 – Data frame mettant en relation deux variables numériques On peut tracer plusieurs points (un pour chaque ligne) en mettant l’une des variables en abscisse et l’autre en ordonnée : c’est ce qu’on appelle un nuage de points. La liste n’est naturellement pas exhaustive, et ce cours serait bien trop long s’il fallait tous les traiter, mais voici cependant un bon échantillon des principales que vous allez être amené à rencontrer. 6.3 Bonnes pratiques de la visualisation des données Maintenant que nous avons différents graphiques à notre portée mais aussi savons dans quel contexte utiliser chacun d’eux. Il est temps de faire un point sur la façon de réaliser ces graphiques, ce qu’on pourrait résumer par : « les bonnes pratiques en data visualisation ». Ce sont des « règles » simples qu’il est très vivement conseillé de suivre pour assurer la lisibilité et la compréhension des visualisations. 6.3. BONNES PRATIQUES DE LA VISUALISATION DES DONNÉES 52 F IGURE 6.10 – Exemple de nuage de points 6.3.1 Privilégiez la simplicité Lorsqu’on travaille dans l’analyse de données, on est souvent amené à travailler avec de nombreuses variables. Il est assez tentant de toutes les mixer en un seul graphique, en jouant par exemple sur les couleurs, sur la taille des points, sur la forme des points, etc. Par exemple : Sur F IGURE 6.11 – Un graphique « trop complexe » présentant cinq informations ce graphique, les cinq informations suivantes sont présentées : • la taille en abscisse ; • le poids en ordonnée ; • le revenu via la taille des points ; • le statut marital via la forme des points. Merde ! ! ! Vous admettrez que même si on peut arriver à le lire en s’aidant de la légende, ce graphique est trop chargé d’informations. Il vaut mieux dans ce genre de cas faire plusieurs gra- 6.3. BONNES PRATIQUES DE LA VISUALISATION DES DONNÉES 53 phiques avec peu d’informations sur chacun, mais qui soient clairs et interprétables au premier coup d’œil ! Afin d’éviter d’avoir un graphique illisible, privilégiez la simplicité, quitte à faire plusieurs graphiques. 6.3.2 Clariez votre graphique Il existe aujourd’hui de nombreuses représentations hyper stylées et complexes dans le monde de la data visualisation. Gardez à l’esprit que votre but premier, lors de la création d’une visualisation, est de rendre cette dernière la plus lisible possible. D’une certaine façon, un graphique doit être autosuffisant : n’importe qui doit être en mesure de le lire et de le comprendre, à partir des seuls éléments présents dessus et autour. Imageons cela en considérant le graphique suivant : F IGURE 6.12 – Exemple de graphique à clarifier Ce graphique peut paraître sympa, mais ... • de quoi parle-t-on ? • Quelles sont les informations représentées ? • À quoi correspond chaque barre ? • À quoi correspond chaque couleur ? Il manque beaucoup trop d’informations pour être en mesure de l’interpréter. À présent, que dire de celui-ci : C’est exactement le même graphique, sauf qu’à présent, nous avons la grille de lecture pour le lire et le comprendre. Qu’est-ce qui a rendu cela possible ? Quatre choses : • Les titres des axes. On a même ici précisé l’unité ! 6.3. BONNES PRATIQUES DE LA VISUALISATION DES DONNÉES 54 F IGURE 6.13 – Un graphique clarifié avec des titres, une légende et des valeurs pertinentes • La légende pour la compréhension des couleurs. • Le titre, qui nous indique clairement de qui et de quoi on parle. • Les valeurs indiquées au-dessus des barres pour éviter l’imprécision. Faites toujours en sorte de donner l’ensemble des informations pertinentes à votre lecteur, pour qu’il soit en mesure d’interpréter correctement son graphique. 6.3.3 Choisissez le graphique adéquat Cela fait directement écho à la présentation des différents graphiques faite précédemment. Considérons le graphique suivant : F IGURE 6.14 – Un exemple de graphique inadapté Nous avons la quantité en stock de chaque catégorie (A, B, C ou D) de différents produits. 6.3. BONNES PRATIQUES DE LA VISUALISATION DES DONNÉES 55 Question : seriez-vous en mesure de dire dans quelle catégorie, entre B et C, nous disposons le plus de stock ? Ce n’est pas évident, n’est-ce pas ? Prenons la visualisation pour les mêmes données mais cette fois-ci avec un diagramme en barres : F IGURE 6.15 – Un graphique plus adapté pour permettre de comparer les stocks La différence est d’un coup beaucoup plus nette, la catégorie C possède plus de stock que la catégorie B. Pourtant, ce sont exactement les mêmes données. C’est pour cela qu’un diagramme en barres est généralement plus avisé qu’un diagramme circulaire, à partir du moment où il y a plus de deux groupes à comparer. En jouant sur les axes, les graduations, les couleurs, le type de graphique, etc., on peut assez facilement masquer certaines informations sur un graphique, voire lui faire dire autre chose que ce qu’il veut vraiment dire. Choisissez bien tous ces différents paramètres avec précaution, afin de ne pas induire votre lecteur en erreur. Allons tracer des graphiques avec Matplotlib ! ! ! 7 Tracez des graphiques avec Matplotlib 7.1 Découvrez Matplotlib À ce stade, nous avons réuni de nombreuses informations sur nos clients, que nous pourrions mixer et représenter au sein de différents graphiques. Par exemple, plutôt que d’avoir l’information sous forme de tableau, il serait intéressant de représenter le chiffre d’affaires total par agence. On peut aussi regarder le taux d’endettement de nos clients en fonction de leur revenu, pour voir si une tendance se dégage. Il nous faut donc une librairie pour réaliser ces différents graphiques avec Python. Il en existe une multitude, et c’est parfois un peu compliqué de comprendre l’intérêt et la plus-value de l’une par rapport à une autre. C’est pourquoi je vous propose de regarder en détail la librairie principalement utilisée pour réaliser des visualisations : Matplotlib. Enfin, nous allons plutôt utiliser pyplot qui est inclus dans Matplotlib. Importer Matplotlib import matplotlib.pyplot as plt Chaque représentation graphique a une fonction correspondante avec Matplotlib : • nuage de points ou scatter plot, en anglais : scatter() ; • diagrammes en ligne ou en courbes : plot() ; • diagrammes en barres (bâton) : bar() ; • histogrammes : hist() ; • diagrammes circulaires : pie() . 7.2 Tracez vos premiers graphiques 7.2.1 Nuage de points Représentons le taux d’endettement en fonction du revenu. Ces deux variables sont numériques, sans évolution dans le temps : nous allons donc tracer un nuage de points, via la fonction 56 7.2. TRACEZ VOS PREMIERS GRAPHIQUES 57 scatter. Cette fonction nécessite de définir x et y, qui sont les valeurs à placer en abscisse et en ordonnée. plt.scatter(prets['revenu'], prets['taux_endettement']) F IGURE 7.1 – Application de la fonction scatter Il existe de nombreuses options pour personnaliser un nuage de points. On peut modifier : • la couleur des points, en utilisant l’argument color ou c ; • la taille des points, via l’argument size ou s ; • le type de marqueur via l’argument marker ; • la transparence des points via l’argument alpha . Reprenons le même graphique, avec des croix rouges dont la taille aura été modifiée, et avec 50% de transparence : plt.scatter(prets['revenu'], prets['taux_endettement'], s=60, alpha=0.5, c='red', marker='P') F IGURE 7.2 – Application d’options sur la fonction scatter Cette liste n’est pas exhaustive. Vous trouverez la liste complète des arguments sur la documentation officielle de la fonction : https://matplotlib.org/3.5.0/api/_as_gen/matplotlib. pyplot.scatter.html. 7.2. TRACEZ VOS PREMIERS GRAPHIQUES 58 On ava maintenant représenter le chiffre d’affaires total par agence. Comme nous l’avons vu précédemment, il existe deux possibilités pour cela : soit un diagramme à barres, soit un diagramme circulaire. Nous allons réaliser ces deux visualisations. 7.2.2 Diagramme circulaire Là où nous autres francophones et amateurs de fromages voyons dans le diagramme circulaire un camembert, les anglo-saxons y voient plutôt une tarte (pie, en anglais) à découper en plusieurs parts ! C’est de là que provient le nom de la fonction permettant de tracer un diagramme circulaire : pie. Son utilisation est très similaire à celle de scatter. Il y a deux arguments à préciser : labels, correspondant à la variable non numérique, celle sur laquelle ont été agrégées les données, et x, les valeurs agrégées correspondantes. La première étape va donc être d’agréger les données. data = prets.groupby('ville')['remboursement'].sum() data = data.reset_index() Le reset_index est nécessaire car nous allons avoir besoin de la variable ville dans la création de nos prochains graphiques. Traçons à présent notre diagramme circulaire à partir de ces données agrégées : plt.pie(x=data['remboursement'], labels=data['ville']) F IGURE 7.3 – Application de la fonction pie On peut améliorer ce graphique en affichant textuellement le pourcentage associé à chaque « part ». Pour cela, il faut spécifier un format numérique via l’argument autopct. plt.pie(x=data['remboursement'], labels=data['ville'], autopct='%.2f%%') Ce format permet d’afficher la part du chiffre d’affaires total réalisé par chaque agence, avec 2 chiffres après la virgule, et suivie du caractère % . 7.2. TRACEZ VOS PREMIERS GRAPHIQUES 59 7.2.3 Diagramme à barres L’alternative au diagramme circulaire est un diagramme à barres ! On peut représenter exactement la même information, mais avec une perspective différente. Pour utiliser la fonction bar, qui est l’implémentation de Matplotlib des diagrammes à barres, il faut préciser deux arguments : • x : les différentes valeurs de la variable non numérique, l’équivalent du labels de pie ; • height : les valeurs agrégées, équivalent du x de pie . Représentons maintenant la même information (le chiffre d’affaires total par agence) via un diagramme à barres. plt.bar(height=data['remboursement'], x=data['ville']) F IGURE 7.4 – Application de la fonction bar Remarque 7.1. Si vous souhaitez ordonner du plus grand au plus petit, il faudra tricher un petit peu. En effet, la fonction bar de Matplotlib ne permet pas, par défaut, de réaliser cela. MAIS on peut tout de même trier le data frame en amont. data_sorted = data.sort_values('remboursement', ascending=False) plt.bar(height=data_sorted['remboursement'], x=data_sorted['ville']) F IGURE 7.5 – Application d’options sur la fonction bar 7.2. TRACEZ VOS PREMIERS GRAPHIQUES 60 7.2.4 Histogramme Lorsqu’il s’agit de connaissance client dans le milieu bancaire, on arrive assez rapidement aux questions : • comment se répartissent nos clients en termes de revenus ? • a-t-on majoritairement des classes moyennes ? • des revenus plus modestes ? Hormis le cadre bancaire, des questions de statistique descriptives se posent généralement. L’histogramme est particulièrement utile lorsqu’on souhaite avoir une idée de la distribution d’une variable, et donc particulièrement adéquat pour répondre à cette problématique. La fonction Matplotlib correspondante est hist. Il suffit de lui passer en paramètre la variable numérique dont on souhaite connaître la distribution : plt.hist(prets['revenu']) Il existe de nombreuses possibilité de personnalisation, notamment sur le nombre de tranches, leur composition, etc. Vous pourrez retrouver tout cela, dans la documentation de la fonction : https://matplotlib.org/3.5.0/api/_as_gen/matplotlib.pyplot.hist.html . F IGURE 7.6 – Application de la fonction hist En un coup d’œil, on peut déterminer, grâce à l’histogramme, que nous avons majoritairement des revenus modestes au sein de notre clientèle. 7.2.5 Courbes On souhaite suivre l’évolution du chiffre d’affaires sur les quatre premiers mois, pour voir la façon dont il varie, et éventuellement anticiper la suite. Nous avons pour cela à notre disposition le chiffre d’affaires réalisé par notre banque sur les prêts de janvier à avril 2013. 7.2. TRACEZ VOS PREMIERS GRAPHIQUES 61 evolution_ca = pd.DataFrame({ 'date': ['2013-01-01', '2013-02-01', '2013-03-01', '2013-04-01'], "chiffre d'affaire": [183000, 193020, 179032, 219174] }) evolution_ca On a ici une évolution dans le temps, donc le choix de représentation le plus pertinent serait de tracer une courbe. Pour ce faire, on utilise la fonction plot de Matplotlib. Celle-ci prend deux arguments en entrée : les informations à mettre en abscisse, et celles à mettre en ordonnée. Traçons, l’évolution de notre chiffre d’affaire. plt.plot(evolution_ca['date'], evolution_ca["chiffre d'affaire"]) F IGURE 7.7 – Application de la fonction plot Il eut un chiffre d’affaires en hausse globale sur le premier tiers de 2013. Remarque 7.2. Comme pour le nuage de points, il existe de très nombreuses options de personnalisation. Vous pouvez jouer sur la couleur de la ligne (color ou c), son style (linestyle ou ls), son épaisseur (linewidth ou lw), si on souhaite ajouter un marqueur en plus de la ligne (marker), etc. Vous trouverez l’ensemble des possibilités sur la documentation de Matplotlib. Avec les mêmes données, traçons un graphique plot avec des lignes rouges hachurées, où on ajoute un point à chaque date. 7.3. CRÉEZ PLUSIEURS GRAPHIQUES SUR UNE MÊME FENÊTRE 62 plt.plot(evolution_ca['date'], evolution_ca["chiffre d'affaire"], marker='o', linestyle='--', color='red') F IGURE 7.8 – Application d’options sur la fonction plot Ces différents graphiques ne respectent pas vraiment les bonnes pratiques présentées précédemment. Ce n’est pas un oublie, on y remédiera dans le chapitre suivant. 7.3 Créez plusieurs graphiques sur une même fenêtre 7.3.1 Créez plusieurs graphiques dans une gure Nous avons six agences différentes avec plusieurs dizaines de clients par agence. Le responsable national souhaite avoir, en un seul graphique, une idée du comportement des agences en termes d’attribution de taux, en fonction du revenu. Question : représenter le revenu en fonction du taux est assez simple : on peut faire cela via un nuage de points. Mais comment représenter, en plus, l’information de l’agence ? Réponse En ajoutant une information supplémentaire à notre graphique, comme la couleur des points ! Cependant, il n’existe pas d’option par défaut avec Matplotlib pour mettre en couleur les points. On va être forcés de créer plusieurs graphiques –un par agence– qu’on va superposer sur une seule et même fenêtre graphique. # Importation des librairies et du jeu de données import numpy as np import pandas as pd import matplotlib.pyplot as plt data=pd.read_csv('prets.csv') data.head() 7.3. CRÉEZ PLUSIEURS GRAPHIQUES SUR UNE MÊME FENÊTRE 63 # Tracé du revenue en fonction du taux pour les villes # de Paris et de Toulouse df1 = data[data['ville']=='Paris', :] df2 = data[data['ville']=='Toulouse', :] plt.scatter(df1['revenu'], df1['taux'], label='Paris') plt.scatter(df2['revenu'], df2['taux'], label='Toulouse') plt.legend() plt.show() On a pu tracer pour deux villes. Afin de tracer pour toutes les villes ont va utiliser une boucle. for temp in data['ville'].unique(): df = data[data['ville']==temp, :] plt.scatter(df['revenu'], df['taux'], label=temp) # On affiche la legende et le graphique hors de la boucle plt.legend() plt.show() 7.3.2 Créez plusieurs sous gures dans une même gure : subplot La fonction figure de python permet de créer une figure en mui spécifiant des paramètres tels que : la taille de la figure, la résolution en dvi, ... import matplotlib.pyplot as plt # Créer une figure avec des paramètres spécifiques fig = plt.figure(figsize=(10, 6), dpi=100, facecolor='w', edgecolor='k') # Créer deux sous-graphiques plt.subplot(1, 2, 1) # 1 ligne, 2 colonnes, premier sous-graphe plt.plot([1, 2, 3], [4, 5, 6]) plt.subplot(3, 4, 2) # 3 lignes, 4 colonnes, deuxième sous-graphe plt.plot([1, 2, 3], [6, 5, 4]) # Afficher la figure plt.show() Dans le code Python précédent : Dans la fonction figure on a utilisé les arguments : • figsize=(10, 6) : Définit la taille de la figure en pouces (largeur, hauteur). 7.3. CRÉEZ PLUSIEURS GRAPHIQUES SUR UNE MÊME FENÊTRE 64 • dpi=100 : Définit la résolution de la figure en points par pouce. • facecolor='w' : Définit la couleur de fond de la figure (ici, blanc). • edgecolor='k' : Définit la couleur du bord de la figure (ici, noir). Pour les autres lignes de codes : • plt.subplot(1, 2, 1) : Crée un sous-graphe dans une figure avec 1 ligne et 2 colonnes, et place ce sous-graphe dans la première position. • plt.plot([1, 2, 3], [4, 5, 6]) : Trace des données sur le premier sous-graphe. • plt.subplot(3, 4, 2) : Crée un sous-graphe dans une figure avec 3 ligne et 4 colonnes, et place ce sous-graphe dans la deuxième position. • plt.plot([1, 2, 3], [6, 5, 4]) : Trace des données sur le deuxième sous-graphe. • plt.show() : Affiche la figure avec les sous-graphiques. Exercice d’application 7.1. Vous êtes en train de préparer le rapport mensuel à présenter chaque fin de mois à votre responsable. La présentation devra comprendre certains graphiques clés : vous allez donc devoir utiliser vos compétences en visualisation de données pour produire les différentes visualisations attendues. Les graphiques à produire sont donc : • la proportion de chaque type de prêt ; • le bénéfice mensuel réalisé en fonction du revenu du client pour les prêts immobiliers ; • la distribution des bénéfices réalisés ; • le bénéfice mensuel total réalisé par agence. Je vous invite à vous entraîner avec cet exercice : https: // colab. research. google. com/ drive/ 1bpkYUS1qaS89VksVuhXSDkzm7nPZulfl? usp= sharing . 8 Personnalisez vos graphiques avec Matplotlib Nous avons jusque-là tracé de nombreux graphiques fonctionnels. Cependant, ils ne sont pas vraiment conformes aux bonnes pratiques énoncées précédemment. En effet, sur la quasi totalité, il manque des éléments indispensables pour faciliter la lecture, comme le titre, les titres des axes ou la légende. Voyons maintenant comment ajouter tout cela avec Matplotlib. 8.1 Modiez les éléments extérieurs Considérons les données suivantes dont le graphique est ci-dessous. Ville Bordeaux Lyon Marseille Nice Paris Toulouse Chiffre d’affaires 15330.59 26064.67 40895.72 23544.24 94052.61 19286.18 F IGURE 8.1 – Graphique de chiffre d’affaires total par agence Vous remarquez que ce graphique est difficile à comprendre. Il lui manque en effet : • l’information globale de ce qui est représenté : le titre du graphique ; • des informations sur l’axe des ordonnées et sur l’unité utilisée ! 65 8.1. MODIFIEZ LES ÉLÉMENTS EXTÉRIEURS 66 Afin de compléter les informations manquantes, nous utiliserons des fonctions supplémentaires dans notre fenêtre graphique. # Créons notre jeu de données import pandas as pd dict = {'ville': ['Bordeaux', 'Lyon', 'Marseille', 'Nice', 'Paris', 'Toulouse'], 'chiffre_aff': [15330.59, 26064.67, 40895.72, 23544.24, 94052.61, 19286.18]} data = pd.DataFrame(dict) data.head() # Traçons et personnalisons notre graphique import matplotlib.pyplot as plt plt.bar(data['ville'], data['chiffre_aff']) # Ajoutons un titre ayant une police: arial et une taille de 18 plt.title("Chiffre d'affaire réalisé par agence", fontname='Arial', fontsize=18) # Renommons les axes des abscisses et des ordonnées plt.xlabel("Agences", color='red', fontweight='bold') # en rouge et en gras plt.ylabel("Chiffre d'affaire (¿)") plt.show() F IGURE 8.2 – Graphique de chiffre d’affaires total par agence après ajout d’éléments externes On a ainsi un graphique complet avec une grille de lecture claire. Il existe cependant d’autres options pour donner plus de clarté à une visualisation, ou pour en améliorer la qualité esthétique. 8.2. MODIFIEZ LES ÉLÉMENTS INTÉRIEURS 67 8.2 Modiez les éléments intérieurs Pour un graphique, il y a de nombreux aspects internes au graphique sur lesquels on peut jouer. Vous en avez déjà en aperçu un, avec l’affichage textuel des valeurs sur les pie plots ou les barplots. Il est également possible de jouer sur les graduations (ou ticks, en anglais), le quadrillage, ou encore les couleurs de fond. (a) Avant modification (b) Après modification F IGURE 8.3 – Graphique de chiffre d’affaires total par agence avant et après modification d’éléments internes Voyons comment passer de la Figure 8.3a à celle 8.3b. # Traçons et personnalisons notre graphique import matplotlib.pyplot as plt plt.figure(figsize=(10,6)) #afin d'agrandir la taille de l'image plt.bar(data['ville'], data['chiffre_aff']) # Ajoutons un titre ayant une police: arial et une taille de 18 plt.title("Chiffre d'affaire réalisé par agence", fontname='Arial', fontsize=18) # Renommons les axes des abscisses et des ordonnées plt.xlabel("Agences", color='red', fontweight='bold') #en rouge et en gras plt.ylabel("Chiffre d'affaire (¿)") plt.grid(axis='y') # grille sur l'axe y plt.ylim(0, 120_000) # pour borner l'axe des y plt.yticks([0, 30_000, 60_000, 90_000, 120_000]) #parametrer l'espacement sur l'axe y ca = data['chiffre_aff'].tolist() for i in range(len(ca)): 8.2. MODIFIEZ LES ÉLÉMENTS INTÉRIEURS 68 plt.text(i-0.2, ca[i]+2_000, round(ca[i], 1)) plt.save("chiffre_affaire_agence") #enregistre la figure dans le dossier courant plt.show() Remarque 8.1. Ce que nous avons vu n’est qu’une partie de tout ce qu’il est possible de faire avec Matplotlib. Plus on plonge dans l’aspect de personnalisation des graphiques, plus on se rend compte que les possibilités sont infinies. Si vous souhaitez aller plus loin, je peux vous rediriger vers ce notebook Jupyter (https: // nbviewer. org/ urls/ gist. githubusercontent. com/ Jwink3101/ e6b57eba3beca4b05ec146d9e38fc839/ raw/ f486ca3dcad44c33fc4e7ddedc1f83b82c02b492/ Matplotlib_ Cheatsheet ) qui répertorie des exemples concrets, que vous pourrez reproduire. Exercice d’application 8.1. Les bénéfices mensuels par type de prêt pour l’année 2021 viennent de sortir au niveau de l’agence où vous travaillez. Dans le cadre du rapport mensuel, il vous est demandé de réaliser un graphique spécifique représentant cette évolution, par type de prêt. Voici le graphique qui avait été obtenu l’an dernier : On cherche à reproduire le même graphique avec les données de l’année 2021. Je vous invite à vous entraîner avec cet exercice : https: // colab. research. google. com/ drive/ 1jkF6wpXEiHJfPkJOxTWcB-63vXrr_ QRK? usp= sharing Deuxième partie Calcul numérique 69 9 Calcul numérique approché 9.1 Erreurs absolue et relative Afin de définir les notions d’erreurs absolue et relative, nous avons besoin d’introduire les notions de quantités ou de valeurs exactes et de quantités approximatives ou valeurs approchées ; ce que nous illustrons ci-après au moyen d’exemples. — Exemples de quantités ou de valeurs exactes : 1, 1 , 3 5, √ 3, ln 2, π, 2π cos 7 , e, ... — Exemples de quantités approximatives ou de valeurs approchées (ci-après, en souligné) : √ 3 ≈ 1.732, π ≈ 3.14, ln 2 ≈ 0.69315, e ≈ 2.718, . . . Soient x un nombre réel et x∗ une valeur approchée de x : — Si x∗ > x, x∗ est dite valeur approchée par excès ; — Si x∗ < x, x∗ est dite valeur approchée par défaut. 9.1.1 Erreur absolue Définition 9.1. On appelle erreur absolue de x∗ sur x, la quantité : E = |x − x∗ |. Remarque 9.1. — Plus l’erreur absolue de x∗ est petite, plus x∗ est précise. — L’erreur absolue sert à déterminer la précision de la valeur approchée x∗ relativement à la valeur exacte x. 9.1.2 Erreur relative Définition 9.2. On appelle erreur relative de x∗ la quantité : Er = 70 E |x − x∗ | = . |x| |x| 9.2. INCERTITUDES ABSOLUE ET RELATIVE Remarque 9.2. 71 — L’erreur relative est souvent exprimée en pourcentage. — Elle est généralement utilisée pour comparer la précision de différentes valeurs approchées x∗ , y∗ , z∗ , . . . relativement à différentes valeurs exactes respectives x, y, z, . . . 9.2 Incertitudes absolue et relative Dans le cas où, en plus d’une valeur approchée qui lui est associée, une valeur exacte est connue, il est possible de déterminer ses erreurs absolue et relative mais souvent cette dernière ne l’est pas. Dans ce dernier cas, les erreurs absolue et relative deviennent impossible à calculer. Afin de les apprécier on introduit alors les notions d’incertitude absolue et d’incertitude relative. Définition 9.3. On appelle incertitude absolue d’une valeur approchée x∗ , tout nombre réel positif, noté ∆x, vérifiant : E = |x − x∗ | ≤ ∆x ou de manière équivalente : x∗ − ∆x ≤ x ≤ x∗ + ∆x. Remarque 9.3. — Une incertitude absolue est un majorant de l’erreur absolue. — Plus ∆x est petite, plus la valeur approchée x∗ est précise. D’où, en pratique, on prend le plus petit ∆x possible. — On écrit : x = x∗ ± ∆x ou encore x ≃ (x∗ ± ∆x), qui exprime le fait que : x ∈ [x∗ − ∆x, x∗ + ∆x]. x1 + x2 est une valeur approchée de x — Si x1 et x2 sont tels que : x1 ≤ x ≤ x2 alors x∗ = 2 x1 − x2 avec comme incertitude absolue : ∆x = . 2 — Souvent au lieu d’écrire : x = x∗ ± ∆x ou x ≃ (x∗ ± ∆x), on écrit : x = x∗ ± δ x.100% ou encore x ≃ (x∗ ± δ x.100%) où la quantité δ x est définie par : δx = ∆x . |x∗ | Cette quantité est appelée incertitude relative à x∗ . — Si l’incertitude relative δ x est connue, on en déduit un encadrement du nombre exact x comme ceci : x∗ (1 − δ x) ≤ x ≤ x∗ (1 + δ x) ou encore x = x∗ (1 ± δ x), car ∆x = x∗ |δ x|. 9.3 Représentation décimale d'un nombre approché 9.3.1 Représentation décimale d'un nombre approché Tout nombre réel positif x peut être représenté sous la forme d’un nombre décimal de développement limité ou illimité : x = am .10m + am−1 .10m−1 + · · · + am−n .10m−n + . . . où les ai sont les chiffres du nombre réel x (ai ∈ {0, 1, 2, . . . , 9}), avec am ̸= 0 et m est un entier naturel appelé rang supérieur du nombre réel x. 9.3. REPRÉSENTATION DÉCIMALE D’UN NOMBRE APPROCHÉ 72 Remarque 9.4. Dans le cas où le nombre réel x est négatif, il suffit de considérer la représentation décimale du nombre y = −x. Exemple 9.1. Considérons les exemples ci-dessous. 1. Exemple de développement limité : 7413.2680 = 7.103 + 4.102 + 1.101 + 3.100 + 2.10−1 + 6.10−2 + 8.10−3 + 0.10−4 . 2. Autre exemple d’un développement limité (faire attention aux zéros !) : 0.041502 = 4.10−2 + 1.10−3 + 5.10−4 + 0.10−5 + 2.10−6 . 3. Exemple de développement illimité : π = 3.14159265358 . . . = 3 · 100 + 1 · 10−1 + 4 · 10−2 + 1 · 10−3 + 5 · 10−4 + 9 · 10−5 + 2 · 10−6 + . . . Dans la pratique on n’utilise, essentiellement, que des nombres approchés de développements limités : x ≃ bm 10m + bm−1 10m−1 + · · · + b1 101 + · · · + bm−n 10m−n , avec bm ̸= 0. • Tous les chiffres bi , i = m, . . . , m − n, s’appellent chiffres significatifs du nombre approché x∗ . • Certains des bi peuvent être nuls. Les exemples suivants illustrent les cas où le zéro n’est pas considéré comme chiffre significatif. • x∗ = 2.10−3 + 0.10−4 + 1.10−5 + 0.10−6 qui s’écrit en notation décimale x∗ = 0.002010. Les zéros soulignés ne sont pas des chiffres significatifs. • x∗ = 3.106 +0.105 +0.104 +7.103 +0.102 +0.101 +0.100 qui s’écrit en notation décimale x∗ = 3007000. Les zéros soulignés ne sont pas des chiffres significatifs. Question : En règle générale, comment reconnaître un chiffre significatif ? Réponse : elle est apportée par la définition 9.4. Définition 9.4. On appelle chiffre significatif (c.s.) d’un nombre approché, tout chiffre dans sa représentation décimale différent du zéro ; et un zéro s’il se trouve entre deux chiffres significatifs ou s’il constitue un chiffre conservé. 9.4. CHIFFRES SIGNIFICATIFS EXACTS D’UN NOMBRE APPROCHÉ Exemple 9.2. 73 1. Une approximation à 6 décimales de 0.00502037 est : 2. Si on approche le nombre 1789 à la centaine près par 1800, à la place des chiffres négligés 8 et 9, on introduit deux zéros. Ils ne servent qu’à fixer l’ordre de grandeur du nombre pris comme valeur approchée ; ce ne sont pas des chiffres significatifs. Par contre si on approche le nombre 1789.7 à l’unité près par le nombre 1790, le zéro est alors un chiffre significatif. 9.4 Chires signicatifs exacts d'un nombre approché Soient x un nombre réel et x∗ une valeur approchée de x. Définition 9.5. Un chiffre significatif de x∗ est dit exact (c.s.e) si l’erreur absolue de ce nombre ne dépasse pas une demi-unité de rang du chiffre significatif, c’est-à-dire que : E = |x − x∗ | ≤ 0.5 × l’unité de rang du c.s. Ainsi : — Le n-ième c.s après la virgule est exact si : |∆x| ≤ 0.5 · 10−n . — Le n-ième c.s avant la virgule est exact si : |∆x| ≤ 0.5 · 10n−1 . Attention ! Un c.s.e de x∗ ne coïncide pas nécessairement avec le c.s. correspondant dans x. Proposition 9.1. — Si un c.s est exact, tous les c.s à sa gauche sont exacts. — Si un c.s n’est pas exact, tous ceux à sa droite ne le sont pas. Remarque 9.5. Si l’erreur absolue de x∗ ne dépasse pas une unité de rang du dernier c.s, on dit que x∗ est une valeur approchée au sens large ou encore qu’il est une valeur approchée à chiffres significatifs exacts au sens large. 9.5 Troncature et arrondissement d'un nombre Pour approcher le nombre π = 3.14159265358 . . . , on peut considérer la valeur approchée 3.14 ou encore 3.14159, etc., selon le besoin. Dans le premier cas, le nombre π est tronqué (coupé en éliminant une partie) après 2 décimales ; dans le second cas, après 5 décimales. 9.6. EXERCICES D’APPLICATION 74 Une méthode habituelle pour tronquer un nombre pour ne garder qu’un nombre fini de chiffres significatifs est l’arrondi. Règle d’arrondissement. Pour arrondir un nombre jusqu’à n c.s, on élimine les chiffres à droite du n-ième c.s conservé si l’on se trouve après la virgule, sinon on remplace par des zéros. Dans les deux cas on procède de la manière suivante : 1. Si le (n + 1)-ième c.s est strictement plus grand que 5, on augmente le n-ième chiffre de 1. Si, par contre, il est strictement plus petit que 5, les chiffres retenus restent inchangés. 2. Si le (n + 1)-ième c.s est égale à 5 alors deux cas sont possibles : — Tous les chiffres rejetés, situés après le (n + 1)-ième c.s, sont des zéros : on applique la règle du chiffre pair, c’est-à-dire que le n-ième chiffre reste inchangé s’il est pair. On lui ajoute 1 s’il est impair. — Parmi les chiffres rejetés, situés après le (n + 1)-ième c.s, il existe au moins un qui soit non nul : on ajoute 1 au n-ième chiffre. Remarque 9.6. Si on applique la règle d’arrondissement ci-dessus, l’erreur absolue de la valeur approchée ainsi obtenue, et qu’on appelle erreur d’arrondi, ne dépasse pas une demi-unité de rang du dernier c.s. retenu, c’est-à-dire qu’on a : E = |x−x∗ | ≤ 0.5×l’unité de rang du dernier c.s. retenu. Conséquence : Un nombre correctement arrondi ne possède que des c.s.e. 1.6 Relation entre erreur relative et c.s.e Proposition 9.2. Soient x un nombre réel, x∗ une valeur approchée de x et Er l’erreur relative à x∗ . — Si x∗ possède n c.s.e, alors Er < 5 · 10−n (sauf si le nombre est 1 suivi de (n − 1) zéros). — Si Er ≤ 0.5 · 10−n alors x∗ possède au moins n c.s.e. 9.6 Exercices d'application Exercice d’application 9.1. Vérifier que pour la valeur exacte x = 2/3, la valeur approchée x1∗ = 0.666667 est 1 000 fois plus précise que la valeur approchée x2∗ = 0.667. 1 2 Exercice d’application 9.2. Pour les valeurs exactes x = et y = , on considère les valeurs 3 15 approchées x∗ = 0.67 et y∗ = 0.07. Comparer les précisions de x∗ et y∗ . 10 Equations non linéaires 10.1 Racines d'équations non linéaires Définition 10.1. Soit f : R −→ R une fonction donnée, définie sur une partie D f de R. On dit que x∗ ∈ D f est une racine de l’équation non linéaire f (x) = 0 (10.1) f (x∗ ) = 0. (10.2) s’il vérifie Résoudre l’équation (10.1) consiste à déterminer tous les nombres réels x∗ ∈ D f tels que (10.2) soit vérifiée. En d’autres termes, on cherche à déterminer l’ensemble R = {x ∈ D f : f (x) = 0}, qui est l’ensemble des racines de l’équation (10.1). Il n’est pas toujours possible de résoudre complètement ce problème pour toutes les formes de fonctions f . L’ensemble R peut, en effet, avoir une grand nombre de structures possibles. Définition 10.2. On dit qu’une racine x∗ de l’équation (10.1) est séparable si on peut trouver un intervalle [a, b] contenu dans D f tel que x∗ soit la seule racine de cette équation dans cet intervalle ; ou encore si R ∩ [a, b] = {x∗ }. La racine x∗ est alors dite séparée (on dit aussi racine isolée). 10.1.1 Séparation des racines Il n’y a pas de méthode générale pour séparer les racines de l’équation (10.1). Dans la pratique, en dehors de l’étude théorique directe de f si celle-ci est donnée analytiquement, on utilise deux types de méthodes : une méthode graphique et une méthode dite de balayage. 10.1.2 Méthode graphique Elle consiste en ceci : 75 10.1. RACINES D’ÉQUATIONS NON LINÉAIRES 76 — soit on trace, expérimentalement ou par étude des variations de f , le graphe de la fonction f , puis on cherche son intersection avec l’axe Ox ; — soit on décompose f en deux fonctions f1 et f2 de sorte que l’équation (10.1) puisse s’écrire de manière équivalente : f1 (x) = f2 (x), puis on cherche les points d’intersection des graphes de f1 et f2 , dont les abscisses sont les racines de l’équation (10.1). Remarque 10.1. Les fonctions f1 et f2 sont souvent choisies de sorte que leurs courbes soient simples et connues. 10.1.3 Méthode de balayage On choisit un intervalle [a, b], contenu dans le domaine de définition D f de f , dans lequel on pense qu’il y a des racines de l’équation (10.1). On le subdivise par une suite croissante finie de points xi , i = 0, 1, . . . , n, avec x0 = a et xn = b. Si f est continue et si f (xi ) f (xi+1 ) < 0 alors il existe entre xi et xi+1 au moins une racine de (10.1) (c’est le théorème classique des valeurs intermédiaires). La méthode consiste donc à déterminer parmi les quantités f (xi ) f (xi+1 ), i = 0, 1, . . . , n − 1, celles qui sont négatives. Remarque 10.2. — La méthode de balayage ne permet de conclure qu’à l’existence d’au moins une racine dans un intervalle [xi , xi+1 ]. —• Si une racine x∗ est double ( f (x∗ ) = f ′ (x∗ ) = 0 et f ′′ (x∗ ) ̸= 0), cette méthode ne permet pas de la séparer (voir Figure 10.1). F IGURE 10.1 – Racine double —• De même, si deux racines sont très voisines, on risque de ne pas les séparer dans le processus ci-dessus. — L’intervalle de départ [a, b] doit être suffisamment grand afin de contenir les racines éventuelles de l’équation (10.1) ; mais, sauf dans des cas particuliers, il est difficile d’estimer correctement sa longueur. 10.2. APPROXIMATION DES RACINES : MÉTHODES ITÉRATIVES 77 F IGURE 10.2 – Racine voisine 10.2 Approximation des racines : Méthodes itératives Définition 10.3. On appelle méthode itérative un procédé de calcul de la forme : xk+1 = F(xk ), k∈N (10.3) dans lequel on part d’une valeur (approchée) x0 pour calculer x1 , puis à l’aide de x1 on calcule x2 , etc. La formule (10.3) est dite formule de récurrence. Le procédé est dit convergent si la suite des itérations (xk )k est convergente. Parmi les méthodes numériques en général et les méthodes itératives en particulier, les plus puissantes permettant la résolution approchée des équations du type (10.1), figure la méthode suivante. 10.2.1 Méthode de Newton-Raphson Partons par x∗ une racine exacte recherchée de l’équation (10.1) et par x0 une valeur approchée de x∗ . On suppose que f est de classe C2 au voisinage de x∗ . Le développement de Taylor d’ordre 2 de f donne : f (x∗ ) = f (x0 ) + f ′ (x0 )(x∗ − x0 ) + f ′′ (ξ ) ∗ (x − x0 )2 2 où ξ ∈]x∗ , x0 [. Comme f (x∗ ) = 0, en supposant f ′ (x0 ) ̸= 0, on tire x∗ de sorte à obtenir : x∗ = x0 − f (x0 ) f ′′ (ξ ) ∗ − (x − x0 )2 . f ′ (x0 ) 2 f ′ (x0 ) En négligeant le reste R2 = − f ′′ (ξ ) ∗ (x − x0 )2 , ′ 2 f (x0 ) (10.4) 10.2. APPROXIMATION DES RACINES : MÉTHODES ITÉRATIVES 78 la quantité x1 = x0 − f (x0 ) f ′ (x0 ) dans (10.4), qu’on notera x1 , constitue alors une valeur approchée améliorée de x∗ . En itérant le procédé on déduit la formule de récurrence : xk+1 = xk − f (xk ) , f ′ (xk ) k ∈ N. qu’on appelle : formule de récurrence de Newton-Raphson. Ainsi l’algorithme de Newton-Raphson s’écrit : x0 ∈ [a, b] f (xk ) , xk+1 = xk − ′ f (xk ) k∈N où l’intervalle [a, b] est choisi convenablement (voir section 10.2.2 ci-dessous). 2.3.2 Critère d'arrêt dans la méthode de Newton-Raphson Soient x∗ une racine isolée de l’équation (10.1), x0 une valeur approchée de x∗ et (xk )k la suite des approximations obtenue à l’aide de la formule de récurrence de Newton-Raphson. Comme nous avons supposé plus haut (voisinage de x∗ ), elle est donc aussi de classe C1 au voisinage de x∗ . Le développement de Taylor d’ordre 1 donne alors, pour k ∈ N : f (x∗ ) = f (xk ) + f ′ (ξk )(x∗ − xk ), ξk ∈]x∗ , xk [ ce qui donne : xk − x∗ = f (xk ) . f ′ (ξk ) D’autre part : xk+1 = xk − f (xk ) f (xk ) =⇒ xk+1 − xk = ′ . ′ f (xk ) f (xk ) En faisant l’approximation f ′ (ξ ) ≃ f ′ (xk ) on obtient finalement : |xk − x∗ | ≃ |xk+1 − xk |. Ainsi, si on veut calculer une valeur approchée de x∗ ayant la n-ième décimale qui est exacte (c’est-à-dire, avec la précision ε = 0.5 · 10−n ), il suffit d’aller dans les itérations jusqu’à ce que xk vérifie : |xk+1 − xk | ≤ 0.5 · 10−n . (10.5) La formule (10.5) s’appelle : critère d’arrêt de la méthode de Newton Raphson. 10.2. APPROXIMATION DES RACINES : MÉTHODES ITÉRATIVES 79 10.2.2 Convergence de la méthode de Newton Raphson Reprenons la formule de Newton-Raphson : xk+1 = xk − On a donc : xk+1 = g(xk ) où g(x) = x − g′ (x) = 1 − f (xk ) , f ′ (xk ) k ∈ N. f (x) . Comme f ′ (x) ( f ′ (x))2 − f (x) f ′′ (x) f (x) f ′′ (x) = , ( f ′ (x))2 ( f ′ (x))2 alors pour x = x∗ , x∗ étant une racine séparée de l’équation f (x) = 0, on a g′ (x∗ ) = 0 (puisque f (x∗ ) = 0) et de là |g′ (x∗ )| = 0 < 1 au voisinage de x∗ . Conséquence : Les conditions i) et ii) du théorème du point fixe (Théorème 2.3, page 31) sont donc réalisées, et par suite on a convergence de la suite des itérations (xk )k vers x∗ . C’est dans ce but qu’on choisit comme voisinage de x∗ un intervalle [a, b] de sorte que : 1. x∗ ∈ [a, b], 2. f est de classe C2 sur [a, b], 3. f ′ ̸= 0 sur [a, b]. On vérifiera ci-après qu’avec une condition supplémentaire sur l’intervalle [a, b], la suite (xk )k converge vers x∗ , indépendamment du choix de la valeur approchée initiale x0 ∈ [a, b]. Remarque 10.3. — f étant de classe C2 sur [a, b], f ′′ est continue sur [a, b] et donc bornée sur [a, b] par une constante M > 0 de manière à ce qu’on ait : ∀x ∈ [a, b], | f ′′ (x)| ≤ M. — f ′ ne s’annulant pas sur [a, b], il existe m > 0 tel que : ∀x ∈ [a, b], | f ′ (x)| ≥ m. Sous les conditions (1), (2) et (3) ci-dessus, faisons un développement de Taylor de f à l’ordre 1 au voisinage de xk pour obtenir : 1 f (x) = f (xk ) + f ′ (xk )(x − xk ) + f ′′ (ξk )(x − xk )2 2 où ξk ∈]x, xk [. Comme f (x) = 0 pour x = x∗ , il s’ensuit : 1 0 = f (xk ) + f ′ (xk )(x∗ − xk ) + f ′′ (ξk )(x∗ − xk )2 , 2 où ξk ∈]x∗ , xk [. 10.2. APPROXIMATION DES RACINES : MÉTHODES ITÉRATIVES 80 En divisant par f ′ (xk ) ̸= 0 et en translatant, on obtient : f ′′ (ξk )(x∗ − xk )2 f (xk ) = x∗ − xk + . − ′ f (xk ) 2 f ′ (xk ) Or xk+1 = xk − f (xk ) f (xk ) =⇒ − ′ = xk+1 − xk . ′ f (xk ) f (xk ) D’où, après simplification : xk+1 − x∗ = f ′′ (ξk )(x∗ − xk )2 , 2 f ′ (xk ) xk+1 − x∗ = f ′′ (ξk ) ∗ (x − xk )2 . 2 f ′ (xk ) soit Comme | f ′′ (x)| ≤ M et | f ′ (x)| ≥ m > 0, on aboutit alors à : |xk+1 − x∗ | ≤ M.|xk − x∗ |2 . 2m (10.6) Ainsi, on constate que l’erreur absolue de la (k + 1)-ième approximation est proportionnelle au carré de l’erreur absolue de la k-ième approximation. On dit que la méthode de Newton-Raphson est une méthode itérative du second ordre. M . L’inégalité (10.6) entraîne par induction : Posons C = 2m k+1 −1 |xk+1 − x∗ | ≤ C|xk − x∗ |2 ≤ C(C|xk−1 − x∗ |2 )2 = C3 |xk−1 − x∗ |4 ≤ · · · ≤ C2 De là, on déduit que : k k k k |xk − x∗ | ≤ C2 −1 |x0 − x∗ |2 . Comme : |x0 − x∗ | ≤ |b − a| = b − a, alors : |xk − x∗ | ≤ C2 −1 (b − a)2 , ou encore k [C(b − a)]2 |xk − x | ≤ . C ∗ Il y a donc convergence vers x∗ si : C(b − a) = M (b − a) < 1, 2m et c’est pour cette raison que l’on choisit [a, b] de longueur telle que : b−a < 2m . M k+1 |x0 − x∗ |2 . 10.2. APPROXIMATION DES RACINES : MÉTHODES ITÉRATIVES 81 Conclusion : Si en plus des conditions (1), (2) et (3), on choisit l’intervalle [a, b] tel que 2m b−a < , alors : ∀x0 ∈ [a, b], l’algorithme de Newton-Raphson converge (vers x∗ ). M Remarque 10.4 (Choix de la valeur approchée initiale x0 ). La valeur approchée initiale x0 est généralement choisie de manière à ce que : f (x0 ) f ′′ (x0 ) > 0. En particulier on prend x0 = a ou x0 = b, s’il vérifie cette condition. 2.3.6 Méthode du point xe Définition 10.4. Soit f : R −→ R une fonction dont le domaine de définition est une partie D f de R. On suppose que f est continue sur D f . On dit que x∗ ∈ D f est un point fixe de f si f (x∗ ) = x∗ . 11 Dérivation et intégration numérique 82 12 Equations diérentielles ordinaires 83 Bibliographie [1] B. Duchesne. Algèbre linéaire ii. 84