Exploration et manipulation de tables
Dans ce cours, nous allons découvrir la manipulation de tables de données en informatique. Nous verrons le format CSV, comment importer et exploiter des données en Python, ainsi que les techniques d'interrogation et de tri. Ces compétences sont essentielles pour analyser et traiter des données dans de nombreux domaines.
Les données tabulaires (sous forme de tableaux) sont omniprésentes dans notre monde numérique. Savoir les manipuler efficacement est une compétence fondamentale en informatique moderne.
📄 Exemple de fichier CSV (eleves.csv) : nom,prenom,age,classe,moyenne Dupont,Marie,16,1NSI,15.5 Martin,Paul,17,1NSI,12.8 Durand,Sophie,16,1NSI,17.2 Moreau,Lucas,17,1NSI,14.1
Méthode | Avantages | Inconvénients |
---|---|---|
Lecture manuelle | Simple, contrôle total | Gestion des cas particuliers |
Module csv | Robuste, gère les virgules dans les données | À importer |
Pandas (avancé) | Très puissant | Bibliothèque externe |
🐍 Méthode 1 : Lecture simple avec split() def lire_csv_simple(nom_fichier): with open(nom_fichier, 'r', encoding='utf-8') as fichier: lignes = fichier.readlines() entetes = lignes[0].strip().split(',') donnees = [] for ligne in lignes[1:]: valeurs = ligne.strip().split(',') donnees.append(valeurs) return entetes, donnees # Utilisation entetes, eleves = lire_csv_simple('eleves.csv') print(entetes) # ['nom', 'prenom', 'age', 'classe', 'moyenne']
🐍 Méthode 2 : Module csv (recommandée) import csv def lire_csv_module(nom_fichier): with open(nom_fichier, 'r', newline='', encoding='utf-8') as fichier: lecteur = csv.reader(fichier) entetes = next(lecteur) # Première ligne = en-têtes donnees = [] for ligne in lecteur: donnees.append(ligne) return entetes, donnees # Lecture avec dictionnaires def lire_csv_dict(nom_fichier): with open(nom_fichier, 'r', newline='', encoding='utf-8') as fichier: lecteur = csv.DictReader(fichier) return list(lecteur) eleves_dict = lire_csv_dict('eleves.csv') # Chaque élève = {'nom': 'Dupont', 'prenom': 'Marie', ...}
Représentation | Structure | Avantages |
---|---|---|
Liste de listes | [['Dupont','Marie','16'], ...] | Simple, rapide |
Liste de dictionnaires | [{'nom':'Dupont', 'prenom':'Marie'}, ...] | Plus lisible, accès par nom |
🔍 Exemples d'interrogation : # Rechercher tous les élèves d'une classe def eleves_classe(eleves, classe_recherchee): resultats = [] for eleve in eleves: if eleve['classe'] == classe_recherchee: resultats.append(eleve) return resultats # Rechercher les élèves avec une moyenne > seuil def eleves_moyenne_superieure(eleves, seuil): resultats = [] for eleve in eleves: if float(eleve['moyenne']) > seuil: resultats.append(eleve) return resultats # Compter les élèves par classe def compter_par_classe(eleves): compteurs = {} for eleve in eleves: classe = eleve['classe'] compteurs[classe] = compteurs.get(classe, 0) + 1 return compteurs
📊 Tri simple par un critère : # Tri par nom (ordre alphabétique) eleves_tries_nom = sorted(eleves, key=lambda x: x['nom']) # Tri par moyenne (ordre décroissant) eleves_tries_moyenne = sorted(eleves, key=lambda x: float(x['moyenne']), reverse=True) # Tri par âge (ordre croissant) eleves_tries_age = sorted(eleves, key=lambda x: int(x['age'])) # Fonction de tri personnalisée def trier_par_moyenne(eleves): return sorted(eleves, key=lambda x: float(x['moyenne']), reverse=True)
🎯 Tri multi-critères avec tuples : # Tri par classe puis par moyenne décroissante eleves_tries = sorted(eleves, key=lambda x: (x['classe'], -float(x['moyenne']))) # Tri par nom puis prénom (ordre alphabétique) eleves_tries = sorted(eleves, key=lambda x: (x['nom'], x['prenom'])) # Tri complexe : classe, puis moyenne (desc), puis nom def tri_complexe(eleve): return (eleve['classe'], -float(eleve['moyenne']), # - pour ordre décroissant eleve['nom']) eleves_tries = sorted(eleves, key=tri_complexe) # Fonction générique de tri multi-critères def trier_multi_criteres(eleves, criteres): """ criteres = [('classe', False), ('moyenne', True), ('nom', False)] False = croissant, True = décroissant """ def cle_tri(eleve): cle = [] for nom_critere, decroissant in criteres: valeur = eleve[nom_critere] # Conversion si nécessaire if nom_critere in ['age', 'moyenne']: valeur = float(valeur) if decroissant: valeur = -valeur if isinstance(valeur, (int, float)) else valeur cle.append(valeur) return tuple(cle) return sorted(eleves, key=cle_tri)
Fonction | Utilité | Exemple |
---|---|---|
Moyenne | Calculer la moyenne d'une colonne | sum(notes)/len(notes) |
Min/Max | Trouver les valeurs extrêmes | min(ages), max(ages) |
Groupement | Regrouper par catégorie | Élèves par classe |
Filtrage | Sélectionner selon critères | Moyenne > 15 |
📈 Fonctions d'analyse statistique : def calculer_statistiques(eleves, colonne): """Calcule les statistiques d'une colonne numérique""" valeurs = [float(eleve[colonne]) for eleve in eleves] return { 'moyenne': sum(valeurs) / len(valeurs), 'min': min(valeurs), 'max': max(valeurs), 'etendue': max(valeurs) - min(valeurs) } def grouper_par(eleves, critere): """Groupe les élèves selon un critère""" groupes = {} for eleve in eleves: cle = eleve[critere] if cle not in groupes: groupes[cle] = [] groupes[cle].append(eleve) return groupes # Utilisation stats_moyennes = calculer_statistiques(eleves, 'moyenne') groupes_classe = grouper_par(eleves, 'classe')
🎓 Application : Système de gestion d'élèves import csv class GestionEleves: def __init__(self, fichier_csv): self.eleves = self.charger_donnees(fichier_csv) def charger_donnees(self, fichier): with open(fichier, 'r', newline='', encoding='utf-8') as f: return list(csv.DictReader(f)) def rechercher(self, critere, valeur): return [e for e in self.eleves if e[critere] == valeur] def trier(self, critere, decroissant=False): if critere in ['age', 'moyenne']: return sorted(self.eleves, key=lambda x: float(x[critere]), reverse=decroissant) return sorted(self.eleves, key=lambda x: x[critere], reverse=decroissant) def statistiques_classe(self): stats = {} for eleve in self.eleves: classe = eleve['classe'] if classe not in stats: stats[classe] = {'count': 0, 'moyennes': []} stats[classe]['count'] += 1 stats[classe]['moyennes'].append(float(eleve['moyenne'])) # Calcul des moyennes par classe for classe, data in stats.items(): data['moyenne_classe'] = sum(data['moyennes']) / len(data['moyennes']) return stats # Utilisation gestion = GestionEleves('eleves.csv') meilleurs = gestion.trier('moyenne', decroissant=True)[:3] stats = gestion.statistiques_classe()
sorted()
avec key=
pour les tris personnalisésLa manipulation de tables de données est une compétence essentielle en informatique. Maîtriser l'importation CSV, l'interrogation et le tri des données vous permettra d'analyser efficacement de nombreux jeux de données. Ces techniques constituent la base de l'analyse de données et vous préparent aux outils plus avancés comme les bases de données et les bibliothèques spécialisées.
Objectif pédagogique : Maîtriser la lecture d'un fichier CSV et l'affichage des premières lignes.
Énoncé :
Vous disposez d'un fichier CSV etudiants.csv
contenant : nom, âge, note, ville
1. Lisez le fichier avec la bibliothèque csv
de Python.
Conseil : Utilisez csv.DictReader
pour une manipulation plus facile.
2. Affichez les 3 premières lignes de données.
Astuce : Utilisez une boucle avec un compteur pour limiter l'affichage.
import csv
with open('etudiants.csv', 'r', encoding='utf-8') as fichier:
lecteur = csv.DictReader(fichier)
donnees = list(lecteur)
for i, ligne in enumerate(donnees):
if i < 3:
print(f"Nom: {ligne['nom']}, Âge: {ligne['âge']}, Note: {ligne['note']}, Ville: {ligne['ville']}")
else:
break
Objectif pédagogique : Filtrer et rechercher des données selon des critères spécifiques.
Énoncé :
À partir du même fichier CSV :
1. Trouvez tous les étudiants ayant une note supérieure à 15.
Rappel : Les données CSV sont lues comme des chaînes, pensez à la conversion.
2. Comptez le nombre d'étudiants par ville.
Procédure : Utilisez un dictionnaire pour compter les occurrences.
etudiants_excellents = []
for etudiant in donnees:
if float(etudiant['note']) > 15:
etudiants_excellents.append(etudiant)
print(f"Nombre d'étudiants avec note > 15 : {len(etudiants_excellents)}")
compteur_villes = {}
for etudiant in donnees:
ville = etudiant['ville']
compteur_villes[ville] = compteur_villes.get(ville, 0) + 1
for ville, count in compteur_villes.items():
print(f"{ville}: {count} étudiant(s)")
Objectif pédagogique : Maîtriser le tri des données CSV selon différents critères.
Énoncé :
1. Triez les étudiants par note décroissante.
2. Triez les étudiants par ordre alphabétique des noms.
3. Affichez les 5 meilleurs étudiants (note la plus élevée).
sorted()
avec le paramètre key
pour spécifier le critère de tri.
etudiants_par_note = sorted(donnees, key=lambda x: float(x['note']), reverse=True)
for etudiant in etudiants_par_note:
print(f"{etudiant['nom']}: {etudiant['note']}")
etudiants_alpha = sorted(donnees, key=lambda x: x['nom'])
for etudiant in etudiants_alpha:
print(f"{etudiant['nom']}")
top_5 = etudiants_par_note[:5]
print("Top 5 des meilleurs étudiants :")
for i, etudiant in enumerate(top_5, 1):
print(f"{i}. {etudiant['nom']}: {etudiant['note']}")
Objectif pédagogique : Effectuer des tris complexes avec plusieurs critères de priorité.
Énoncé :
1. Triez les étudiants par ville (ordre alphabétique), puis par note décroissante au sein de chaque ville.
2. Créez une fonction qui permet de trier selon n'importe quelle combinaison de critères.
3. Testez votre fonction en triant par âge croissant, puis par nom alphabétique.
key
pour définir plusieurs critères de tri.
etudiants_ville_note = sorted(donnees,
key=lambda x: (x['ville'], -float(x['note'])))
for etudiant in etudiants_ville_note:
print(f"{etudiant['ville']} - {etudiant['nom']}: {etudiant['note']}")
def trier_donnees(donnees, criteres):
"""
criteres: liste de tuples (champ, reverse)
exemple: [('ville', False), ('note', True)]
"""
def cle_tri(item):
result = []
for champ, reverse in criteres:
valeur = item[champ]
if champ in ['note', 'âge']:
valeur = float(valeur)
if reverse:
valeur = -valeur if isinstance(valeur, (int, float)) else valeur
result.append(valeur)
return tuple(result)
return sorted(donnees, key=cle_tri)
criteres = [('âge', False), ('nom', False)]
result = trier_donnees(donnees, criteres)
for etudiant in result:
print(f"{etudiant['âge']} ans - {etudiant['nom']}")
Objectif pédagogique : Utiliser pandas pour des manipulations avancées de données CSV.
Énoncé :
Utilisez la bibliothèque pandas pour :
1. Lire le fichier CSV et calculer la moyenne des notes par ville.
2. Filtrer les étudiants âgés de 18 à 25 ans avec une note > 12.
3. Créer un tableau croisé dynamique montrant la répartition âge/ville.
groupby()
pour les regroupementsquery()
pour les filtres complexespivot_table()
pour les tableaux croisés
import pandas as pd
df = pd.read_csv('etudiants.csv')
moyenne_par_ville = df.groupby('ville')['note'].mean()
print("Moyenne des notes par ville :")
print(moyenne_par_ville)
etudiants_filtres = df.query('18 <= âge <= 25 and note > 12')
print(f"Nombre d'étudiants correspondants : {len(etudiants_filtres)}")
print(etudiants_filtres[['nom', 'âge', 'note', 'ville']])
tableau_croise = pd.pivot_table(df,
values='nom',
index='âge',
columns='ville',
aggfunc='count',
fill_value=0)
print("Répartition âge/ville :")
print(tableau_croise)
Objectif pédagogique : Maîtriser l'importation CSV avec le module csv et comprendre les structures de données.
Énoncé :
Vous disposez d'un fichier produits.csv
avec les colonnes : nom, prix, categorie, stock
1. Implémentez deux fonctions : une avec csv.reader()
(liste de listes) et une avec csv.DictReader()
.
Conseil : Comparez les deux approches et leurs avantages respectifs.
2. Affichez la structure obtenue et testez l'accès aux données.
Astuce : Montrez comment accéder au prix du premier produit dans chaque structure.
import csv
# Méthode 1 : csv.reader() - Liste de listes
def lire_csv_listes(nom_fichier):
with open(nom_fichier, 'r', newline='', encoding='utf-8') as fichier:
lecteur = csv.reader(fichier)
entetes = next(lecteur)
donnees = []
for ligne in lecteur:
donnees.append(ligne)
return entetes, donnees
# Méthode 2 : csv.DictReader() - Liste de dictionnaires
def lire_csv_dict(nom_fichier):
with open(nom_fichier, 'r', newline='', encoding='utf-8') as fichier:
lecteur = csv.DictReader(fichier)
return list(lecteur)
# Test méthode 1
entetes, produits_listes = lire_csv_listes('produits.csv')
print("Structure liste:", entetes)
print("Premier produit:", produits_listes[0])
print("Prix du premier:", produits_listes[0][1]) # Index 1 pour prix
# Test méthode 2
produits_dict = lire_csv_dict('produits.csv')
print("Premier produit dict:", produits_dict[0])
print("Prix du premier:", produits_dict[0]['prix']) # Accès par nom
Avantage dictionnaires : Code plus lisible et moins d'erreurs d'index
Objectif pédagogique : Développer des fonctions d'analyse et de statistiques sur les données.
Énoncé :
À partir du fichier produits :
1. Créez une fonction calculer_statistiques(produits, colonne)
qui retourne moyenne, min, max et étendue.
Rappel : Attention à la conversion des types pour les calculs numériques.
2. Implémentez grouper_par_categorie(produits)
qui retourne un dictionnaire avec les produits regroupés par catégorie.
Procédure : Parcourir les produits et les classer dans des listes selon leur catégorie.
def calculer_statistiques(produits, colonne):
"""Calcule les statistiques d'une colonne numérique"""
valeurs = []
for produit in produits:
if colonne in ['prix', 'stock']:
valeurs.append(float(produit[colonne]))
if not valeurs:
return None
return {
'moyenne': sum(valeurs) / len(valeurs),
'min': min(valeurs),
'max': max(valeurs),
'etendue': max(valeurs) - min(valeurs),
'nombre': len(valeurs)
}
# Utilisation
stats_prix = calculer_statistiques(produits, 'prix')
print(f"Prix moyen: {stats_prix['moyenne']:.2f}€")
def grouper_par_categorie(produits):
"""Regroupe les produits par catégorie"""
groupes = {}
for produit in produits:
categorie = produit['categorie']
if categorie not in groupes:
groupes[categorie] = []
groupes[categorie].append(produit)
return groupes
# Test
groupes = grouper_par_categorie(produits)
for cat, liste_produits in groupes.items():
print(f"{cat}: {len(liste_produits)} produit(s)")
Objectif pédagogique : Implémenter un système de tri flexible avec plusieurs critères et ordres personnalisés.
Énoncé :
1. Créez une fonction trier_produits(produits, critere, decroissant=False)
qui gère tous les types de colonnes.
2. Implémentez tri_multi_criteres(produits, criteres)
où critères est une liste de tuples (nom_colonne, decroissant).
3. Testez en triant par catégorie (croissant) puis prix (décroissant).
def trier_produits(produits, critere, decroissant=False):
"""Tri intelligent selon le type de colonne"""
def cle_tri(produit):
valeur = produit[critere]
# Conversion automatique pour colonnes numériques
if critere in ['prix', 'stock']:
return float(valeur)
return valeur.lower() # Tri insensible à la casse pour texte
return sorted(produits, key=cle_tri, reverse=decroissant)
# Test
produits_par_prix = trier_produits(produits, 'prix', decroissant=True)
def tri_multi_criteres(produits, criteres):
"""
criteres: liste de tuples (nom_colonne, decroissant)
Exemple: [('categorie', False), ('prix', True)]
"""
def cle_tri(produit):
cle = []
for nom_colonne, decroissant in criteres:
valeur = produit[nom_colonne]
# Conversion selon le type
if nom_colonne in ['prix', 'stock']:
valeur = float(valeur)
if decroissant:
valeur = -valeur # Négation pour ordre décroissant
else:
valeur = valeur.lower()
# Pour texte décroissant, on inverse avec un artifice
cle.append(valeur)
return tuple(cle)
return sorted(produits, key=cle_tri)
# Test
criteres = [('categorie', False), ('prix', True)]
produits_tries = tri_multi_criteres(produits, criteres)
for p in produits_tries[:5]:
print(f"{p['categorie']} - {p['nom']}: {p['prix']}€")
def tri_multi_criteres_ameliore(produits, criteres):
# Tri en plusieurs passes pour gérer texte décroissant
result = produits.copy()
# Tri dans l'ordre inverse des critères
for nom_colonne, decroissant in reversed(criteres):
if nom_colonne in ['prix', 'stock']:
result = sorted(result,
key=lambda x: float(x[nom_colonne]),
reverse=decroissant)
else:
result = sorted(result,
key=lambda x: x[nom_colonne].lower(),
reverse=decroissant)
return result
Objectif pédagogique : Créer une classe complète pour la gestion de données CSV avec toutes les fonctionnalités.
Énoncé :
Créez une classe GestionCSV
avec les méthodes suivantes :
1. __init__(fichier)
: Charge les données
2. filtrer(critere, valeur)
: Filtre selon un critère
3. rechercher_avancee(**kwargs)
: Recherche avec plusieurs critères
4. exporter_filtre(donnees, nom_fichier)
: Sauvegarde un sous-ensemble
import csv
class GestionCSV:
def __init__(self, fichier):
"""Initialise avec le chargement des données"""
self.fichier = fichier
self.donnees = self.charger_donnees()
self.colonnes_numeriques = ['prix', 'stock'] # Configurable
def charger_donnees(self):
"""Charge les données du fichier CSV"""
with open(self.fichier, 'r', newline='', encoding='utf-8') as f:
return list(csv.DictReader(f))
def filtrer(self, critere, valeur):
"""Filtre selon un critère exact"""
return [item for item in self.donnees if item[critere] == str(valeur)]
def rechercher_avancee(self, **kwargs):
"""Recherche avec critères multiples et opérateurs"""
resultats = self.donnees.copy()
for cle, valeur in kwargs.items():
if cle.endswith('_min'):
# Critère minimum (ex: prix_min)
colonne = cle[:-4]
if colonne in self.colonnes_numeriques:
resultats = [r for r in resultats
if float(r[colonne]) >= float(valeur)]
elif cle.endswith('_max'):
# Critère maximum (ex: prix_max)
colonne = cle[:-4]
if colonne in self.colonnes_numeriques:
resultats = [r for r in resultats
if float(r[colonne]) <= float(valeur)]
elif cle.endswith('_contient'):
# Recherche textuelle (ex: nom_contient)
colonne = cle[:-9]
resultats = [r for r in resultats
if str(valeur).lower() in r[colonne].lower()]
else:
# Critère exact
resultats = [r for r in resultats if r[cle] == str(valeur)]
return resultats
def exporter_filtre(self, donnees, nom_fichier):
"""Exporte un sous-ensemble des données"""
if not donnees:
print("Aucune donnée à exporter")
return
with open(nom_fichier, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=donnees[0].keys())
writer.writeheader()
writer.writerows(donnees)
print(f"Exporté {len(donnees)} lignes vers {nom_fichier}")
def statistiques_globales(self):
"""Retourne des statistiques générales"""
stats = {}
for col in self.colonnes_numeriques:
valeurs = [float(item[col]) for item in self.donnees]
stats[col] = {
'moyenne': sum(valeurs) / len(valeurs),
'min': min(valeurs),
'max': max(valeurs)
}
return stats
# Initialisation
gestion = GestionCSV('produits.csv')
# Recherches avancées
chers = gestion.rechercher_avancee(prix_min=50, categorie="Electronique")
recherche = gestion.rechercher_avancee(nom_contient="phone", prix_max=800)
# Export des résultats
gestion.exporter_filtre(chers, 'produits_chers_electronique.csv')
# Statistiques
stats = gestion.statistiques_globales()
print(f"Prix moyen: {stats['prix']['moyenne']:.2f}€")
Objectif pédagogique : Développer un système d'analyse comparative entre plusieurs fichiers CSV et génération de rapports.
Énoncé :
Vous avez deux fichiers : produits_2023.csv
et produits_2024.csv
1. Créez une fonction qui compare les prix entre les deux années et identifie les évolutions.
2. Générez un rapport textuel avec les produits ajoutés, supprimés et modifiés.
3. Calculez les statistiques d'évolution par catégorie (hausse/baisse moyenne des prix).
def comparer_annees(fichier_ancien, fichier_nouveau):
"""Compare deux fichiers CSV de produits"""
import csv
# Chargement des données
def charger_dict_produits(fichier):
with open(fichier, 'r', newline='', encoding='utf-8') as f:
lecteur = csv.DictReader(f)
return {row['nom']: row for row in lecteur}
produits_2023 = charger_dict_produits(fichier_ancien)
produits_2024 = charger_dict_produits(fichier_nouveau)
# Analyse des changements
rapport = {
'ajoutes': [],
'supprimes': [],
'modifies': [],
'inchanges': []
}
# Produits de 2024
for nom, produit_2024 in produits_2024.items():
if nom not in produits_2023:
rapport['ajoutes'].append(produit_2024)
else:
produit_2023 = produits_2023[nom]
if produit_2023['prix'] != produit_2024['prix']:
rapport['modifies'].append({
'nom': nom,
'ancien_prix': float(produit_2023['prix']),
'nouveau_prix': float(produit_2024['prix']),
'evolution': float(produit_2024['prix']) - float(produit_2023['prix']),
'categorie': produit_2024['categorie']
})
else:
rapport['inchanges'].append(produit_2024)
# Produits supprimés (présents en 2023 mais pas en 2024)
for nom, produit in produits_2023.items():
if nom not in produits_2024:
rapport['supprimes'].append(produit)
return rapport
def generer_rapport_textuel(rapport, nom_fichier_rapport):
"""Génère un rapport textuel détaillé"""
with open(nom_fichier_rapport, 'w', encoding='utf-8') as f:
f.write("RAPPORT D'ÉVOLUTION DES PRODUITS 2023-2024\n")
f.write("=" * 50 + "\n\n")
# Statistiques générales
f.write(f"📊 STATISTIQUES GÉNÉRALES\n")
f.write(f"Produits ajoutés: {len(rapport['ajoutes'])}\n")
f.write(f"Produits supprimés: {len(rapport['supprimes'])}\n")
f.write(f"Produits modifiés: {len(rapport['modifies'])}\n")
f.write(f"Produits inchangés: {len(rapport['inchanges'])}\n\n")
# Détail des modifications
if rapport['modifies']:
f.write("💰 ÉVOLUTIONS DE PRIX\n")
f.write("-" * 30 + "\n")
for modif in rapport['modifies']:
evolution = modif['evolution']
signe = "📈" if evolution > 0 else "📉"
f.write(f"{signe} {modif['nom']}: ")
f.write(f"{modif['ancien_prix']:.2f}€ → {modif['nouveau_prix']:.2f}€ ")
f.write(f"({evolution:+.2f}€)\n")
# Nouveaux produits
if rapport['ajoutes']:
f.write(f"\n✅ NOUVEAUX PRODUITS ({len(rapport['ajoutes'])})\n")
f.write("-" * 30 + "\n")
for produit in rapport['ajoutes']:
f.write(f"• {produit['nom']} - {produit['prix']}€ ")
f.write(f"({produit['categorie']})\n")
# Produits supprimés
if rapport['supprimes']:
f.write(f"\n❌ PRODUITS SUPPRIMÉS ({len(rapport['supprimes'])})\n")
f.write("-" * 30 + "\n")
for produit in rapport['supprimes']:
f.write(f"• {produit['nom']} - {produit['prix']}€\n")
print(f"Rapport généré: {nom_fichier_rapport}")
def analyser_evolution_categories(rapport):
"""Analyse les évolutions de prix par catégorie"""
stats_categories = {}
for modif in rapport['modifies']:
cat = modif['categorie']
if cat not in stats_categories:
stats_categories[cat] = {
'evolutions': [],
'hausse_count': 0,
'baisse_count': 0
}
evolution = modif['evolution']
stats_categories[cat]['evolutions'].append(evolution)
if evolution > 0:
stats_categories[cat]['hausse_count'] += 1
else:
stats_categories[cat]['baisse_count'] += 1
# Calcul des moyennes
for cat, data in stats_categories.items():
evolutions = data['evolutions']
data['evolution_moyenne'] = sum(evolutions) / len(evolutions)
data['total_modifies'] = len(evolutions)
return stats_categories
# Utilisation complète
rapport = comparer_annees('produits_2023.csv', 'produits_2024.csv')
generer_rapport_textuel(rapport, 'rapport_evolution.txt')
stats_cat = analyser_evolution_categories(rapport)
print("Évolution par catégorie:")
for cat, stats in stats_cat.items():
print(f"{cat}: {stats['evolution_moyenne']:+.2f}€ en moyenne")
Objectif pédagogique : Manipuler des données RH avec calculs de salaires et gestion des départements.
Contexte :
Vous travaillez pour une entreprise et devez analyser le fichier employes.csv
contenant : nom, prenom, departement, salaire_base, heures_sup, taux_horaire
Énoncé :
1. Créez une fonction calculer_salaire_total(employes)
qui ajoute une clé 'salaire_total' à chaque dictionnaire d'employé.
Formule : salaire_total = salaire_base + (heures_sup × taux_horaire)
2. Implémentez top_employes_par_departement(employes, n=3)
qui retourne les n meilleurs salaires par département.
Conseil : Utilisez les listes de dictionnaires pour conserver toutes les informations.
import csv
def charger_employes(fichier):
"""Charge les employés depuis le CSV"""
with open(fichier, 'r', newline='', encoding='utf-8') as f:
return list(csv.DictReader(f))
def calculer_salaire_total(employes):
"""Ajoute le salaire total à chaque employé"""
for employe in employes:
salaire_base = float(employe['salaire_base'])
heures_sup = float(employe['heures_sup'])
taux_horaire = float(employe['taux_horaire'])
# Ajout de la nouvelle clé au dictionnaire
employe['salaire_total'] = salaire_base + (heures_sup * taux_horaire)
return employes
# Test
employes = charger_employes('employes.csv')
employes = calculer_salaire_total(employes)
print(f"Premier employé: {employes[0]['prenom']} {employes[0]['nom']}")
print(f"Salaire total: {employes[0]['salaire_total']:.2f}€")
def top_employes_par_departement(employes, n=3):
"""Retourne les n meilleurs salaires par département"""
# Groupement par département
departements = {}
for employe in employes:
dept = employe['departement']
if dept not in departements:
departements[dept] = []
departements[dept].append(employe)
# Tri et sélection des top n pour chaque département
top_par_dept = {}
for dept, liste_employes in departements.items():
# Tri par salaire total décroissant
employes_tries = sorted(liste_employes,
key=lambda x: x['salaire_total'],
reverse=True)
top_par_dept[dept] = employes_tries[:n]
return top_par_dept
# Utilisation
top_employes = top_employes_par_departement(employes, 3)
for dept, top_liste in top_employes.items():
print(f"\nTop 3 - {dept}:")
for i, emp in enumerate(top_liste, 1):
print(f" {i}. {emp['prenom']} {emp['nom']}: {emp['salaire_total']:.2f}€")
Objectif pédagogique : Analyser des données de ventes avec agrégations complexes et calculs de performances.
Contexte :
Une chaîne de magasins vous fournit ventes.csv
avec : magasin, region, vendeur, date, produit, quantite, prix_unitaire
Énoncé :
1. Créez enrichir_ventes(ventes)
qui ajoute les clés 'chiffre_affaires' et 'trimestre' à chaque vente.
Astuce : chiffre_affaires = quantite × prix_unitaire, trimestre basé sur le mois
2. Implémentez performance_vendeurs(ventes)
qui retourne pour chaque vendeur : total_ca, nb_ventes, ca_moyen, meilleur_mois.
Défi : Exploitez les dictionnaires pour stocker plusieurs métriques par vendeur.
from datetime import datetime
def enrichir_ventes(ventes):
"""Enrichit chaque vente avec CA et trimestre"""
for vente in ventes:
# Calcul du chiffre d'affaires
quantite = float(vente['quantite'])
prix_unitaire = float(vente['prix_unitaire'])
vente['chiffre_affaires'] = quantite * prix_unitaire
# Calcul du trimestre depuis la date
date_vente = datetime.strptime(vente['date'], '%Y-%m-%d')
mois = date_vente.month
if mois <= 3:
vente['trimestre'] = 'Q1'
elif mois <= 6:
vente['trimestre'] = 'Q2'
elif mois <= 9:
vente['trimestre'] = 'Q3'
else:
vente['trimestre'] = 'Q4'
return ventes
# Test d'enrichissement
ventes = charger_ventes('ventes.csv')
ventes_enrichies = enrichir_ventes(ventes)
print(f"Première vente enrichie:")
print(f"CA: {ventes_enrichies[0]['chiffre_affaires']:.2f}€")
print(f"Trimestre: {ventes_enrichies[0]['trimestre']}")
def performance_vendeurs(ventes):
"""Analyse la performance de chaque vendeur"""
performances = {}
for vente in ventes:
vendeur = vente['vendeur']
ca = vente['chiffre_affaires']
date_vente = datetime.strptime(vente['date'], '%Y-%m-%d')
mois = date_vente.strftime('%Y-%m')
# Initialisation du vendeur s'il n'existe pas
if vendeur not in performances:
performances[vendeur] = {
'total_ca': 0,
'nb_ventes': 0,
'ventes_par_mois': {},
'region': vente['region'] # Info supplémentaire
}
# Mise à jour des métriques
perf = performances[vendeur]
perf['total_ca'] += ca
perf['nb_ventes'] += 1
# Suivi par mois
if mois not in perf['ventes_par_mois']:
perf['ventes_par_mois'][mois] = 0
perf['ventes_par_mois'][mois] += ca
# Calculs finaux pour chaque vendeur
for vendeur, perf in performances.items():
perf['ca_moyen'] = perf['total_ca'] / perf['nb_ventes']
# Meilleur mois
meilleur_mois = max(perf['ventes_par_mois'].items(),
key=lambda x: x[1])
perf['meilleur_mois'] = meilleur_mois[0]
perf['ca_meilleur_mois'] = meilleur_mois[1]
return performances
# Utilisation et affichage
perfs = performance_vendeurs(ventes_enrichies)
for vendeur, stats in perfs.items():
print(f"\n🏆 {vendeur} ({stats['region']}):")
print(f" CA Total: {stats['total_ca']:,.2f}€")
print(f" Nb ventes: {stats['nb_ventes']}")
print(f" CA moyen: {stats['ca_moyen']:.2f}€")
print(f" Meilleur mois: {stats['meilleur_mois']} ({stats['ca_meilleur_mois']:,.2f}€)")
Objectif pédagogique : Construire un système de recommandation basé sur les ratings utilisateurs avec analyse de similarité.
Contexte :
Une plateforme de streaming vous fournit ratings.csv
avec : user_id, film_titre, genre, note, date_visionnage, duree_minutes
Énoncé :
1. Créez profil_utilisateur(ratings, user_id)
qui retourne le profil complet d'un utilisateur avec ses préférences de genre.
Inclure : genres favoris, note moyenne, films notés, temps total de visionnage
2. Implémentez recommander_films(ratings, user_id, nb_recommandations=5)
qui suggère des films basés sur les utilisateurs similaires.
Méthode : Trouver les utilisateurs avec des goûts similaires et recommander leurs films bien notés.
def profil_utilisateur(ratings, user_id):
"""Génère le profil complet d'un utilisateur"""
ratings_user = [r for r in ratings if r['user_id'] == user_id]
if not ratings_user:
return None
# Calculs de base
notes = [float(r['note']) for r in ratings_user]
durees = [int(r['duree_minutes']) for r in ratings_user]
# Analyse des genres
compteur_genres = {}
notes_par_genre = {}
for rating in ratings_user:
genre = rating['genre']
note = float(rating['note'])
# Comptage des genres
compteur_genres[genre] = compteur_genres.get(genre, 0) + 1
# Notes par genre
if genre not in notes_par_genre:
notes_par_genre[genre] = []
notes_par_genre[genre].append(note)
# Genres favoris (par fréquence et note moyenne)
genres_avec_stats = []
for genre, count in compteur_genres.items():
note_moy_genre = sum(notes_par_genre[genre]) / len(notes_par_genre[genre])
genres_avec_stats.append({
'genre': genre,
'count': count,
'note_moyenne': note_moy_genre,
'score_preference': count * note_moy_genre # Score combiné
})
# Tri par score de préférence
genres_favoris = sorted(genres_avec_stats,
key=lambda x: x['score_preference'],
reverse=True)
return {
'user_id': user_id,
'nb_films_notes': len(ratings_user),
'note_moyenne': sum(notes) / len(notes),
'temps_total_minutes': sum(durees),
'temps_total_heures': sum(durees) / 60,
'genres_favoris': genres_favoris[:3], # Top 3
'meilleur_film': max(ratings_user, key=lambda x: float(x['note'])),
'dernier_visionnage': max(ratings_user, key=lambda x: x['date_visionnage'])
}
def calculer_similarite_utilisateurs(profil1, profil2):
"""Calcule la similarité entre deux profils utilisateur"""
if not profil1 or not profil2:
return 0
# Similarité basée sur les notes moyennes
diff_notes = abs(profil1['note_moyenne'] - profil2['note_moyenne'])
sim_notes = max(0, 1 - diff_notes / 5) # Normalisation sur 5
# Similarité des genres favoris
genres1 = set(g['genre'] for g in profil1['genres_favoris'])
genres2 = set(g['genre'] for g in profil2['genres_favoris'])
if genres1 and genres2:
intersection = len(genres1.intersection(genres2))
union = len(genres1.union(genres2))
sim_genres = intersection / union if union > 0 else 0
else:
sim_genres = 0
# Score de similarité combiné
return (sim_notes * 0.4) + (sim_genres * 0.6)
def recommander_films(ratings, user_id, nb_recommandations=5):
"""Recommande des films basés sur des utilisateurs similaires"""
# Profil de l'utilisateur cible
profil_cible = profil_utilisateur(ratings, user_id)
if not profil_cible:
return []
# Films déjà vus par l'utilisateur
films_vus = set(r['film_titre'] for r in ratings if r['user_id'] == user_id)
# Calcul de similarité avec tous les autres utilisateurs
autres_users = list(set(r['user_id'] for r in ratings if r['user_id'] != user_id))
similarities = []
for other_user in autres_users:
profil_autre = profil_utilisateur(ratings, other_user)
if profil_autre:
sim_score = calculer_similarite_utilisateurs(profil_cible, profil_autre)
if sim_score > 0.3: # Seuil de similarité
similarities.append((other_user, sim_score))
# Tri par similarité décroissante
similarities.sort(key=lambda x: x[1], reverse=True)
users_similaires = similarities[:10] # Top 10 utilisateurs similaires
# Collecte des recommandations
recommandations = {}
for similar_user, sim_score in users_similaires:
user_ratings = [r for r in ratings if r['user_id'] == similar_user]
for rating in user_ratings:
film = rating['film_titre']
note = float(rating['note'])
# Seulement les films bien notés (>= 4) et non vus
if note >= 4 and film not in films_vus:
if film not in recommandations:
recommandations[film] = {
'score_total': 0,
'nb_recommandeurs': 0,
'genre': rating['genre'],
'duree_minutes': rating['duree_minutes']
}
# Score pondéré par la similarité
recommandations[film]['score_total'] += note * sim_score
recommandations[film]['nb_recommandeurs'] += 1
# Calcul du score final et tri
films_recommandes = []
for film, data in recommandations.items():
if data['nb_recommandeurs'] >= 2: # Au moins 2 recommandeurs
score_final = data['score_total'] / data['nb_recommandeurs']
films_recommandes.append({
'film': film,
'score': score_final,
'genre': data['genre'],
'duree_minutes': data['duree_minutes'],
'nb_recommandeurs': data['nb_recommandeurs']
})
# Tri par score et retour des top recommandations
films_recommandes.sort(key=lambda x: x['score'], reverse=True)
return films_recommandes[:nb_recommandations]
# Utilisation complète
profil = profil_utilisateur(ratings, 'user_123')
print(f"Profil de {profil['user_id']}:")
print(f"Films notés: {profil['nb_films_notes']}")
print(f"Note moyenne: {profil['note_moyenne']:.2f}")
print(f"Genres favoris: {[g['genre'] for g in profil['genres_favoris']]}")
recommandations = recommander_films(ratings, 'user_123', 5)
print(f"\n🎬 Recommandations pour user_123:")
for i, rec in enumerate(recommandations, 1):
print(f"{i}. {rec['film']} ({rec['genre']}) - Score: {rec['score']:.2f}")
Objectif pédagogique : Analyser des données financières complexes avec calculs de rendements et gestion de risque.
Contexte :
Une société de gestion vous confie l'analyse de transactions.csv
contenant : client_id, date, action_type, symbole, quantite, prix, frais
(action_type: 'BUY' ou 'SELL')
Énoncé :
1. Créez calculer_portefeuille_actuel(transactions)
qui retourne pour chaque client son portefeuille actuel (positions et valeurs).
Logique : BUY ajoute des actions, SELL les retire
2. Implémentez analyser_performance_client(transactions, client_id, prix_actuels)
qui calcule les plus/moins-values réalisées et latentes.
Challenge : Gérer les achats/ventes multiples avec méthode FIFO (First In, First Out)
from datetime import datetime
from collections import defaultdict
import pandas as pd
def calculer_portefeuille_actuel(transactions):
"""Calcule le portefeuille actuel de chaque client"""
portefeuilles = defaultdict(lambda: defaultdict(lambda: {'quantite': 0, 'historique': []}))
# Tri chronologique des transactions
transactions_triees = sorted(transactions,
key=lambda x: datetime.strptime(x['date'], '%Y-%m-%d'))
for transaction in transactions_triees:
client = transaction['client_id']
symbole = transaction['symbole']
quantite = int(transaction['quantite'])
prix = float(transaction['prix'])
frais = float(transaction['frais'])
action = transaction['action_type']
position = portefeuilles[client][symbole]
if action == 'BUY':
# Achat : augmente la position
position['quantite'] += quantite
position['historique'].append({
'type': 'BUY',
'quantite': quantite,
'prix': prix,
'frais': frais,
'date': transaction['date']
})
elif action == 'SELL':
# Vente : diminue la position
position['quantite'] -= quantite
position['historique'].append({
'type': 'SELL',
'quantite': quantite,
'prix': prix,
'frais': frais,
'date': transaction['date']
})
# Nettoyage : suppression des positions nulles
portefeuilles_nettoyes = {}
for client, positions in portefeuilles.items():
portefeuilles_nettoyes[client] = {
symbole: data for symbole, data in positions.items()
if data['quantite'] > 0
}
return portefeuilles_nettoyes
def analyser_performance_client(transactions, client_id, prix_actuels):
"""Analyse complète de performance d'un client avec méthode FIFO"""
# Filtrage des transactions du client
trans_client = [t for t in transactions if t['client_id'] == client_id]
trans_client = sorted(trans_client,
key=lambda x: datetime.strptime(x['date'], '%Y-%m-%d'))
# Structure pour gérer les positions FIFO
positions = defaultdict(list) # Liste des achats par symbole
plus_values_realisees = []
frais_totaux = 0
for transaction in trans_client:
symbole = transaction['symbole']
quantite = int(transaction['quantite'])
prix = float(transaction['prix'])
frais = float(transaction['frais'])
action = transaction['action_type']
date = transaction['date']
frais_totaux += frais
if action == 'BUY':
# Ajout à la pile FIFO
positions[symbole].append({
'quantite': quantite,
'prix': prix,
'date': date
})
elif action == 'SELL':
# Vente FIFO : on vend les plus anciens achats en premier
quantite_a_vendre = quantite
while quantite_a_vendre > 0 and positions[symbole]:
achat = positions[symbole][0]
if achat['quantite'] <= quantite_a_vendre:
# Vente complète de cet achat
quantite_vendue = achat['quantite']
plus_value = (prix - achat['prix']) * quantite_vendue
plus_values_realisees.append({
'symbole': symbole,
'quantite': quantite_vendue,
'prix_achat': achat['prix'],
'prix_vente': prix,
'plus_value': plus_value,
'date_achat': achat['date'],
'date_vente': date
})
quantite_a_vendre -= quantite_vendue
positions[symbole].pop(0) # Retrait de la pile
else:
# Vente partielle
plus_value = (prix - achat['prix']) * quantite_a_vendre
plus_values_realisees.append({
'symbole': symbole,
'quantite': quantite_a_vendre,
'prix_achat': achat['prix'],
'prix_vente': prix,
'plus_value': plus_value,
'date_achat': achat['date'],
'date_vente': date
})
achat['quantite'] -= quantite_a_vendre
quantite_a_vendre = 0
# Calcul des plus-values latentes (positions actuelles)
plus_values_latentes = []
valeur_portefeuille = 0
cout_total_positions = 0
for symbole, achats in positions.items():
if symbole in prix_actuels:
prix_actuel = prix_actuels[symbole]
for achat in achats:
quantite = achat['quantite']
prix_achat = achat['prix']
valeur_actuelle = quantite * prix_actuel
cout_achat = quantite * prix_achat
plus_value_latente = valeur_actuelle - cout_achat
plus_values_latentes.append({
'symbole': symbole,
'quantite': quantite,
'prix_achat': prix_achat,
'prix_actuel': prix_actuel,
'plus_value_latente': plus_value_latente,
'valeur_actuelle': valeur_actuelle,
'date_achat': achat['date']
})
valeur_portefeuille += valeur_actuelle
cout_total_positions += cout_achat
# Calculs de synthèse
total_plus_values_realisees = sum(pv['plus_value'] for pv in plus_values_realisees)
total_plus_values_latentes = sum(pv['plus_value_latente'] for pv in plus_values_latentes)
return {
'client_id': client_id,
'plus_values_realisees': plus_values_realisees,
'plus_values_latentes': plus_values_latentes,
'resume': {
'total_pv_realisees': total_plus_values_realisees,
'total_pv_latentes': total_plus_values_latentes,
'total_pv_globales': total_plus_values_realisees + total_plus_values_latentes,
'valeur_portefeuille': valeur_portefeuille,
'cout_total_positions': cout_total_positions,
'frais_totaux': frais_totaux,
'rendement_net': ((total_plus_values_realisees + total_plus_values_latentes - frais_totaux) / cout_total_positions * 100) if cout_total_positions > 0 else 0
}
}
def analyser_risque_portefeuille(transactions, prix_actuels, volatilites):
"""Analyse de risque avancée pour tous les portefeuilles"""
portefeuilles = calculer_portefeuille_actuel(transactions)
analyses_risque = {}
for client_id in portefeuilles.keys():
performance = analyser_performance_client(transactions, client_id, prix_actuels)
# Calcul de la répartition du portefeuille
positions_actuelles = {}
valeur_totale = performance['resume']['valeur_portefeuille']
for pv_latente in performance['plus_values_latentes']:
symbole = pv_latente['symbole']
valeur = pv_latente['valeur_actuelle']
if symbole in positions_actuelles:
positions_actuelles[symbole] += valeur
else:
positions_actuelles[symbole] = valeur
# Calcul du risque (écart-type pondéré)
risque_portefeuille = 0
if valeur_totale > 0:
for symbole, valeur in positions_actuelles.items():
poids = valeur / valeur_totale
volatilite = volatilites.get(symbole, 0.2) # 20% par défaut
risque_portefeuille += (poids * volatilite) ** 2
risque_portefeuille = (risque_portefeuille ** 0.5) * 100
# Ratio de Sharpe simplifié (rendement / risque)
rendement = performance['resume']['rendement_net']
ratio_sharpe = rendement / risque_portefeuille if risque_portefeuille > 0 else 0
analyses_risque[client_id] = {
'risque_portefeuille': risque_portefeuille,
'rendement_net': rendement,
'ratio_sharpe': ratio_sharpe,
'diversification': len(positions_actuelles),
'concentration_max': (max(positions_actuelles.values()) / valeur_totale * 100) if valeur_totale > 0 else 0
}
return analyses_risque
def generer_rapport_complet(transactions, prix_actuels, volatilites=None):
"""Génère un rapport complet d'analyse de portefeuille"""
if volatilites is None:
# Volatilités par défaut pour l'exemple
volatilites = {
'AAPL': 0.25, 'GOOGL': 0.30, 'MSFT': 0.22, 'TSLA': 0.45,
'AMZN': 0.28, 'META': 0.35, 'NVDA': 0.40
}
print("="*80)
print("📊 RAPPORT D'ANALYSE DE PORTEFEUILLE - SOCIÉTÉ DE GESTION")
print("="*80)
# Analyse globale
portefeuilles = calculer_portefeuille_actuel(transactions)
analyses_risque = analyser_risque_portefeuille(transactions, prix_actuels, volatilites)
print(f"\n📈 RÉSUMÉ EXÉCUTIF")
print(f"Nombre de clients analysés: {len(portefeuilles)}")
# Analyse par client
for client_id in portefeuilles.keys():
print(f"\n" + "="*60)
print(f"💼 CLIENT: {client_id}")
print("="*60)
# Performance détaillée
performance = analyser_performance_client(transactions, client_id, prix_actuels)
resume = performance['resume']
print(f"💰 PERFORMANCE FINANCIÈRE:")
print(f" • Valeur du portefeuille: {resume['valeur_portefeuille']:,.2f} €")
print(f" • Plus-values réalisées: {resume['total_pv_realisees']:,.2f} €")
print(f" • Plus-values latentes: {resume['total_pv_latentes']:,.2f} €")
print(f" • Frais totaux: {resume['frais_totaux']:,.2f} €")
print(f" • Rendement net: {resume['rendement_net']:.2f}%")
# Analyse de risque
if client_id in analyses_risque:
risque = analyses_risque[client_id]
print(f"\n⚠️ ANALYSE DE RISQUE:")
print(f" • Risque du portefeuille: {risque['risque_portefeuille']:.2f}%")
print(f" • Ratio de Sharpe: {risque['ratio_sharpe']:.2f}")
print(f" • Diversification: {risque['diversification']} titres")
print(f" • Concentration max: {risque['concentration_max']:.1f}%")
# Détail des positions actuelles
print(f"\n📋 POSITIONS ACTUELLES:")
portefeuille_client = portefeuilles[client_id]
for symbole, data in portefeuille_client.items():
if symbole in prix_actuels:
valeur = data['quantite'] * prix_actuels[symbole]
print(f" • {symbole}: {data['quantite']} actions → {valeur:,.2f} €")
# Top 3 des meilleures plus-values réalisées
if performance['plus_values_realisees']:
print(f"\n🏆 TOP 3 MEILLEURES OPÉRATIONS:")
top_operations = sorted(performance['plus_values_realisees'],
key=lambda x: x['plus_value'], reverse=True)[:3]
for i, op in enumerate(top_operations, 1):
print(f" {i}. {op['symbole']}: +{op['plus_value']:,.2f} € "
f"({op['quantite']} actions à {op['prix_vente']:.2f} €)")
return {
'portefeuilles': portefeuilles,
'analyses_performance': {client_id: analyser_performance_client(transactions, client_id, prix_actuels)
for client_id in portefeuilles.keys()},
'analyses_risque': analyses_risque
}
# ========================================
# EXEMPLE D'UTILISATION ET TESTS
# ========================================
if __name__ == "__main__":
# Données de test
transactions_exemple = [
{'client_id': 'C001', 'date': '2023-01-15', 'action_type': 'BUY', 'symbole': 'AAPL', 'quantite': 100, 'prix': 150.0, 'frais': 10.0},
{'client_id': 'C001', 'date': '2023-02-01', 'action_type': 'BUY', 'symbole': 'GOOGL', 'quantite': 50, 'prix': 2800.0, 'frais': 15.0},
{'client_id': 'C001', 'date': '2023-03-15', 'action_type': 'SELL', 'symbole': 'AAPL', 'quantite': 30, 'prix': 165.0, 'frais': 8.0},
{'client_id': 'C001', 'date': '2023-04-01', 'action_type': 'BUY', 'symbole': 'MSFT', 'quantite': 75, 'prix': 280.0, 'frais': 12.0},
{'client_id': 'C002', 'date': '2023-01-20', 'action_type': 'BUY', 'symbole': 'TSLA', 'quantite': 80, 'prix': 200.0, 'frais': 20.0},
{'client_id': 'C002', 'date': '2023-02-15', 'action_type': 'BUY', 'symbole': 'NVDA', 'quantite': 40, 'prix': 450.0, 'frais': 18.0},
{'client_id': 'C002', 'date': '2023-03-01', 'action_type': 'SELL', 'symbole': 'TSLA', 'quantite': 20, 'prix': 250.0, 'frais': 10.0},
]
prix_actuels_exemple = {
'AAPL': 175.0,
'GOOGL': 2900.0,
'MSFT': 320.0,
'TSLA': 240.0,
'NVDA': 520.0
}
# Test des fonctions
print("🧪 TESTS DES FONCTIONS")
print("-" * 50)
# Test 1: Calcul des portefeuilles actuels
print("✅ Test 1: Portefeuilles actuels")
portefeuilles = calculer_portefeuille_actuel(transactions_exemple)
for client, positions in portefeuilles.items():
print(f" {client}: {len(positions)} positions")
# Test 2: Analyse de performance
print("\n✅ Test 2: Analyse de performance C001")
perf_c001 = analyser_performance_client(transactions_exemple, 'C001', prix_actuels_exemple)
print(f" Plus-values réalisées: {perf_c001['resume']['total_pv_realisees']:.2f} €")
print(f" Plus-values latentes: {perf_c001['resume']['total_pv_latentes']:.2f} €")
# Test 3: Rapport complet
print("\n" + "="*80)
print("📊 GÉNÉRATION DU RAPPORT COMPLET")
print("="*80)
rapport = generer_rapport_complet(transactions_exemple, prix_actuels_exemple)
Explorez comment l'art et la philosophie s'entrelacent pour questionner notre perception de la réalité et de l'esthétique.
Read more.Plongez dans les débats philosophiques sur la liberté, ses implications éthiques et les défis contemporains qui l'entourent.
Read more.Découvrez les différentes approches philosophiques de la vérité et comment elles influencent notre compréhension du monde.
Read more.Abonnez-vous maintenant et recevez notre newsletter hebdomadaire avec des matériaux éducatifs, de nouveaux cours, des articles intéressants, des livres populaires et bien plus encore !