Adloun

Python (école d'ingénieur) · Chapitre 7 · Exercice

Application complète : analyse de données météo

Fichiers, exceptions et modules

Énoncé

Créer une application modulaire et robuste qui :

  • Lit un fichier CSV de données météo (contenant les colonnes : date, tmin, tmax, precipitation).
  • Calcule des statistiques mensuelles (températures moyennes et extrêmes absolues, précipitations cumulées).
  • Génère un rapport texte.
  • Sauvegarde les résultats mensuels dans un nouveau fichier CSV.
  • Gère les erreurs de conversion et de lecture.

Corrigé

import csv
from datetime import datetime
from collections import defaultdict

class AnalyseMeteo:
    """Classe pour l'analyse de données météo."""
    
    def __init__(self, nom_fichier):
        self.nom_fichier = nom_fichier
        self.donnees = []
        self.statistiques = {}
        
    def charger_donnees(self):
        """Charge les données météo depuis un fichier CSV."""
        try:
            with open(self.nom_fichier, 'r', encoding='utf-8') as f:
                reader = csv.DictReader(f)
                for ligne in reader:
                    try:
                        date = datetime.strptime(ligne['date'], '%Y-%m-%d')
                        tmin = float(ligne['tmin'])
                        tmax = float(ligne['tmax'])
                        precip = float(ligne['precipitation'])
                        
                        self.donnees.append({
                            'date': date,
                            'tmin': tmin,
                            'tmax': tmax,
                            'tavg': (tmin + tmax) / 2,
                            'precip': precip
                        })
                    except (ValueError, KeyError) as e:
                        print(f"Ligne ignorée (erreur de conversion) : {ligne}")
                        continue
            print(f"Chargement terminé : {len(self.donnees)} enregistrements.")
            return True
        except FileNotFoundError:
            print(f"Erreur : Fichier {self.nom_fichier} introuvable.")
            return False
            
    def calculer_statistiques(self):
        """Calcule les statistiques mensuelles."""
        if not self.donnees:
            print("Aucune donnée à analyser.")
            return
            
        # Regroupement par mois
        mois_stats = defaultdict(lambda: {
            'tmin_sum': 0.0, 'tmax_sum': 0.0, 'tavg_sum': 0.0, 'precip_sum': 0.0,
            'count': 0, 'tmin_min': float('inf'), 'tmax_max': float('-inf')
        })
        
        for d in self.donnees:
            mois_cle = d['date'].strftime('%Y-%m')  # Format "2024-01"
            stats = mois_stats[mois_cle]
            
            stats['tmin_sum'] += d['tmin']
            stats['tmax_sum'] += d['tmax']
            stats['tavg_sum'] += d['tavg']
            stats['precip_sum'] += d['precip']
            stats['count'] += 1
            stats['tmin_min'] = min(stats['tmin_min'], d['tmin'])
            stats['tmax_max'] = max(stats['tmax_max'], d['tmax'])
            
        # Calcul des moyennes
        self.statistiques = {}
        for mois, stats in mois_stats.items():
            cnt = stats['count']
            self.statistiques[mois] = {
                'tmin_moy': stats['tmin_sum'] / cnt,
                'tmax_moy': stats['tmax_sum'] / cnt,
                'tavg_moy': stats['tavg_sum'] / cnt,
                'tmin_min': stats['tmin_min'],
                'tmax_max': stats['tmax_max'],
                'precip_tot': stats['precip_sum'],
                'nb_jours': cnt
            }
            
        # Identification des extrêmes absolus
        mois_tmin_min = min(self.statistiques.items(), key=lambda x: x[1]['tmin_min'])
        mois_tmax_max = max(self.statistiques.items(), key=lambda x: x[1]['tmax_max'])
        
        self.statistiques['_extrema'] = {
            'mois_plus_froid': mois_tmin_min[0],
            'temp_min_absolue': mois_tmin_min[1]['tmin_min'],
            'mois_plus_chaud': mois_tmax_max[0],
            'temp_max_absolue': mois_tmax_max[1]['tmax_max']
        }
        
    def generer_rapport(self, fichier_rapport="rapport_meteo.txt"):
        """Génère un rapport texte des statistiques."""
        if not self.statistiques:
            print("Calculez d'abord les statistiques.")
            return
            
        with open(fichier_rapport, 'w', encoding='utf-8') as f:
            f.write("=" * 60 + "\n")
            f.write("RAPPORT D'ANALYSE MÉTÉO\n")
            f.write("=" * 60 + "\n\n")
            
            ext = self.statistiques['_extrema']
            f.write("EXTREMES :\n")
            f.write(f"  Mois le plus froid : {ext['mois_plus_froid']}")
            f.write(f" (temp. min: {ext['temp_min_absolue']:.1f}°C)\n")
            f.write(f"  Mois le plus chaud : {ext['mois_plus_chaud']}")
            f.write(f" (temp. max: {ext['temp_max_absolue']:.1f}°C)\n\n")
            
            f.write("STATISTIQUES MENSUELLES :\n")
            f.write("-" * 60 + "\n")
            f.write(f"{'Mois':10} {'Tmin':8} {'Tmax':8} {'Tavg':8} {'Précip':10}\n")
            f.write("-" * 60 + "\n")
            
            for mois in sorted(self.statistiques.keys()):
                if mois == '_extrema':
                    continue
                s = self.statistiques[mois]
                f.write(f"{mois:10} {s['tmin_moy']:8.1f} {s['tmax_moy']:8.1f} ")
                f.write(f"{s['tavg_moy']:8.1f} {s['precip_tot']:10.1f}\n")
                
        print(f"Rapport généré : {fichier_rapport}")
        
    def exporter_csv(self, fichier_sortie="statistiques_mensuelles.csv"):
        """Exporte les statistiques mensuelles vers un fichier CSV."""
        if not self.statistiques:
            print("Calculez d'abord les statistiques.")
            return
            
        with open(fichier_sortie, 'w', newline='', encoding='utf-8') as f:
            writer = csv.writer(f)
            writer.writerow(['Mois', 'Tmin_moy', 'Tmax_moy', 'Tavg_moy',
                             'Tmin_min', 'Tmax_max', 'Precip_tot', 'Nb_jours'])
            
            for mois in sorted(self.statistiques.keys()):
                if mois == '_extrema':
                    continue
                s = self.statistiques[mois]
                writer.writerow([
                    mois, f"{s['tmin_moy']:.1f}", f"{s['tmax_moy']:.1f}",
                    f"{s['tavg_moy']:.1f}", f"{s['tmin_min']:.1f}",
                    f"{s['tmax_max']:.1f}", f"{s['precip_tot']:.1f}", s['nb_jours']
                ])
        print(f"Export CSV : {fichier_sortie}")

# Création d'un fichier CSV de test
def creer_fichier_test():
    with open("meteo_test.csv", "w", encoding="utf-8") as f:
        f.write("date,tmin,tmax,precipitation\n")
        f.write("2024-01-15,2.0,8.0,12.5\n")
        f.write("2024-01-20,1.5,7.5,8.0\n")
        f.write("2024-02-10,3.0,10.0,5.0\n")
        f.write("2024-02-15,4.0,12.0,0.0\n")

# Exemple d'utilisation
if __name__ == "__main__":
    creer_fichier_test()
    analyse = AnalyseMeteo("meteo_test.csv")
    if analyse.charger_donnees():
        analyse.calculer_statistiques()
        analyse.generer_rapport()
        analyse.exporter_csv()

100 % gratuit

La suite du chapitre est sur Adloun

Exercice suivant et tuteur

Sans compte : le cours et le premier QCM. Exercices et tuteur : inscription gratuite en 30 secondes, sans carte bancaire.

Le cours du chapitre · Tous les exercices du chapitre

Exercice suivant et tuteur →