Introduction aux Bibliothèques Data Science avec Python
Dernière mise à jour : Novembre 2025
Parcours d'apprentissage
Partie 1 : Déploiement et Packaging
Partie 2 : Documentation du Programme
Partie 3 : Bases & Environnement
Partie 4 : Module Collections
Partie 5 : Calcul Scientifique avec NumPy
- Chapitre 1 : Introduction et Fondamentaux
- Chapitre 2 : Création de Tableaux
- Chapitre 3 : Inspection des Tableaux
- Chapitre 4 : Indexation et Slicing
- Chapitre 5 : Manipulation Avancée
- Chapitre 6 : Masquage (Indexation Booléenne)
- Chapitre 7 : Opérations et Broadcasting
- Chapitre 8 : Statistiques
- Chapitre 9 : Glossaire des Fonctions
- Chapitre 10 : Exercice Récapitulatif
Partie 6 : Bibliothèques du Calcul Scientifique SciPy
Partie 7 : Bibliothèques de Manipulation des Données Pandas
Partie 8 : Bibliothèques de Visualisation
Partie 9 : Machine Learning (Scikit-learn)
Partie 10 : Traitement de Langage Naturel (TALN)
Déploiement et Packaging
Définitions Fondamentales
Déploiement
Le déploiement d'une application se définit comme la promotion des composants d'une application depuis un environnement vers un autre (ex: du développement vers la production).
Packaging
Le packaging est l'étape cruciale de préparation. Il consiste à regrouper dans un fichier unique tous les scripts et ressources nécessaires pour que l'installation et le déploiement soient automatisés et reproductibles.
Le Packaging en Python
En Python, le packaging permet de partager et réutiliser du code proprement, sans duplication. C'est la différence entre "j'ai un script sur mon ordi" et "j'ai une bibliothèque installable par tout le monde".
Les outils de l'écosystème
- distutils : L'outil historique (inclus dans la bibliothèque standard), mais limité.
- setuptools : L'outil standard actuel, plus puissant, recommandé par la PyPA (Python Packaging Authority).
- wheel : Le format de distribution binaire moderne (plus rapide que les anciens "eggs").
Setuptools
Nous allons voir comment créer un vrai package Python installable, comme les bibliothèques que vous installez avec pip.
1 — Qu’est-ce que setuptools ?
setuptools est le standard pour packager votre code Python. Il sert à :
- Lui donner un nom et une version.
- Déclarer ses dépendances.
- Le rendre installable avec
pip install .
2 — Exemple concret : Package "calculatrice"
Nous allons créer un package nommé calculatrice contenant une fonction addition.
👉 Structure du projet
calculatrice/
├── pyproject.toml
├── setup.py
├── LICENSE
├── README.md
└── src/
└── calculatrice/
├── __init__.py
└── operations.py
3 — Contenu des fichiers
setup.py (Le cœur de setuptools)
from setuptools import setup, find_packages
setup(
name="calculatrice",
version="1.0.0",
packages=find_packages(where="src"),
package_dir={"": "src"},
description="Un mini package de calcul",
)
src/calculatrice/__init__.py
Permet d'exposer les fonctions directement.
from .operations import addition
src/calculatrice/operations.py
def addition(a, b):
return a + b
pyproject.toml (Configuration de build)
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
LICENSE
README.md
4 — Génération du package (Distribution)
Pour générer les archives de distribution (source et wheel) que vous pourrez partager ou uploader sur PyPI :
1. Installez l'outil de build :
pip install build
2. Lancez la construction :
py -m build
Cela va créer un dossier dist/ contenant vos fichiers .whl (Wheel) et .tar.gz (Source).
5 — Partager et installer manuellement (Sans Internet)
Vous n'êtes pas obligé de mettre votre package sur Internet (PyPI) pour le partager. Vous pouvez simplement envoyer le fichier généré (.whl) à un collègue par clé USB, mail ou dossier partagé.
Comment votre collègue l'installe ?
Il doit récupérer le fichier .whl (qui se trouve dans votre dossier dist/) et lancer :
pip install calculatrice-1.0.0-py3-none-any.whl
Note : Il doit être dans le dossier où se trouve le fichier .whl, ou donner le chemin complet.
6 — Installation en mode développement (Pour vous)
Ouvrez un terminal dans le dossier où se trouve setup.py et lancez :
pip install .
Le point . signifie "installe le package courant".
7 — Utilisation du package
Maintenant, vous pouvez aller n’importe où sur votre machine et faire :
from calculatrice import addition
print(addition(5, 7))
# Résultat : 12
🎉 Bravo ! Vous venez de créer votre propre package Python officiel, reconnu par pip et importable comme n’importe quelle librairie.
Publication sur TestPyPI
Avant de publier votre package sur le "vrai" PyPI (et qu'il soit visible par le monde entier), il est fortement recommandé de tester la procédure sur TestPyPI. C'est un environnement "bac à sable" identique à PyPI, mais dédié aux tests.
1. Création de compte
- Allez sur test.pypi.org et créez un compte.
- Important : Vous devez valider votre adresse email via le lien reçu.
- Notez votre nom d'utilisateur et votre mot de passe (ou créez un token API dans les paramètres du compte).
2. Installation des outils d'envoi
Nous allons utiliser Twine, l'outil officiel pour uploader des packages de manière sécurisée.
pip install twine
3. Upload du package
Une fois votre package généré (vous devez avoir le dossier dist/ avec vos fichiers .whl et .tar.gz), lancez la commande suivante :
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
Entrez votre nom d'utilisateur et votre mot de passe (ou __token__ comme utilisateur et votre token API comme mot de passe).
4. Vérification et Installation
Si tout s'est bien passé, Twine vous donnera un lien vers la page de votre projet sur TestPyPI (ex: https://test.pypi.org/project/calculatrice/).
Pour tester l'installation comme un utilisateur lambda, utilisez cette commande spéciale (car par défaut pip cherche sur le vrai PyPI) :
pip install --index-url https://test.pypi.org/simple/ --no-deps calculatrice
L'option --no-deps est souvent nécessaire sur TestPyPI car les dépendances (comme pandas ou numpy) n'y sont pas forcément présentes (elles sont sur le vrai PyPI).
Publication officielle sur PyPI
PyPI (Python Package Index) est le dépôt officiel. Une fois votre package ici, n'importe qui dans le monde pourra l'installer avec un simple pip install votre-package.
Attention : C'est définitif !
Contrairement à TestPyPI, vous ne pouvez pas écraser une version existante. Si vous avez publié la version 1.0.0 et que vous trouvez un bug 5 minutes après, vous devez publier une version 1.0.1. On ne peut pas "supprimer et remplacer" un fichier sur PyPI.
1. Préparer une belle page PyPI
Pour que votre page PyPI soit accueillante, assurez-vous que votre setup.py utilise votre README.md comme description longue.
# Dans setup.py
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
setup(
# ...
long_description=long_description,
long_description_content_type="text/markdown",
# ...
)
2. Publication (La vraie !)
- Créez un compte sur pypi.org (différent de TestPyPI).
- Activez l'authentification à deux facteurs (2FA), c'est désormais obligatoire.
- Créez un API Token dans les paramètres de votre compte.
- Lancez l'upload (sans spécifier d'URL cette fois, Twine utilise PyPI par défaut) :
twine upload dist/*
3. Semantic Versioning (SemVer)
Pour gérer vos mises à jour, suivez la convention MAJOR.MINOR.PATCH (ex: 1.0.0) :
- MAJOR (1.x.x) : Changements incompatibles (Breaking changes).
- MINOR (x.1.x) : Nouvelles fonctionnalités rétro-compatibles.
- PATCH (x.x.1) : Corrections de bugs rétro-compatibles.
Exercice : Comprendre les versions
Si vous définissez votre dépendance comme "requests>=2.0.0,<3.0.0" dans votre setup.py :
1. Est-ce que la version 2.5.0 sera acceptée ?
2. Est-ce que la version 3.0.1 sera acceptée ?
PyInstaller : Exécutables autonomes
PyInstaller est un outil qui convertit (gèle) des applications Python en exécutables autonomes (.exe sous Windows, binaires sous Linux/Mac).
Utilité principale
Permettre à des utilisateurs finaux de lancer votre application sans avoir besoin d'installer Python ni aucune bibliothèque sur leur machine. Tout est inclus.
Comment ça marche ?
PyInstaller analyse votre code, détecte toutes les dépendances (pandas, numpy, etc.), et les regroupe avec un interpréteur Python minimal dans un dossier ou un fichier unique.
1. Installation
pip install pyinstaller
2. Utilisation basique
Placez-vous dans le dossier de votre script principal (ex: mon_app.py) et lancez :
pyinstaller mon_app.py
Cela va créer plusieurs dossiers (build/, dist/) et un fichier .spec.
3. Options courantes
--onefile: Crée un seul fichier exécutable (au lieu d'un dossier). C'est l'option la plus populaire.--noconsole(ou-w) : Pour les interfaces graphiques (Tkinter, PyQt). Masque la fenêtre noire de terminal au lancement.--name "MonApp": Donne un nom spécifique à l'exécutable.
pyinstaller --onefile --noconsole mon_app.py
4. Exploiter le résultat
Une fois la compilation terminée, tout se trouve dans le dossier dist/.
- Si vous n'avez pas mis
--onefile: Vous aurez un dossierdist/mon_app/contenant l'exécutable et plein de fichiers .dll/.pyd. Vous devez distribuer tout le dossier. - Si vous avez mis
--onefile: Vous aurez juste un fichierdist/mon_app.exe. C'est ce fichier que vous pouvez envoyer à vos utilisateurs.
Exercice : Créer un exécutable unique
Vous avez un script analyse.py. Quelle commande lancez-vous pour obtenir un seul fichier .exe facile à partager ?
Documentation du Programme
Définitions et Outils
Documentation Logicielle
C'est un texte écrit qui accompagne le logiciel. Elle explique comment le logiciel fonctionne et/ou comment on doit l'employer. Elle est essentielle pour la maintenance et l'utilisation du code.
Sphinx & ReST
Sphinx est un outil qui génère automatiquement de la documentation (HTML, PDF) à partir de fichiers texte et des commentaires du code. Il utilise le format ReStructured Text (ReST).
Installation
pip install sphinx
Workflow de Création
Voici les étapes standards pour initialiser la documentation d'un projet :
-
Créer un dossier pour la documentation (souvent nommé
docs) à la racine du projet. -
Initialiser Sphinx en lançant la commande suivante dans ce dossier :
sphinx-quickstartCela va créer les fichiers de configuration de base :
conf.pyetindex.rst.
index.rst
Représente la structure (le sommaire) de la documentation.
conf.py
Contient toute la configuration : nom du projet, version, auteur, extensions, etc.
Exemple Concret : Projet "Bonjour"
Imaginons un projet contenant un module Bonjour.py que nous voulons documenter automatiquement.
1. Le Code Source (Bonjour.py)
Le code doit contenir des docstrings pour être reconnu par Sphinx.
def bonjour(nom):
"""Cette fonction permet d'afficher le message bonjour
:param nom: chaine de caractères
:return: un message de bonjour
:rtype: chaine de caractères
"""
return 'bonjour ' + nom
2. Configuration (conf.py)
Il faut dire à Sphinx où trouver le code et activer l'extension autodoc.
import os
import sys
# Indiquer le chemin vers le code source
sys.path.insert(0, os.path.abspath('../src'))
project = 'MonProjet'
copyright = '2024, Moi'
author = 'Moi'
release = '1.0'
# Activer l'extension autodoc
extensions = [
'sphinx.ext.autodoc'
]
3. Création de la page (bnj.rst)
Créez un fichier bnj.rst qui va automatiquement aspirer la documentation de votre fonction.
Documentation du module Bonjour
===============================
.. automodule:: Bonjour
:members:
4. Mise à jour de index.rst
Ajoutez votre nouveau fichier bnj.rst au sommaire principal.
.. toctree::
:maxdepth: 2
:caption: Contents:
bnj.rst
5. Génération finale
Dans le dossier docs, lancez la commande magique :
.\make html
Votre documentation magnifique est maintenant disponible dans docs/build/html/index.html ! 🎉
Module Collections
Introduction aux Collections
Le module collections implémente des types de données de conteneurs spécialisés, qui apportent des alternatives performantes et pratiques aux conteneurs natifs de Python (dict, list, set et tuple).
Vue d'ensemble des conteneurs
| Conteneur | Utilité |
|---|---|
| namedtuple | Une fonction permettant de créer une sous-classe de tuple avec des champs nommés. |
| deque | Un conteneur ressemblant à une liste mais avec ajout et suppression rapide à chacun des bouts. |
| ChainMap | Permet d’encapsuler de nombreux dictionnaires dans une seule unité. |
| Counter | Permet de compter les occurrences d'objets hachables. |
| OrderedDict | Une sous-classe de dictionnaire permettant de conserver l'ordre des entrées. |
| defaultdict | Une sous-classe de dictionnaire permettant de spécifier une valeur par défaut dans le constructeur. |
namedtuple
Les namedtuples assignent un sens à chaque position dans un tuple et permettent un code plus lisible et auto-documenté. Ils peuvent être utilisés partout où les tuples classiques sont utilisés.
Exemple : Point Géométrique
from collections import namedtuple
# Définition du namedtuple
Point = namedtuple('Point', ['x', 'y'])
# Création d'une instance
p = Point(11, y=22)
print(f"Point complet : {p}")
print(f"Coordonnée x : {p.x}")
print(f"Coordonnée y : {p[1]}") # Accès par index comme un tuple classique
Exemple 2 : Gestion de Produits
Utilisation pour structurer des données métier simples.
from collections import namedtuple
Produit = namedtuple("Produit", ["id", "nom", "prix", "stock", "categorie"])
p = Produit(1, "Clavier", 150, 20, "Informatique")
print(p.nom)
print(p.prix)
print(p.categorie)
Exercice 1 : Gestion d'Étudiants
Créez un namedtuple appelé 'Etudiant' avec les champs 'nom', 'age', et 'note'. Créez ensuite une instance pour un étudiant nommé "Alice", 20 ans, avec une note de 15. Affichez son nom et sa note.
Exercice 2 : Conversion de Dictionnaire
Soit le dictionnaire data = {'marque': 'Toyota', 'modele': 'Corolla', 'annee': 2020}. Convertissez ce dictionnaire en un namedtuple 'Voiture'.
deque (Double Ended Queue)
Une deque (prononcé "deck") est une généralisation des piles et des files. Elle supporte des ajouts et des suppressions efficaces (O(1)) aux deux extrémités, contrairement aux listes qui sont lentes pour les opérations en début de liste (O(n)).
Exemple : File d'attente rapide
from collections import deque
d = deque(['milieu'])
d.append('droite') # Ajout à la fin
d.appendleft('gauche') # Ajout au début
print(d)
d.pop() # Retire à la fin
d.popleft() # Retire au début
print(d)
Exemple 2 : Extension et Inversion
Ajout multiple d'éléments et inversion de l'ordre.
from collections import deque
d = deque([1, 2, 3])
d.extend([4, 5]) # Ajoute plusieurs éléments à la fin
d.extendleft([0, -1]) # Ajoute plusieurs éléments au début (ordre inversé)
print(d)
# Résultat : deque([-1, 0, 1, 2, 3, 4, 5])
d.reverse()
print(d)
Exercice 1 : Rotation
Créez une deque avec les éléments "A", "B", "C", "D". Utilisez la méthode rotate() pour décaler les éléments de 1 vers la droite, puis affichez le résultat.
Exercice 2 : Historique Limité
Créez une deque avec une taille maximale (maxlen) de 3. Ajoutez successivement les nombres 1, 2, 3, 4. Que contient la deque à la fin ?
ChainMap
ChainMap regroupe plusieurs dictionnaires ou autres correspondances pour créer une vue unique et pouvant être mise à jour. Si vous recherchez une clé, ChainMap la cherche dans le premier dictionnaire, puis le second, etc.
Exemple : Configuration par défaut et utilisateur
from collections import ChainMap
defauts = {'theme': 'light', 'langue': 'en'}
config_user = {'theme': 'dark'}
config = ChainMap(config_user, defauts)
# 'theme' est pris dans config_user (premier trouvé)
print(config['theme'])
# 'langue' est pris dans defauts (pas dans config_user)
print(config['langue'])
Exemple 2 : Modification de contexte
Les modifications affectent toujours le premier dictionnaire de la chaîne.
from collections import ChainMap
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
chain = ChainMap(dict1, dict2)
chain['b'] = 100 # Modifie dict1
chain['z'] = 999 # Ajoute à dict1
print(f"Chain: {chain}")
print(f"Dict1: {dict1}") # Modifié
print(f"Dict2: {dict2}") # Inchangé
Exercice 1 : Fusion de contextes
Vous avez deux dictionnaires : d1 = {'a': 1, 'b': 2} et d2 = {'b': 3, 'c': 4}. Créez une ChainMap qui priorise d1. Quelle est la valeur de 'b' ?
Exercice 2 : Ajout dynamique
Créez une ChainMap vide. Ajoutez-y un nouveau dictionnaire enfant au début avec la méthode new_child() contenant {'x': 10}.
Counter
Counter est une sous-classe de dictionnaire pour compter les objets hachables. C'est un outil très puissant pour faire des statistiques rapides sur des données.
Exemple : Compter les lettres
from collections import Counter
texte = "abracadabra"
compteur = Counter(texte)
print(compteur)
# Affiche Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
print(compteur.most_common(2))
# Affiche les 2 éléments les plus fréquents : [('a', 5), ('b', 2)]
Exemple 2 : Opérations Arithmétiques
Combinaison de compteurs avec des opérations mathématiques.
from collections import Counter
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)
print(f"Addition : {c1 + c2}") # a:4, b:3
print(f"Soustraction : {c1 - c2}") # a:2 (b est négatif donc ignoré)
print(f"Minimum : {c1 & c2}") # min(c1, c2) -> a:1, b:1
print(f"Maximum : {c1 | c2}") # max(c1, c2) -> a:3, b:2
Exercice 1 : Compter les mots
Soit la liste mots = ['chat', 'chien', 'chat', 'oiseau', 'chat', 'chien']. Utilisez Counter pour savoir combien de fois chaque mot apparaît.
Exercice 2 : Opérations sur les compteurs
Soit c1 = Counter(a=3, b=1) et c2 = Counter(a=1, b=2). Calculez la somme des deux compteurs (c1 + c2).
OrderedDict
OrderedDict est une sous-classe de dictionnaire qui se souvient de l'ordre dans lequel les entrées ont été ajoutées.
Note : Depuis Python 3.7, les dictionnaires standards conservent aussi l'ordre d'insertion, mais OrderedDict offre des méthodes supplémentaires comme move_to_end().
Exemple : Réorganiser
from collections import OrderedDict
d = OrderedDict()
d['a'] = 1
d['b'] = 2
d['c'] = 3
print(d)
# Déplacer 'a' à la fin
d.move_to_end('a')
print(d)
Exemple 2 : Pile vs File (LIFO/FIFO)
Utilisation de popitem pour retirer des éléments.
from collections import OrderedDict
d = OrderedDict(a=1, b=2, c=3)
# popitem(last=True) retire le dernier (LIFO - Pile)
print(f"Retiré (LIFO) : {d.popitem(last=True)}")
# popitem(last=False) retire le premier (FIFO - File)
print(f"Retiré (FIFO) : {d.popitem(last=False)}")
print(f"Reste : {d}")
Exercice 1 : Sensibilité à l'ordre
Contrairement aux dictionnaires classiques, deux OrderedDict ne sont égaux que si l'ordre des éléments est le même.
Créez od1 = OrderedDict([('a', 1), ('b', 2)]) et od2 = OrderedDict([('b', 2), ('a', 1)]). Vérifiez s'ils sont égaux. Comparez avec deux dictionnaires classiques identiques.
Exercice 2 : Déplacer au début
Créez un OrderedDict od = OrderedDict([('a', 1), ('b', 2), ('c', 3)]). Utilisez move_to_end(key, last=False) pour déplacer la clé 'c' au tout début.
defaultdict
Un defaultdict est un dictionnaire qui ne lève jamais d’erreur quand une clé n’existe pas. Il crée automatiquement une valeur par défaut quand vous accédez à une clé absente.
Le problème avec un dict normal
Avec un dictionnaire classique, accéder à une clé inexistante provoque une erreur :
d = {}
d["age"] += 1 # BOOM → KeyError
La solution avec defaultdict
Vous définissez le type de valeur par défaut (ici int qui vaut 0 par défaut) :
from collections import defaultdict
d = defaultdict(int) # int() = 0 par défaut
d["age"] += 1
print(d["age"])
# Résultat : 1
Pourquoi ? Parce que defaultdict(int) crée automatiquement {"age": 0} au moment de l'accès.
Les types de valeurs par défaut les plus utilisés
1) int → compteur automatique
from collections import defaultdict
compteur = defaultdict(int)
for lettre in "hello":
compteur[lettre] += 1
print(compteur)
2) list → pour grouper des données
from collections import defaultdict
groupes = defaultdict(list)
groupes["A"].append(1)
groupes["A"].append(2)
groupes["B"].append(3)
print(groupes)
# Résultat : {'A': [1, 2], 'B': [3]}
3) set → éviter les doublons
from collections import defaultdict
groupes = defaultdict(set)
groupes["x"].add(10)
groupes["x"].add(10)
groupes["x"].add(20)
print(groupes)
Exemple concret : Compter par catégorie
from collections import defaultdict
produits = [
("fruit", "pomme"),
("fruit", "banane"),
("legume", "carotte"),
]
groups = defaultdict(list)
for cat, item in produits:
groups[cat].append(item)
print(groups)
Exercice 1 : Regroupement de notes
Soit la liste notes = [('Alice', 15), ('Bob', 12), ('Alice', 18), ('Bob', 14)]. Utilisez un defaultdict(list) pour regrouper les notes par étudiant.
Exercice 2 : Inversion de dictionnaire
Soit d = {'a': 1, 'b': 2, 'c': 1}. Créez un dictionnaire inversé où les clés sont les nombres et les valeurs sont les listes des lettres correspondantes (ex: {1: ['a', 'c'], ...}).
Partie 1 : Bases & Environnement
Chapitre 1 : Manipulation des Modules
1. Création des modules
Un module est un fichier .py contenant un ensemble de variables, fonctions et classes que l'on peut importer et utiliser dans le programme principal (ou dans d'autres modules).
Pourquoi utiliser des modules ?
- Organisation : Séparation du code en fichiers logiques.
- Réutilisation : Écrire une fois, utiliser partout.
- Partage : Facilite la distribution du code.
Exemple de module (mon_module.py)
"""
Exemple de module, test
"""
exemple_variable = 3
def exemple_fonction():
"""Exemple de fonction"""
return 0
class ExempleClasse:
"""Exemple de classe"""
def __str__(self):
return "ExempleClasse"
2. Importation des modules
L'instruction import permet de charger un module. Python offre plusieurs syntaxes :
Import classique
import mon_module
print(mon_module.exemple_variable)
c = mon_module.ExempleClasse()
Import avec alias (recommandé)
import mon_module as mm
print(mm.exemple_variable)
c = mm.ExempleClasse()
Import spécifique
from mon_module import exemple_fonction
print(exemple_fonction())
Import total (Déconseillé ⚠️)
from mon_module import *
# Masque l'origine des fonctions
print(exemple_variable)
3. Où Python cherche-t-il les modules ?
Lors d'un import, Python cherche dans cet ordre :
- Le répertoire courant.
- Les répertoires de la variable d'environnement PYTHONPATH.
- Le chemin par défaut de l'installation (ex:
\Python\Python39\Lib).
Modifier le chemin dynamiquement
Vous pouvez ajouter un dossier temporairement via sys.path :
import sys
sys.path.insert(0, "E:/mon_dossier_perso")
print(sys.path)
4. Packages et Arborescence
Un package est un dossier contenant des modules et un fichier spécial __init__.py (obligatoire avant Python 3.3).
Structure typique
mesmodules/
├── __init__.py
├── monfichier.py
├── part1/
│ ├── __init__.py
│ └── monfichier2.py
└── part2/
├── __init__.py
└── monfichier3.py
Types d'importation
1. Importation Absolue
Chemin complet depuis la racine du projet.
import mesmodules.part1.monfichier2
from mesmodules.part1 import monfichier2
2. Importation Relative
Par rapport au fichier courant (nécessite d'être dans un package).
.: Dossier courant..: Dossier parent
# Depuis part1/monfichier2.py
from . import autre_fichier # Même dossier
from ..part2 import monfichier3 # Autre dossier
Exercice : Créer et Importer
1. Créez un fichier outils.py avec une fonction dire_bonjour(nom).
2. Créez un fichier main.py dans le même dossier.
3. Importez outils dans main.py avec l'alias tl et appelez la fonction.
Chapitre 2 : Manipulation des Bibliothèques (Pip)
1. Qu'est-ce qu'une bibliothèque ?
Une bibliothèque est un ensemble de modules (classes, fonctions, constantes) qui étend les capacités de Python (calcul, graphisme, réseau, etc.). La force de Python réside dans son immense écosystème, notamment via PyPI (Python Package Index).
La Bibliothèque Standard
Python est livré "piles incluses" avec de nombreux modules natifs :
2. PIP (Python Installer Package)
pip est l'outil standard pour installer et gérer des paquets externes. Il est inclus par défaut depuis Python 3.4.
Commandes d'installation courantes
| Action | Commande |
|---|---|
| Installer un paquet | pip install numpy |
| Version spécifique | pip install pandas==1.0.4 |
| Version minimale | pip install "requests>=2.0" |
| Mettre à jour | pip install --upgrade numpy |
| Désinstaller | pip uninstall numpy |
3. Créer sa propre bibliothèque
Pourquoi créer une bibliothèque au lieu de copier-coller ?
Imaginez que vous avez une fonction géniale calcul_impots(). Si vous copiez ce fichier dans 10 projets différents :
- ❌ Maintenance cauchemardesque : Si vous trouvez un bug, vous devez le corriger dans 10 endroits différents.
- ❌ Incohérence : Certains projets auront la version v1, d'autres la v2.
- ❌ Perte de temps : Copier manuellement des fichiers est source d'erreurs.
✅ La solution : Créer un package installable. Vous corrigez le bug une seule fois, vous augmentez la version, et tous vos projets en profitent via une simple mise à jour pip install --upgrade.
Exemple Concret : Bibliothèque "MaSuperLib"
Créons une bibliothèque composée de 3 fichiers Python pour bien comprendre l'organisation.
mon_projet/ ├── setup.py # Script d'installation └── ma_super_lib/ # Dossier du package ├── __init__.py # Point d'entrée (expose les fonctions) ├── operations.py # Module de calcul └── utils.py # Module utilitaire
1. ma_super_lib/operations.py
def additionner(a, b):
"""Retourne la somme"""
return a + b
def multiplier(a, b):
"""Retourne le produit"""
return a * b
2. ma_super_lib/utils.py
def formater_texte(texte):
"""Met en majuscules"""
return texte.upper() + " !!!"
3. ma_super_lib/__init__.py
Ce fichier expose les fonctions pour simplifier l'import.
from .operations import additionner
from .utils import formater_texte
# On choisit de ne pas exposer 'multiplier' par défaut
4. setup.py (Racine)
from setuptools import setup, find_packages
setup(
name="MaSuperLib",
version="1.0.0",
packages=find_packages(),
author="Votre Nom",
description="Une lib de démo"
)
Installation et Utilisation
Une fois ces fichiers créés, installez votre bibliothèque localement :
Installation :
pip install .
Ou py setup.py install
Utilisation (n'importe où) :
import ma_super_lib as msl
print(msl.additionner(5, 10))
# Affiche : 15
4. Techniques d'importation
Importer une fonction spécifique
from random import choice
# Utilisation directe
print(choice('ABC'))
Importer tout (Wildcard)
from random import *
# Toutes les fonctions sont dispos
print(randint(1, 10))
Chapitre 3 : Panorama des Bibliothèques Data Science
Python est le langage le plus utilisé dans la science de données. Il est possible de se contenter des fonctionnalités de ce langage ou bien d'utiliser un ensemble de bibliothèques externes open source qui facilitent la manipulation des données.
Calcul Scientifique
- NumPy : Calcul matriciel performant.
- SciPy : Algorithmes scientifiques avancés.
Manipulation des Données
- Pandas : Manipulation de tableaux (DataFrames).
Visualisation
- Matplotlib : Graphiques de base.
- Seaborn : Visualisation statistique esthétique.
Big Data
- Spark : Traitement distribué rapide.
- Hadoop : Stockage et traitement distribué.
Bases de Données
- MongoDB : Base NoSQL orientée documents.
- SQLite : Base SQL légère et intégrée.
- PostgreSQL : SGBD relationnel robuste.
Web Scraping
- Scrapy : Framework complet d'extraction.
- Beautiful Soup : Parsing HTML/XML simple.
Apprentissage Automatique (Machine Learning)
- Scikit-learn : Algorithmes classiques (régression, classification).
- Keras : Interface haut niveau pour réseaux de neurones.
- TensorFlow : Plateforme complète de ML (Google).
- PyTorch : Framework flexible de Deep Learning (Facebook).
Partie 2 : Calcul Scientifique avec NumPy
Chapitre 1 : Introduction et Fondamentaux
1. Qu'est-ce que NumPy ?
NumPy (Numerical Python) est la bibliothèque fondamentale pour le calcul scientifique en Python. Elle introduit un objet puissant : le ndarray (tableau à n-dimensions), qui permet de manipuler des vecteurs, des matrices et des tenseurs avec une efficacité redoutable.
Contrairement aux listes Python qui sont généralistes, les tableaux NumPy sont spécialisés pour le calcul numérique. Ils sont à la base de presque toutes les autres bibliothèques de Data Science (Pandas, Scikit-learn, TensorFlow).
Pourquoi utiliser NumPy plutôt que des listes ?
- 🚀 Vitesse fulgurante : NumPy est écrit en C. Les opérations sur les tableaux sont jusqu'à 50x plus rapides que les boucles Python classiques.
- 💾 Efficacité mémoire : Les tableaux NumPy stockent les données de manière contiguë en mémoire et utilisent des types fixes (ex: `int32`), occupant beaucoup moins de RAM.
- ⚡ Vectorisation : Vous pouvez additionner, multiplier ou transformer des millions de données en une seule ligne de code, sans écrire de boucles.
2. Installation et Importation
Si ce n'est pas déjà fait, installez NumPy via pip :
Dans vos scripts, la convention universelle est d'importer NumPy sous l'alias np :
import numpy as np
# Vérifier la version installée
print(f"Version de NumPy : {np.__version__}")
3. Constantes et Variables Importantes
NumPy inclut plusieurs constantes mathématiques et valeurs spéciales très utiles :
import numpy as np
print(f"Pi : {np.pi}") # 3.141592653589793
print(f"Euler (e) : {np.e}") # 2.718281828459045
print(f"Infini : {np.inf}") # inf (Infinity)
print(f"NaN : {np.nan}") # nan (Not a Number - Valeur manquante)
4. Comparaison : Liste vs NumPy
Regardons concrètement la différence de structure.
Liste Python (Classique)
- • Peut contenir n'importe quoi (mix de types).
- • Chaque élément est un objet Python complet (lourd).
- • Mémoire dispersée (pointeurs).
Tableau NumPy (ndarray)
- • Type unique pour tout le tableau (Homogène).
- • Données brutes compactes (léger).
- • Mémoire contiguë (accès rapide).
Chapitre 2 : Création de Tableaux
Il existe de nombreuses façons de créer des tableaux NumPy. Voici les méthodes les plus courantes que vous utiliserez au quotidien.
1. À partir d'une liste Python
La méthode la plus simple pour convertir vos données existantes.
import numpy as np
# Vecteur (1 Dimension)
liste_notes = [10, 15, 20]
arr_1d = np.array(liste_notes)
print("1D :", arr_1d)
# Matrice (2 Dimensions)
liste_2d = [[1, 2, 3], [4, 5, 6]]
arr_2d = np.array(liste_2d)
print("2D :\n", arr_2d)
2. Tableaux pré-remplis (Zeros, Ones, Full)
Utile pour initialiser des matrices avant de les remplir par des calculs.
import numpy as np
# Tableau de 5 zéros (souvent utilisé pour l'initialisation)
z = np.zeros(5, dtype=int)
print("Zeros :", z)
# Matrice 2x3 remplie de 1 (float par défaut)
o = np.ones((2, 3))
print("Ones :\n", o)
# Matrice 2x2 remplie de 7
f = np.full((2, 2), 7)
print("Full :\n", f)
# Matrice Identité (carrée avec des 1 sur la diagonale)
i = np.eye(3)
print("Identité :\n", i)
3. Générer des séquences (Arange, Linspace)
Pour générer des suites de nombres automatiquement.
import numpy as np
# np.arange(début, fin, pas) - Comme range() mais renvoie un tableau
# Note : la fin est EXCLUE
seq1 = np.arange(0, 10, 2)
print("Arange :", seq1) # [0 2 4 6 8]
# np.linspace(début, fin, nombre_points)
# Note : la fin est INCLUSE. Très utile pour les graphiques.
seq2 = np.linspace(0, 1, 5)
print("Linspace :", seq2) # [0. 0.25 0.5 0.75 1. ]
4. Génération Aléatoire (Random)
NumPy possède un module random très performant.
import numpy as np
# Fixer la graine pour avoir toujours les mêmes résultats (reproductibilité)
np.random.seed(42)
# 3 nombres aléatoires entre 0 et 1 (Distribution uniforme)
rand_uni = np.random.random(3)
print("Uniforme :", rand_uni)
# Matrice 2x2 d'entiers entre 0 et 10 (exclu)
rand_int = np.random.randint(0, 10, (2, 2))
print("Entiers :\n", rand_int)
# Distribution Normale (Gaussienne) : Moyenne=0, Écart-type=1
rand_norm = np.random.normal(0, 1, 5)
print("Normale :", rand_norm)
Chapitre 3 : Inspection des Tableaux
Une fois un tableau créé, il est crucial de savoir l'interroger pour connaître ses dimensions et son type.
| Attribut | Description |
|---|---|
| .ndim | Nombre de dimensions (1=vecteur, 2=matrice, 3=cube...) |
| .shape | Tuple représentant la forme (ex: (3, 4) pour 3 lignes, 4 colonnes) |
| .size | Nombre total d'éléments dans le tableau |
| .dtype | Type des données contenues (int64, float32, bool...) |
| .nbytes | Taille totale occupée en mémoire (en octets) |
Exemple complet d'inspection
import numpy as np
# Créons un tableau 3D (2 blocs, 3 lignes, 4 colonnes)
cube = np.random.randint(10, size=(2, 3, 4))
print("Tableau :\n", cube)
print("-" * 20)
print(f"Dimensions (ndim) : {cube.ndim}") # 3
print(f"Forme (shape) : {cube.shape}") # (2, 3, 4)
print(f"Taille (size) : {cube.size}") # 24 (2*3*4)
print(f"Type (dtype) : {cube.dtype}") # int32 ou int64
print(f"Mémoire (nbytes) : {cube.nbytes} octets")
Chapitre 4 : Indexation et Slicing (Découpage)
Accéder aux données est l'opération la plus courante. NumPy offre une syntaxe puissante pour extraire des sous-ensembles de données.
1. Accès par index (Comme les listes)
import numpy as np
arr = np.array([10, 20, 30, 40])
print(arr[0]) # 10 (Premier élément)
print(arr[-1]) # 40 (Dernier élément)
# Modification
arr[1] = 99
print(arr) # [10 99 30 40]
2. Slicing 1D (Tranches)
La syntaxe est [début : fin : pas].
- Si début est omis : commence à 0.
- Si fin est omis : va jusqu'au bout.
- Si pas est omis : pas de 1.
import numpy as np
x = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
print(x[:5]) # [0 1 2 3 4] (5 premiers)
print(x[5:]) # [5 6 7 8 9] (À partir de l'index 5)
print(x[4:7]) # [4 5 6] (De 4 inclus à 7 exclu)
print(x[::2]) # [0 2 4 6 8] (Un élément sur deux)
print(x[::-1]) # [9 8 ... 0] (Inverser le tableau)
3. Indexation et Slicing en 2D (Matrices)
En 2D, on utilise une virgule pour séparer les dimensions : [lignes, colonnes].
Règle d'or : tableau[ ligne , colonne ]
import numpy as np
M = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
])
# Accéder à un élément précis (Ligne 1, Colonne 2)
# Rappel : les indices commencent à 0
print(M[1, 2]) # 7
# Extraire une ligne entière (Ligne 0)
print(M[0, :]) # [1 2 3 4] (ou simplement M[0])
# Extraire une colonne entière (Colonne 1)
print(M[:, 1]) # [2 6 10]
# Extraire un sous-bloc (2 premières lignes, 2 premières colonnes)
print(M[:2, :2])
# [[1 2]
# [5 6]]
Chapitre 5 : Manipulation Avancée
1. Attention au piège : Copie vs Vue
Par défaut, le slicing crée une vue (référence). Modifier la vue modifie l'original ! Pour éviter cela, utilisez .copy().
Comportement par défaut (Vue)
a = np.array([1, 2, 3])
b = a[0:2] # Vue !
b[0] = 99
print(a) # [99 2 3] (MODIFIÉ !)
Avec .copy() (Sûr)
a = np.array([1, 2, 3])
b = a[0:2].copy() # Copie !
b[0] = 99
print(a) # [1 2 3] (INTACT)
2. Redimensionnement (Reshape)
La méthode .reshape() permet de changer la forme d'un tableau sans changer ses données.
Condition : Le nombre total d'éléments doit rester le même (ex: 12 éléments peuvent devenir 3x4 ou 2x6).
import numpy as np
# Créer un vecteur de 12 éléments
x = np.arange(1, 13)
print("Original :", x)
# Transformer en matrice 3 lignes x 4 colonnes
mat = x.reshape((3, 4))
print("3x4 :\n", mat)
# Astuce : Utiliser -1 pour que NumPy calcule la dimension manquante
col = x.reshape((-1, 1)) # "Autant de lignes que nécessaire, 1 colonne"
print("Colonne :\n", col)
3. Aplatissement (Flatten & Ravel)
Pour transformer un tableau multidimensionnel en vecteur 1D.
.flatten() : Crée une COPIE
m = np.array([[1, 2], [3, 4]])
f = m.flatten()
f[0] = 99
print(m)
# [[1 2] [3 4]] (Intact)
.ravel() : Crée une VUE (Rapide)
m = np.array([[1, 2], [3, 4]])
r = m.ravel()
r[0] = 99
print(m)
# [[99 2] [3 4]] (Modifié !)
4. Concaténation (Assemblage)
Pour assembler plusieurs tableaux en un seul.
np.concatenate() : La méthode générique
import numpy as np
a = np.array([1, 2])
b = np.array([3, 4])
# Axe 0 (Défaut) : bout à bout
print(np.concatenate((a, b))) # [1 2 3 4]
# En 2D
m1 = np.array([[1, 2], [3, 4]])
m2 = np.array([[5, 6]])
# Axe 0 (Vertical)
print(np.concatenate((m1, m2), axis=0))
# [[1 2]
# [3 4]
# [5 6]]
Helpers : vstack, hstack, dstack
A = np.array([1, 2, 3])
B = np.array([4, 5, 6])
# vstack (Vertical - Empilement)
print(np.vstack((A, B))) # [[1 2 3], [4 5 6]]
# hstack (Horizontal - Côte à côte)
print(np.hstack((A, B))) # [1 2 3 4 5 6]
# dstack (Profondeur - 3ème dimension)
print(np.dstack((A, B)))
# [[[1 4], [2 5], [3 6]]] (Dimensions 1x3x2)
5. Splitting (Découpage)
Pour diviser un tableau en plusieurs sous-tableaux.
import numpy as np
x = np.arange(16).reshape(4, 4)
# vsplit : Coupe horizontalement (sépare les lignes)
haut, bas = np.vsplit(x, 2)
print("Haut :\n", haut)
# hsplit : Coupe verticalement (sépare les colonnes)
gauche, droite = np.hsplit(x, 2)
print("Gauche :\n", gauche)
# split : Générique (ici axis=1 équivaut à hsplit)
p1, p2 = np.split(x, 2, axis=1)
6. Suppression d'éléments
Utilisez np.delete(tableau, index, axis).
import numpy as np
M = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Supprimer la ligne 1 (axis=0)
M_sans_L1 = np.delete(M, 1, axis=0)
# Supprimer la colonne 2 (axis=1)
M_sans_C2 = np.delete(M, 2, axis=1)
7. Tri (Sort)
Trier les éléments d'un tableau.
import numpy as np
arr = np.array([2, 1, 5, 3, 7, 4, 6, 8])
# np.sort() : Renvoie une copie triée (l'original ne change pas)
trie = np.sort(arr)
print(trie) # [1 2 3 4 5 6 7 8]
# Tri en place (modifie l'original)
arr.sort()
Chapitre 6 : Masquage (Indexation Booléenne)
Le masquage est une fonctionnalité ultra-puissante de NumPy qui permet de filtrer ou modifier des données selon une condition, sans boucle.
Le concept
- On crée une condition (ex:
arr > 5). Cela génère un tableau de Booléens (Masque). - On utilise ce masque comme index :
arr[masque]. - NumPy ne garde que les éléments où le masque est
True.
import numpy as np
a = np.array([1, 10, 3, 25, 7, 2])
# 1. Créer le masque (Qui est supérieur à 5 ?)
mask = a > 5
print(mask) # [False True False True True False]
# 2. Appliquer le filtre
print(a[mask]) # [10 25 7]
# Version compacte (très courante)
print(a[a > 5])
# 3. Modification conditionnelle (Ex: Remplacer les > 5 par 0)
a[a > 5] = 0
print(a) # [1 0 3 0 0 2]
Chapitre 7 : Opérations et Broadcasting
1. Opérations Arithmétiques (UFuncs)
Les opérateurs classiques (+, -, *, /) sont des raccourcis vers des fonctions universelles NumPy (UFuncs). Elles s'appliquent élément par élément.
| Opérateur | Fonction NumPy | Description |
|---|---|---|
| + | np.add() | Addition |
| - | np.subtract() | Soustraction |
| * | np.multiply() | Multiplication |
| / | np.divide() | Division |
| // | np.floor_divide() | Division entière |
| ** | np.power() | Puissance |
| % | np.mod() | Modulo (Reste) |
import numpy as np
a = np.arange(4) # [0 1 2 3]
print("a =", a)
print("a + 4 =", a + 4) # [4 5 6 7]
print("a * 2 =", a * 2) # [0 2 4 6]
print("a ** 2=", a ** 2) # [0 1 4 9]
2. Le Broadcasting (Diffusion)
Le broadcasting est la règle qui permet à NumPy de faire des calculs entre des tableaux de tailles différentes.
Règle simplifiée :
NumPy "étire" automatiquement les dimensions plus petites pour qu'elles correspondent aux plus grandes, si c'est possible.
Exemple 1 : Scalaire sur Vecteur
Le scalaire 5 est étiré en [5, 5, 5]
arr = np.array([1, 2, 3])
print(arr + 5)
# [6 7 8]
Exemple 2 : Vecteur sur Matrice
Le vecteur est ajouté à CHAQUE ligne.
M = np.ones((3, 3))
v = np.array([0, 1, 2])
print(M + v)
# [[1. 2. 3.]
# [1. 2. 3.]
# [1. 2. 3.]]
Chapitre 8 : Statistiques (Moyenne, Médiane, Pondérée)
En Data Science, il est crucial de bien choisir son indicateur de tendance centrale.
1. Moyenne (Mean)
La somme divisée par le nombre d'éléments.
⚠️ Sensible aux valeurs extrêmes (outliers).
Exemple vie réelle :
Consommation moyenne d'essence sur un trajet.
np.mean(arr)
2. Médiane (Median)
La valeur du milieu (50% au-dessus, 50% en dessous).
✅ Robuste aux valeurs extrêmes.
Exemple vie réelle :
Prix médian de l'immobilier (non faussé par les châteaux).
np.median(arr)
3. Moyenne Pondérée
Moyenne où chaque valeur a un "poids" différent.
Prise en compte de l'importance.
Exemple vie réelle :
Note du Bac (Maths coeff 7, Sport coeff 2).
np.average(arr, weights=w)
4. Mode
La valeur la plus fréquente dans le jeu de données.
Utile pour les catégories.
Exemple vie réelle :
La pointure de chaussures la plus vendue (gestion de stock).
via np.unique()
Exemple Concret : Salaires dans une startup
Imaginez une entreprise avec 4 stagiaires et 1 PDG.
Stagiaires : 1 500 € | PDG : 100 000 €
import numpy as np
salaires = np.array([1500, 1500, 1500, 1500, 100000])
# 1. Moyenne : "Le salaire moyen est élevé" (Trompeur !)
print(f"Moyenne : {np.mean(salaires)} €")
# Résultat : 21 200 € (Personne ne gagne ça !)
# 2. Médiane : "Le salaire médian est réaliste"
print(f"Médiane : {np.median(salaires)} €")
# Résultat : 1 500 € (Représente mieux la majorité)
# 3. Mode : "Le salaire le plus fréquent"
# NumPy n'a pas de fonction mode directe, on utilise unique
valeurs, comptes = np.unique(salaires, return_counts=True)
index_max = np.argmax(comptes)
mode = valeurs[index_max]
print(f"Mode : {mode} €") # 1 500 €
# 4. Moyenne Pondérée (Exemple notes)
notes = np.array([10, 20])
coeffs = np.array([1, 9]) # Le 20 compte 9 fois plus
moy_pond = np.average(notes, weights=coeffs)
print(f"Moyenne pondérée : {moy_pond}") # 19.0
Chapitre 9 : Glossaire des Fonctions Utiles
Référence rapide des fonctions essentielles pour l'analyse de données.
Agrégation & Stats
np.sum(arr): Somme totale.np.prod(arr): Produit des éléments.np.mean(arr): Moyenne.np.median(arr): Médiane.np.average(arr, weights=w): Moyenne pondérée.np.std(arr): Écart-type (Standard Deviation).np.var(arr): Variance.np.min() / np.max(): Minimum / Maximum.np.argmin() / np.argmax(): Indices du min/max.np.cumsum(): Somme cumulée.
Mathématiques & Utilitaires
np.abs(arr): Valeur absolue.np.exp(arr): Exponentielle.np.log(arr): Logarithme naturel.np.where(cond, x, y): Si cond alors x sinon y.np.unique(arr): Valeurs uniques triées.np.transpose(arr): Inverse les axes (Matrice transposée).np.any() / np.all(): Teste si au moins un / tous sont True.
Exemple : Statistiques sur un axe
import numpy as np
notes = np.array([[10, 15], [8, 12], [18, 20]]) # 3 élèves, 2 matières
# Moyenne de chaque élève (Axe 1 : colonnes)
print(np.mean(notes, axis=1)) # [12.5 10. 19. ]
# Meilleure note par matière (Axe 0 : lignes)
print(np.max(notes, axis=0)) # [18 20]
Chapitre 10 : Exercice Récapitulatif
Objectif : Manipuler une matrice de notes.
- Créez une matrice 4x3 avec des notes aléatoires entre 0 et 20 (entiers).
- Affichez la note de la 2ème ligne, 3ème colonne.
- Extrayez toutes les notes de la première ligne.
- Créez une copie de la matrice et remplacez toutes les notes < 10 par 10 dans cette copie.
Partie 3 : Bibliothèques du Calcul Scientifique SciPy
Chapitre 1 : Introduction et Objectif
1. Qu'est-ce que SciPy ?
SciPy (Scientific Python) est une bibliothèque open-source utilisée pour le calcul scientifique et technique. Elle s'appuie sur NumPy et fournit une vaste collection d'algorithmes mathématiques et de fonctions de commodité.
Elle fournit des algorithmes pour résoudre de nombreux problèmes scientifiques standards :
- ✓ L'optimisation
- ✓ L'intégration
- ✓ L'interpolation
- ✓ Les problèmes de valeurs propres
- ✓ Les équations algébriques
- ✓ Les équations différentielles
- ✓ Les statistiques
SciPy vs NumPy
Si SciPy utilise NumPy, pourquoi ne pas simplement utiliser NumPy ?
- NumPy fournit les blocs de construction de base (tableaux, opérations élémentaires).
- SciPy ajoute des algorithmes scientifiques de haut niveau (optimisation, traitement du signal, stats avancées) qui utilisent ces tableaux.
- SciPy est optimisée et contient des fonctions qui ne sont pas présentes dans NumPy pour garder NumPy léger.
2. Installation
Installez SciPy via pip (NumPy sera installé automatiquement comme dépendance) :
Vérification de l'installation
import scipy
import numpy as np
print(f"Version de SciPy : {scipy.__version__}")
Chapitre 2 : Organisation de SciPy
SciPy est organisée en sous-packages spécialisés couvrant différents domaines du calcul scientifique. Voici les principaux :
| Sous-package | Description |
|---|---|
| scipy.cluster | Algorithmes de partitionnement (Clustering, K-Means...) |
| scipy.constants | Constantes mathématiques et physiques (pi, c, h...) |
| scipy.integrate | Intégration numérique et équations différentielles |
| scipy.interpolate | Interpolation et lissage de données |
| scipy.io | Entrée et sortie (fichiers Matlab, Wav, etc.) |
| scipy.linalg | Algèbre linéaire avancée |
| scipy.optimize | Optimisation et recherche de racines |
| scipy.stats | Distributions statistiques et tests |
Exemple : Utilisation des constantes
SciPy fournit de nombreuses constantes physiques précises.
from scipy import constants
print(f"Pi : {constants.pi}")
print(f"Vitesse de la lumière (c) : {constants.c} m/s")
print(f"Constante de Planck (h) : {constants.h}")
# Conversion d'unités
print(f"1 Mile en mètres : {constants.mile}") # 1609.344
print(f"1 Gramme en kg : {constants.gram}") # 0.001
Chapitre 3 : Entrée et Sortie (IO)
SciPy et NumPy offrent de nombreux outils pour lire et écrire des données.
1. Fichiers Binaires NumPy (.npy, .npz)
Le format natif de NumPy est le plus efficace pour stocker des tableaux.
Sauvegarde
np.save(): Un seul tableau (.npy)np.savez(): Plusieurs tableaux (.npz)np.savez_compressed(): Compressé (.npz)
Chargement
np.load(): Charge .npy ou .npz
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
# Sauvegarder
np.save('mon_tableau.npy', arr)
# Charger
loaded_arr = np.load('mon_tableau.npy')
print(loaded_arr)
2. Fichiers Textes (CSV, TXT)
Pour l'interopérabilité avec Excel ou d'autres logiciels.
np.savetxt(): Sauvegarder en texte.np.loadtxt(): Charger depuis un texte (simple).np.genfromtxt(): Plus robuste (gère les valeurs manquantes).
3. Spécifique SciPy : Matlab & Autres
Le module scipy.io permet de lire des formats spécifiques comme ceux de Matlab (.mat), IDL, Matrix Market, etc.
from scipy import io
import numpy as np
# Créer un dictionnaire de données
data = {'vecteur': np.array([1, 2, 3]), 'label': 'expérience 1'}
# Sauvegarder au format MATLAB (.mat)
io.savemat('data.mat', data)
# Recharger
mat_data = io.loadmat('data.mat')
print(mat_data['vecteur'])
Chapitre 4 : Distributions Statistiques
Le module scipy.stats est très complet. Il contient des centaines de distributions de probabilité continues et discrètes, ainsi que des tests statistiques.
Distributions Continues
norm: Normale (Gaussienne)uniform: Uniformeexpon: Exponentiellegamma: Gammabeta: Betachi2: Chi-carré
Distributions Discrètes
binom: Binomialepoisson: Poissongeom: Géométriquebernoulli: Bernoulli
Méthodes communes aux distributions
Chaque objet de distribution (ex: norm) possède ces méthodes :
rvs(): Générer des nombres aléatoires (Random Variates).pdf(): Fonction de densité de probabilité (Probability Density Function).cdf(): Fonction de répartition (Cumulative Distribution Function).ppf(): Fonction quantile (Percent Point Function - inverse de CDF).
from scipy.stats import norm
import numpy as np
# Distribution Normale centrée réduite (mu=0, sigma=1)
# 1. Générer 5 nombres aléatoires
r = norm.rvs(size=5)
print("Aléatoire :", r)
# 2. Probabilité d'être inférieur à 0 (CDF)
# Pour une loi normale centrée, c'est 50% (0.5)
p = norm.cdf(0)
print("P(X < 0) :", p)
# 3. Densité en 0 (Le sommet de la cloche)
d = norm.pdf(0)
print("Densité en 0 :", d)
🧠 Exercice : Pile ou Face truqué
On lance 10 fois une pièce qui a 30% de chance de tomber sur Face. Quelle est la probabilité d'obtenir exactement 3 fois Face ?
Indice : Utilisez la loi Binomiale (binom).
Voir la solution
from scipy.stats import binom
n = 10 # Nombre d'essais
p = 0.3 # Probabilité de succès (Face)
k = 3 # Nombre de succès voulus
# pmf = Probability Mass Function (pour les discrets)
proba = binom.pmf(k, n, p)
print(f"Probabilité d'avoir 3 faces : {proba:.4f}")
# Résultat : ~0.2668 (soit 26.68%)
Partie 4 : Bibliothèques de Manipulation des Données Pandas
Chapitre 1 : Introduction et Concepts Clés
1. Qu'est-ce que Pandas ?
Pandas est une bibliothèque Python de manipulation et d'analyse de données de haut niveau, construite sur la base de NumPy. C'est un outil essentiel pour l'analyse de données en Python.
Utilité de Pandas
- Manipulation de données : Permet de manipuler des données tabulaires (similaires à une feuille de calcul Excel) et des séries chronologiques.
- Nettoyage et organisation : Aide à nettoyer, filtrer, trier et organiser les données brutes.
Structures de Données Principales
- Series (Série) : Un tableau unidimensionnel étiqueté, capable de contenir n'importe quel type de données.
- DataFrame : Une structure de données bidimensionnelle (tableau), avec des colonnes de types potentiellement différents, similaire à une table SQL.
Chapitre 2 : La Structure de Données Series (Série)
Une Série est la structure fondamentale pour construire des DataFrame. Elle peut être vue de deux manières : comme un tableau NumPy amélioré ou comme un dictionnaire Python spécialisé.
A. La Série comme un Tableau NumPy
Une série enveloppe à la fois une séquence de valeurs et une séquence d'indices. Contrairement aux tableaux NumPy simples, les indices peuvent être de n'importe quel type.
import pandas as pd
# Création d'une Série simple
data = pd.Series([0.25, 0.50, 0.75, 1.0])
print(data)
# 0 0.25
# 1 0.50
# 2 0.75
# 3 1.00
# dtype: float64
print("Valeurs :", data.values) # [0.25 0.5 0.75 1. ]
print("Index :", data.index) # RangeIndex(start=0, stop=4, step=1)
Accès aux éléments (Comme un tableau)
# Accès par indice numérique
print(data[1]) # 0.5
# Accès par tranche (Slicing)
print(data[1:3])
# 1 0.50
# 2 0.75
Indices Explicites
On peut définir nos propres indices (lettres, dates, etc.).
data = pd.Series([0.25, 0.5, 0.75, 1.0],
index=['a', 'b', 'c', 'd'])
print(data['c']) # 0.75
B. La Série comme un Dictionnaire Python
Une série fournit un mappage entre des clés (index) et des valeurs, tout comme un dictionnaire.
# Création à partir d'un dictionnaire
population_dict = {
'Casablanca': 6200000,
'Rabat': 1200000,
'Marrakech': 950000,
'Fès': 1100000
}
population = pd.Series(population_dict)
print(population)
# Casablanca 6200000
# Rabat 1200000
# ...
Accès par Clé
print(population['Rabat'])
# 1200000
# Vérifier l'existence
print('Paris' in population)
# False
Slicing avec Clés
⚠️ La borne de fin est INCLUSE !
print(population['Rabat':'Marrakech'])
# Rabat 1200000
# Marrakech 950000
Chapitre 3 : La Structure de Données DataFrame
Un DataFrame est la structure la plus puissante de Pandas. Il peut être considéré comme une collection de Séries alignées (partageant le même index). C'est l'équivalent d'une feuille Excel en Python.
1. Création d'un DataFrame
La méthode la plus simple est d'assembler plusieurs Séries ou d'utiliser un dictionnaire de listes.
# 1. Créons une deuxième série (Superficie)
area_dict = {
'Casablanca': 1615,
'Rabat': 118,
'Marrakech': 230,
'Fès': 240
}
area = pd.Series(area_dict)
# 2. Assemblons le tout dans un DataFrame
data = pd.DataFrame({
'population': population,
'superficie': area
})
print(data)
# population superficie
# Casablanca 6200000 1615
# Rabat 1200000 118
# Marrakech 950000 230
# Fès 1100000 240
2. Attributs Essentiels
Comme les Séries, les DataFrames possèdent des attributs pour inspecter leur structure.
| Attribut | Description |
|---|---|
| .index | Les étiquettes des lignes (ex: Casablanca, Rabat...) |
| .columns | Les noms des colonnes (ex: population, superficie) |
| .values | Les données brutes sous forme de tableau NumPy 2D |
| .shape | Dimensions (Lignes, Colonnes) |
print(data.index)
# Index(['Casablanca', 'Rabat', 'Marrakech', 'Fès'], dtype='object')
print(data.columns)
# Index(['population', 'superficie'], dtype='object')
print(data.values)
# [[6200000 1615]
# [1200000 118] ... ]
3. Inspection Rapide des Données
Pour avoir un aperçu rapide de vos données sans tout afficher :
| Méthode | Description |
|---|---|
| .head(n) | Affiche les n premières lignes (5 par défaut). |
| .tail(n) | Affiche les n dernières lignes (5 par défaut). |
| .info() | Résumé concis (types, non-nulls, mémoire). |
| .shape | Dimensions du DataFrame (lignes, colonnes). |
# Les 2 premières lignes
print(data.head(2))
# Les dimensions
print(data.shape)
# (4, 2) -> 4 lignes, 2 colonnes
# Infos techniques
data.info()
# class 'pandas.core.frame.DataFrame'
# Index: 4 entries, Casablanca to Fès
# Data columns (total 2 columns): ...
🧠 Exercice : Gestion de Stock
Créez un DataFrame représentant un stock de fruits avec les colonnes 'Prix' et 'Quantité'.
Fruits (Index) : Pomme, Banane, Orange.
Prix : 2, 1.5, 3
Quantité : 100, 50, 75
Voir la solution
import pandas as pd
stock = pd.DataFrame({
'Prix': [2, 1.5, 3],
'Quantité': [100, 50, 75]
}, index=['Pomme', 'Banane', 'Orange'])
print(stock)
Chapitre 4 : Indexation Avancée et Sélection
Accéder aux données avec précision est l'une des forces majeures de Pandas. Il est crucial de distinguer la sélection par étiquette (Label) de la sélection par position (Position).
📊 Dataset Fil rouge : Gestion RH
Pour ce chapitre et les suivants, nous utiliserons un DataFrame df_employes réaliste.
import pandas as pd
data = {
'Nom': ['Alice', 'Bob', 'Charlie', 'David', 'Eva'],
'Departement': ['RH', 'IT', 'Finance', 'IT', 'Marketing'],
'Salaire': [45000, 60000, 52000, 58000, 48000],
'Ville': ['Paris', 'Lyon', 'Paris', 'Marseille', 'Lyon']
}
df_employes = pd.DataFrame(data)
df_employes = df_employes.set_index('Nom') # Utilisons 'Nom' comme index
1. Sélection par Étiquette (.loc) vs Position (.iloc)
.loc[ligne, colonne]
Utilise les NOMS des index et des colonnes.
- Dernier élément inclus (inclusive).
- Erreur si le label n'existe pas.
.iloc[ligne, colonne]
Utilise les POSITIONS ENTIÈRES (0, 1, 2...).
- Comme les listes Python.
- Dernier élément exclu (exclusive).
# --- EXEMPLE AVEC .LOC ---
# Sélectionner le salaire de Alice
print(df_employes.loc['Alice', 'Salaire']) # 45000
# Sélectionner de Alice à Charlie, colonnes Departement et Ville
print(df_employes.loc['Alice':'Charlie', ['Departement', 'Ville']])
# --- EXEMPLE AVEC .ILOC ---
# Sélectionner la 2ème ligne (Bob), 3ème colonne (Salaire) -> Index 1, 2
print(df_employes.iloc[1, 2]) # 60000
# Sélectionner les 3 premières lignes et les 2 dernières colonnes
print(df_employes.iloc[0:3, -2:])
2. Filtrage conditionnel (Masquage)
C'est la méthode la plus courante pour extraire des données : poser une question logique (Vrai/Faux) au DataFrame.
# 1. Créer un masque (Filtre)
# Qui gagne plus de 50 000 ?
masque_salaire = df_employes['Salaire'] > 50000
# 2. Appliquer le masque
riches = df_employes[masque_salaire]
print(riches)
# Affiche Bob, Charlie, David
# 3. Conditions multiples (Et=&, Ou=|)
# Salaire > 50000 ET Ville est Paris
top_paris = df_employes[(df_employes['Salaire'] > 50000) & (df_employes['Ville'] == 'Paris')]
🧠 Exercice 1 : Sélection ciblée
À partir de df_employes, affichez uniquement les colonnes "Nom" (qui est l'index) et "Salaire" pour les employés dont le nom est "Bob" ou "Eva".
Indice : Utilisez .loc avec une liste de noms.
Voir la solution
# Sélection par étiquettes spécifiques
print(df_employes.loc[['Bob', 'Eva'], ['Salaire']])
🧠 Exercice 2 : Recherche complexe
Trouvez tous les employés du département "IT" qui habitent à "Lyon" ou "Marseille".
Voir la solution
# Méthode 1 : Booléens classiques
cond_dept = df_employes['Departement'] == 'IT'
cond_ville = df_employes['Ville'].isin(['Lyon', 'Marseille'])
print(df_employes[cond_dept & cond_ville])
# Méthode 2 : Query (Plus lisible)
print(df_employes.query("Departement == 'IT' and Ville in ['Lyon', 'Marseille']"))
Chapitre 5 : Nettoyage des Données
"Garbage in, garbage out". Avant toute analyse, il faut nettoyer les données. Pandas excelle dans la détection et la correction des anomalies comme les valeurs manquantes (NaN) ou les doublons.
📊 Dataset "Sale" (Dirty Data)
Introduisons des erreurs volontaires pour apprendre à les corriger.
import numpy as np
data_dirty = {
'Nom': ['Alice', 'Bob', 'Charlie', 'Alice', 'David'], # Alice en double
'Age': [25, 30, np.nan, 25, 40], # Manquant pour Charlie
'Salaire': [45000, 60000, 52000, 45000, np.nan] # Manquant pour David
}
df = pd.DataFrame(data_dirty)
print(df)
1. Gestion des Valeurs Manquantes (NaN)
Détection
df.isnull(): Renvoie True si NaN.df.isnull().sum(): Compte les NaN par colonne.
Correction
dropna(): Supprime la ligne/colonne.fillna(valeur): Remplace par une constante ou une moyenne.
# 1. Identifier les manques
print(df.isnull().sum())
# Age: 1, Salaire: 1
# 2. Stratégie radicale : Supprimer les lignes avec au moins un NaN
df_clean = df.dropna()
# 3. Stratégie douce : Remplacer (Imputation)
# Remplir l'âge manquant par la moyenne des âges
age_moyen = df['Age'].mean()
df['Age'] = df['Age'].fillna(age_moyen)
# Remplir le salaire par 0 ou une valeur fixe
df['Salaire'] = df['Salaire'].fillna(0)
2. Gestion des Doublons
Les doublons faussent les statistiques. Il est facile de les supprimer.
# Vérifier les doublons complets (toutes les colonnes identiques)
print(df.duplicated())
# Supprimer les doublons (garde la première occurrence par défaut)
df = df.drop_duplicates()
# Supprimer basé sur une seule colonne (ex: Nom unique)
df.drop_duplicates(subset=['Nom'], keep='last')
🧠 Exercice 1 : Nettoyage sélectif
Soit un DataFrame examens avec des colonnes "Etudiant", "Maths", "Physique". Certaines notes sont NaN.
Remplissez les NaN de "Maths" par 10 (moyenne par défaut) et supprimez les lignes où "Physique" est NaN.
Voir la solution
# Remplissage
examens['Maths'] = examens['Maths'].fillna(10)
# Suppression ciblée
examens.dropna(subset=['Physique'], inplace=True)
🧠 Exercice 2 : Doublons subtils
Dans un journal de transactions bancaires, supprimez les doublons mais uniquement ceux qui ont le même "id_transaction", en gardant la dernière entrée (la plus récente).
Voir la solution
import pandas as pd
# Création du DataFrame avec doublons
transactions = pd.DataFrame({
'id_transaction': [101, 102, 103, 101, 104],
'montant': [100, 250, 50, 100, 300],
'date': ['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-05', '2023-01-06']
})
print("Avant suppression :")
print(transactions)
# Suppression des doublons sur 'id_transaction', en gardant le dernier (le plus récent 2023-01-05 pour l'id 101)
transactions.drop_duplicates(subset=['id_transaction'], keep='last', inplace=True)
print("\nAprès suppression :")
print(transactions)
Chapitre 6 : Combinaison de DataFrames
Les données sont rarement dans un seul fichier. Il faut souvent assembler des morceaux (Concaténation) ou croiser des informations (Fusion/Jointure).
1. Concaténation (Empilement)
Imaginez coller deux feuilles Excel l'une en dessous de l'autre. C'est pd.concat().
# Deux équipes de vente
equipe_A = pd.DataFrame({'Vendeur': ['A1', 'A2'], 'Vente': [100, 200]})
equipe_B = pd.DataFrame({'Vendeur': ['B1'], 'Vente': [50]})
# Rassembler tout le monde (axe 0 par défaut = vertical)
total = pd.concat([equipe_A, equipe_B], ignore_index=True)
print(total)
# Vendeur Vente
# 0 A1 100
# 1 A2 200
# 2 B1 50
2. Fusion (Jointures SQL)
Pour enrichir un tableau avec des informations d'un autre (ex: ajouter le nom du département à un employé), on utilise pd.merge().
📊 Données relationnelles
df_staff = pd.DataFrame({
'Employe': ['Alice', 'Bob', 'Charlie'],
'Dept_ID': [1, 2, 99] # Charlie est dans un département inconnu
})
df_depts = pd.DataFrame({
'Dept_ID': [1, 2, 3],
'Nom_Dept': ['RH', 'IT', 'Marketing']
})
| Type (how) | Explication Logique |
|---|---|
| 'inner' | Intersection. Ne garde que ceux qui sont présents dans les deux tables. |
| 'left' | Garde tout le tableau de gauche (Employés) et ajoute les infos de droite si disponibles (sinon NaN). |
| 'outer' | Union. Garde tout le monde, quitte à avoir des trous des deux côtés. |
# Inner Join : Charlie va disparaître (Dept 99 inconnu)
print(pd.merge(df_staff, df_depts, on='Dept_ID', how='inner'))
# Left Join : Charlie reste, mais Nom_Dept sera NaN
print(pd.merge(df_staff, df_depts, on='Dept_ID', how='left'))
🧠 Exercice 1 : Consolidation mensuelle
Vous avez les ventes de Janvier et Février dans deux DataFrames distincts.
Créez un DataFrame unique ventes_Q1 contenant toutes les lignes.
Voir la solution
import pandas as pd
# Données de Janvier
janvier = pd.DataFrame({
'Produit': ['Pomme', 'Orange'],
'Ventes': [150, 200]
})
# Données de Février
fevrier = pd.DataFrame({
'Produit': ['Pomme', 'Banane'],
'Ventes': [120, 180]
})
# Consolidation
ventes_Q1 = pd.concat([janvier, fevrier], ignore_index=True)
print(ventes_Q1)
🧠 Exercice 2 : Catalogues produits
Table produits (id_prod, nom, prix, id_cat) et Table categories (id_cat, nom_categorie).
Affichez le nom de chaque produit avec le nom de sa catégorie. Si un produit n'a pas de catégorie, il doit quand même apparaître.
Voir la solution
import pandas as pd
# Table Produits
produits = pd.DataFrame({
'id_prod': [1, 2, 3, 4],
'nom': ['Laptop', 'Souris', 'Clavier', 'Écran'],
'prix': [1200, 20, 45, 150],
'id_cat': [100, 101, 101, 999] # 999 = Catégorie inconnue
})
# Table Catégories
categories = pd.DataFrame({
'id_cat': [100, 101, 102],
'nom_categorie': ['Informatique', 'Accessoire', 'Bureautique']
})
# Fusion Left Join pour garder tous les produits
resultat = pd.merge(produits, categories, on='id_cat', how='left')
print(resultat[['nom', 'nom_categorie']])
Chapitre 7 : Tri, Statistiques et GroupBy
Transformer des données brutes en informations utiles (Insights). La clé de voute de l'analyse est souvent le regroupement (GroupBy).
1. Tri et Analyses Rapides
Trier (Sort)
# Trier par Salaire décroissant
df.sort_values(by='Salaire', ascending=False)
# Multi-critères (Dept puis Salaire)
df.sort_values(by=['Dept', 'Salaire'])
Décrire (Describe)
# Stats rapides (mean, std, min, max...)
df.describe()
# Compter les occurrences (Fréquence)
df['Ville'].value_counts()
# Paris: 15, Lyon: 10...
2. Agrégation avec GroupBy
C'est l'opération "Split-Apply-Combine". On divise le DataFrame en groupes, on applique une fonction (somme, moyenne...), et on combine le résultat.
📊 Question Business
"Quel est le salaire moyen par Département ?"
# 1. Grouper par Département
groupes = df_employes.groupby('Departement')
# 2. Appliquer une agrégation (Moyenne sur le Salaire)
moyennes = groupes['Salaire'].mean()
print(moyennes)
# Departement
# Finance 52000.0
# IT 59000.0
# ...
# Plusieurs métriques d'un coup
stats = df_employes.groupby('Departement')['Salaire'].agg(['mean', 'max', 'count'])
🧠 Exercice 1 : Le Top 3
Affichez les 3 employés les mieux payés.
Voir la solution
df_employes.sort_values(by='Salaire', ascending=False).head(3)
🧠 Exercice 2 : Analyse des Ventes
Soit un DataFrame ventes (Region, Montant). Calculez le chiffre d'affaires total (somme) par Région.
Voir la solution
ca_region = ventes.groupby('Region')['Montant'].sum()
print(ca_region)
Chapitre 8 : Lecture et Écriture de Fichiers
Pandas communique avec le monde extérieur. Il peut lire et écrire dans une multitude de formats (CSV, Excel, JSON, SQL, Parquet...).
1. Lire des données (Input)
CSV (.csv)
Le format le plus universel.
df = pd.read_csv(
'donnees.csv',
sep=';', # Séparateur (souvent , ou ;)
encoding='utf-8', # Pour les accents
index_col='ID' # Utiliser une col comme index
)
Excel (.xlsx)
Nécessite la librairie openpyxl.
df = pd.read_excel(
'rapport.xlsx',
sheet_name='Feuille1'
)
2. Sauvegarder des données (Output)
Une fois vos analyses terminées (nettoyage, calculs...), vous devez sauvegarder le résultat.
# 1. Vers CSV (Le classique)
# index=False évite d'écrire la colonne d'index (0, 1, 2...) dans le fichier
df.to_csv('resultat_final.csv', index=False, sep=',')
# 2. Vers Excel
df.to_excel('bilan_2024.xlsx', sheet_name='Bilan')
# 3. Vers JSON (Pour le web)
df.to_json('data.json', orient='records', indent=4)
🧠 Exercice 1 : Lecture complexe
Vous devez lire un fichier "clients.txt" où les colonnes sont séparées par des tabulations (\t) et il n'y a pas d'en-tête (header).
Voir la solution
# header=None indique qu'il n'y a pas de noms de colonnes dans le fichier
# names=[...] permet de les définir manuellement
df = pd.read_csv('clients.txt', sep='\t', header=None, names=['ID', 'Nom', 'Email'])
🧠 Exercice 2 : Export filtré
Sauvegardez dans "rh_paris.csv" uniquement les employés habitant à Paris.
Voir la solution
df_paris = df_employes[df_employes['Ville'] == 'Paris']
df_paris.to_csv('rh_paris.csv')
Chapitre 9 : Statistiques Avancées et Séries Temporelles
Au-delà des bases, Pandas est un outil redoutable pour l'analyse temporelle (Time Series) et les calculs statistiques poussés.
📊 Dataset "Ventes Chronologiques"
import pandas as pd
data_ventes = {
'Date': ['2023-01-15', '2023-01-20', '2023-02-10', '2023-03-05', '2024-01-10'],
'Montant': [150, 200, 120, 300, 400],
'Produit': ['A', 'B', 'A', 'C', 'A']
}
df_ventes = pd.DataFrame(data_ventes)
# Conversion cruciale vers le format Datetime
df_ventes['Date'] = pd.to_datetime(df_ventes['Date'])
1. Manipulation de Dates (.dt accessor)
Une fois convertie, la colonne Date permet d'extraire très facilement des composants (Mois, Année, Jour de la semaine...).
Extraction
df_ventes['Annee'] = df_ventes['Date'].dt.year
df_ventes['Mois'] = df_ventes['Date'].dt.month
df_ventes['Jour'] = df_ventes['Date'].dt.day_name()
print(df_ventes[['Date', 'Annee', 'Jour']])
Filtrage Temporel
# Ventes après Février 2023
filtre = df_ventes['Date'] > '2023-02-01'
# Sélectionner une année spécifique
ventes_2024 = df_ventes[df_ventes['Date'].dt.year == 2024]
2. Fonctions Statistiques (Agrégation & Transformation)
| Fonction | Description |
|---|---|
| .sum(), .mean(), .median() | Somme, Moyenne, Médiane. |
| .cumsum() | Somme cumulée (Running Total). |
| .quantile(0.5) | Quantile (0.5 = Médiane, 0.25 = Q1...). |
| .var(), .std() | Variance et Écart-Type. |
# Somme cumulée des ventes au fil du temps
df_ventes = df_ventes.sort_values('Date')
df_ventes['Cumul'] = df_ventes['Montant'].cumsum()
print(df_ventes[['Date', 'Montant', 'Cumul']])
🧠 Exercice 1 : Analyse mensuelle
Ajoutez une colonne "Nom_Mois" (Janvier, Février...) et calculez le montant total des ventes par Mois (toutes années confondues).
Voir la solution
df_ventes['Nom_Mois'] = df_ventes['Date'].dt.month_name()
resultat = df_ventes.groupby('Nom_Mois')['Montant'].sum()
print(resultat)
🧠 Exercice 2 : Filtrage temporel
Affichez uniquement les ventes réalisées le "Week-end" (Samedi ou Dimanche).
Indice : Utilisez dt.dayofweek (5=Samedi, 6=Dimanche) ou dt.day_name().
Voir la solution
weekend = df_ventes[df_ventes['Date'].dt.dayofweek.isin([5, 6])]
print(weekend)
Chapitre 10 : Étude de Cas Complète (Projet Final)
Mettez en pratique tout ce que vous avez appris. Nous allons analyser un jeu de données de commandes E-commerce réaliste.
📦 Dataset "Commandes E-commerce"
data_ecommerce = {
'ID_Commande': [101, 102, 103, 104, 105, 106],
'Date': ['2023-01-15', '2023-01-20', '2023-02-10', '2023-02-12', '2023-03-05', '2023-03-05'],
'Produit': ['Ordinateur', 'Souris', 'Clavier', 'Écran', 'Ordinateur', 'Souris'],
'Categorie': ['High-Tech', 'Accessoire', 'Accessoire', 'High-Tech', 'High-Tech', 'Accessoire'],
'Prix': [1200, 25, 45, 200, 1200, np.nan], # Prix manquant pour la dernière souris
'Statut': ['Livré', 'Annulé', 'Livré', 'Livré', 'En cours', 'Livré']
}
df = pd.DataFrame(data_ecommerce)
df['Date'] = pd.to_datetime(df['Date'])
1. Nettoyage des données
Il manque un prix pour une souris. Sachant qu'une autre souris coûte 25€, nous allons remplir le NaN par la médiane des prix de la catégorie 'Accessoire'.
Voir le code
# Calculer la médiane des accessoires
mediane_accessoires = df.loc[df['Categorie'] == 'Accessoire', 'Prix'].median()
# Remplir les NaN
df['Prix'] = df['Prix'].fillna(mediane_accessoires)
2. Enrichissement (Feature Engineering)
Ajoutez une colonne 'Mois' pour analyser la saisonnalité.
Voir le code
df['Mois'] = df['Date'].dt.month_name()
3. Analyse Business
Question : Quel est le Chiffre d'Affaires (CA) total par Catégorie, en excluant les commandes "Annulées" ?
Voir le code
# 1. Filtrer les commandes valides (Non annulées)
df_valide = df[df['Statut'] != 'Annulé']
# 2. Grouper par Catégorie et sommer les Prix
ca_par_categorie = df_valide.groupby('Categorie')['Prix'].sum()
print(ca_par_categorie)
# Categorie
# Accessoire 70.0
# High-Tech 2600.0
4. Export du Rapport
Sauvegardez ce résumé dans un fichier CSV "rapport_ca.csv".
Voir le code
ca_par_categorie.to_csv('rapport_ca.csv')
Partie 5 : Bibliothèques de Visualisation
La visualisation des données est une étape cruciale en Data Science. Elle permet de comprendre les tendances, les modèles et les anomalies. Nous allons explorer les deux bibliothèques les plus populaires : Matplotlib et Seaborn.
Chapitre 1 : Matplotlib
1. Introduction
Matplotlib est la bibliothèque la plus utilisée en Python pour tracer des graphiques 2D. Elle est puissante, flexible et permet de créer des tracés de haute qualité en quelques lignes de code.
Types de graphiques courants
- 📈 Graphiques linéaires (Line plots)
- 📊 Diagrammes à barres (Bar charts)
- 📉 Histogrammes (Histograms)
- 📍 Diagrammes de dispersion (Scatter)
- 🍰 Graphiques circulaires (Pie charts)
2. Installation et Importation
Installation via pip :
Le module principal est pyplot, importé conventionnellement sous l'alias plt.
3. Exemple de Base
Traçons une simple courbe sinusoïdale.
import matplotlib.pyplot as plt
import numpy as np
# 1. Création des données
x = np.linspace(0, 10, 100)
y = np.sin(x)
# 2. Création du tracé (Line plot)
plt.plot(x, y, label='Sinus', color='blue')
# Ajout de titres et légendes
plt.title("Mon Premier Graphique")
plt.xlabel("Axe X")
plt.ylabel("Axe Y")
plt.legend()
# 3. Affichage
plt.show()
🧠 Exercice : Nuage de points
Générez 50 points aléatoires pour X et Y et affichez-les sous forme de nuage de points (Scatter plot) rouge.
Indice : Utilisez plt.scatter().
Voir la solution
import matplotlib.pyplot as plt
import numpy as np
x = np.random.rand(50)
y = np.random.rand(50)
plt.scatter(x, y, color='red', marker='x')
plt.title("Nuage de points aléatoires")
plt.show()
Chapitre 2 : Seaborn
1. Pourquoi Seaborn ?
Seaborn est construit au-dessus de Matplotlib. Elle fournit une interface de plus haut niveau pour dessiner des graphiques statistiques attrayants.
Avantages
- 🎨 Meilleurs thèmes et palettes par défaut.
- 🐼 Intégration native avec les DataFrames Pandas.
- 📊 Facilite les graphiques complexes (Heatmaps, Violins).
Installation
Import alias : sns
2. Exemple : Histogramme et Densité
Seaborn rend très simple l'ajout d'une estimation de densité (KDE) sur un histogramme.
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
# Générer des données suivant une loi normale
data = np.random.normal(size=1000)
# Création du graphique (histplot)
# kde=True ajoute la courbe de densité
sns.histplot(data, kde=True, color='teal')
plt.title("Distribution Normale avec Seaborn")
plt.show()
Chapitre 3 : Autres Outils
Bien que Matplotlib et Seaborn soient les standards, d'autres bibliothèques méritent d'être mentionnées pour des besoins spécifiques :
Plotly
Pour des graphiques interactifs (zoom, survol) utilisables dans le web.
Bokeh
Similaire à Plotly, excellent pour les tableaux de bord interactifs et les grands jeux de données.
Vispy
Basé sur OpenGL, pour la visualisation haute performance (millions de points) en temps réel.
Partie 6 : Bibliothèques d'Apprentissage Automatique (Machine Learning)
Chapitre 1 : Introduction à Scikit-learn (sklearn)
1. Qu'est-ce que Scikit-learn ?
Scikit-learn est la bibliothèque la plus populaire et la plus utilisée en Python pour l'apprentissage automatique (Machine Learning). Elle fournit des outils efficaces pour l'analyse statistique et la modélisation de données.
Caractéristiques Principales
- Simple et efficace : Interface cohérente pour tous les modèles.
- Open source : Disponible gratuitement.
- Réutilisable : Les modèles peuvent être sauvegardés.
- Interopérabilité : Construite sur NumPy, SciPy et Matplotlib.
Domaines Couverts
- Apprentissage Supervisé : Classification, Régression.
- Apprentissage Non Supervisé : Clustering, Réduction de dimension.
- Note : Le Deep Learning est plutôt géré par TensorFlow/PyTorch.
2. Installation
Chapitre 2 : Algorithmes et Fonctions Clés
Scikit-learn est organisé en sous-modules spécialisés. Voici les plus importants :
| Sous-module | Description | Exemples |
|---|---|---|
| sklearn.linear_model | Modèles linéaires | LinearRegression, LogisticRegression |
| sklearn.svm | Machines à Vecteurs de Support | SVC, SVR |
| sklearn.tree | Arbres de décision | DecisionTreeClassifier |
| sklearn.ensemble | Méthodes d'ensemble | RandomForestClassifier |
| sklearn.cluster | Clustering (Non supervisé) | KMeans, DBSCAN |
| sklearn.preprocessing | Prétraitement des données | StandardScaler, MinMaxScaler |
| sklearn.model_selection | Sélection et validation | train_test_split, GridSearchCV |
| sklearn.metrics | Mesures de performance | accuracy_score, mean_squared_error |
Chapitre 3 : Les Étapes d'un Projet ML (Workflow)
L'utilisation de Scikit-learn suit presque toujours le même schéma en 5 étapes.
Choisir la classe de Modèle
Importer la classe appropriée.
from sklearn.linear_model import LinearRegression
Instancier le Modèle (Hyperparamètres)
Créer une instance en fixant les paramètres qui ne sont pas appris.
model = LinearRegression()
Organiser les Données (X et y)
X (Features) : Matrice 2D (Lignes=Échantillons, Colonnes=Caractéristiques).
y (Target) : Vecteur 1D (La valeur à prédire).
Entraîner le Modèle (.fit)
C'est ici que le modèle "apprend".
model.fit(X_train, y_train)
Prédire (.predict)
Utiliser le modèle sur de nouvelles données.
y_pred = model.predict(X_test)
Exemple Complet : Régression Linéaire
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
# 1. Générer des données factices
X = np.random.rand(100, 1) * 10 # 100 valeurs entre 0 et 10
y = 2 * X + 1 + np.random.randn(100, 1) # y = 2x + 1 + bruit
# 2. Séparer les données (Train / Test)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# 3. Choisir et Instancier le modèle
model = LinearRegression()
# 4. Entraîner
model.fit(X_train, y_train)
# 5. Prédire
predictions = model.predict(X_test)
print(f"Coefficient appris : {model.coef_[0][0]:.2f}") # Devrait être proche de 2
print(f"Ordonnée à l'origine : {model.intercept_[0]:.2f}") # Devrait être proche de 1
🧠 Exercice : Classification Iris
Utilisez le jeu de données Iris (inclus dans sklearn) pour entraîner un arbre de décision (DecisionTreeClassifier) et prédire la classe d'une fleur.
Voir la solution
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 1. Charger les données
iris = load_iris()
X, y = iris.data, iris.target
# 2. Split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 3. Modèle
clf = DecisionTreeClassifier()
# 4. Entraînement
clf.fit(X_train, y_train)
# 5. Prédiction et Score
y_pred = clf.predict(X_test)
print(f"Précision : {accuracy_score(y_test, y_pred):.2f}")
Chapitre 4 : Autres Bibliothèques
Pour l'apprentissage profond (Deep Learning) et les réseaux de neurones complexes, d'autres bibliothèques sont privilégiées :
TensorFlow / Keras
Développé par Google. Très populaire pour la production et le déploiement de modèles.
PyTorch
Développé par Facebook (Meta). Très apprécié en recherche pour sa flexibilité et son approche dynamique.
Partie 7 : Bibliothèques du Traitement de Langage Naturel (TALN)
Le Traitement de Langage Naturel (TALN), ou NLP en anglais, est un sous-domaine de l'intelligence artificielle qui permet aux machines de lire, de comprendre et de générer le langage humain.
Chapitre 1 : NLTK (Natural Language Toolkit)
1. Présentation
NLTK est l'une des bibliothèques open source les plus populaires et puissantes en Python pour la recherche et le développement dans le domaine du TALN. C'est un outil d'introduction idéal pour les étudiants.
Utilité
- Fournit des ensembles de données (corpus) prêts à l'emploi.
- Offre des algorithmes pour effectuer des tâches courantes du TALN.
- Facilite l'apprentissage et le prototypage rapide.
Installation
Chapitre 2 : Sous-modules et Fonctionnalités Clés
NLTK est riche en sous-modules couvrant l'ensemble du processus de traitement du langage.
| Sous-module | Description | Exemples |
|---|---|---|
| nltk.tokenize | Segmentation du texte en unités (tokens). | word_tokenize, sent_tokenize |
| nltk.stem | Réduction des mots à leur racine. | PorterStemmer, WordNetLemmatizer |
| nltk.corpus | Collection de corpus (jeux de données). | WordNet, Brown Corpus |
| nltk.tag | Étiquetage des parties du discours (POS Tagging). | n-gram, HMM |
| nltk.classify | Classification de texte. | Naive Bayes, Decision Tree |
| nltk.chunk | Segmentation en morceaux (Chunking). | Named Entity Recognition (NER) |
Chapitre 3 : Exemple Détaillé - La Tokenisation
1. Concept
La tokenisation est un processus fondamental en TALN. Elle vise à transformer un texte brut en une série d'unités individuelles appelées tokens (mots, signes de ponctuation, symboles).
2. Exemple de Code
Tokenisons une phrase concernant l'OFPPT.
import nltk
from nltk.tokenize import word_tokenize
# Note : Il faut parfois télécharger les ressources NLTK au préalable
# nltk.download('punkt')
sentence = "L'OFPPT a développé au cours de la dernière décennie une coopération fructueuse avec de nombreux pays. Une politique volontariste qui s'est concrétisée par des projets allant de missions d'assistance technique, la formation, jusqu'à l'amélioration des compétences des formateurs."
tokens = word_tokenize(sentence)
print(tokens)
Résultat (Sortie Console)
['L', "'", 'OFPPT', 'a', 'développé', 'au', 'cours', 'de', 'la', 'dernière', 'décennie', 'une', 'coopération', 'fructueuse', 'avec', 'de', 'nombreux', 'pays', '.', 'Une', 'politique', 'volontariste', 'qui', 's', "'", 'est', 'concrétisée', 'par', 'des', 'projets', 'allant', 'de', 'missions', "d'assistance", 'technique', ',', 'la', 'formation', ',', 'jusqu', "'", 'à', "l'amélioration", 'des', 'compétences', 'des', 'formateurs', '.']
🧠 Exercice : Tokenisation de Phrases
Essayez d'utiliser sent_tokenize pour diviser le texte ci-dessus en phrases plutôt qu'en mots.
Voir la solution
from nltk.tokenize import sent_tokenize
sentences = sent_tokenize(sentence)
for s in sentences:
print("-", s)
# Résultat :
# - L'OFPPT a développé au cours de la dernière décennie une coopération fructueuse avec de nombreux pays.
# - Une politique volontariste qui s'est concrétisée par des projets...