Module data

Chargement et cache des données depuis S3 Parquet avec Streamlit @st.cache_data (TTL 3600s).

Données : 178K recettes + 1.1M ratings (~450 MB Parquet) → voir Glossaire pour détails.

data.loaders

Classe DataLoader pour chargement de données avec gestion d’erreurs robuste.

Classes pour le chargement de données avec gestion d’erreurs.

Ce module contient les classes pour charger les données depuis S3/DuckDB avec une gestion robuste des exceptions personnalisées.

class mangetamain_analytics.data.loaders.DataLoader[source]

Bases : object

Classe pour charger les données avec gestion d’erreurs robuste.

Cette classe encapsule la logique de chargement de données depuis mangetamain_data_utils avec gestion appropriée des exceptions.

Exemples

>>> loader = DataLoader()
>>> recipes = loader.load_recipes()
>>> ratings = loader.load_ratings(min_interactions=100)
load_recipes() Any[source]

Charge les recettes depuis S3.

Renvoie:

DataFrame Polars avec les recettes

Lève:

DataLoadError – Si le module est introuvable ou si le chargement échoue

load_ratings(min_interactions: int = 100, return_metadata: bool = False, verbose: bool = False) Any[source]

Charge les ratings pour analyse long-terme depuis S3.

Paramètres:
  • min_interactions – Nombre minimum d’interactions requises

  • return_metadata – Si True, retourne (data, metadata)

  • verbose – Mode verbeux

Renvoie:

DataFrame Polars avec les ratings (ou tuple si return_metadata=True)

Lève:

DataLoadError – Si le module est introuvable ou si le chargement échoue

Classe DataLoader

Encapsule la logique de chargement depuis mangetamain_data_utils avec exceptions personnalisées.

Méthodes :

  • load_recipes() : Charge recettes depuis S3 Parquet

  • load_ratings(min_interactions, return_metadata, verbose) : Charge ratings pour analyse long-terme

Exceptions levées :

  • DataLoadError : Si module introuvable ou chargement S3 échoue

Exemple :

from mangetamain_analytics.data.loaders import DataLoader
from mangetamain_analytics.exceptions import DataLoadError

loader = DataLoader()

try:
    recipes = loader.load_recipes()
    print(f"Chargé {len(recipes)} recettes")
except DataLoadError as e:
    print(f"Erreur: {e.source} - {e.detail}")

Relation avec cached_loaders

cached_loaders utilise DataLoader en interne :

  1. DataLoader : Logique métier + gestion erreurs (testable)

  2. cached_loaders : Wrapping avec @st.cache_data (cache Streamlit)

Cette séparation permet de tester DataLoader sans mocker Streamlit.

data.cached_loaders

Fonctions de chargement des données avec cache Streamlit.

Module pour charger les données avec cache Streamlit.

Ce module wrapper les fonctions de chargement avec le décorateur @st.cache_data pour améliorer les performances. La logique de chargement et de gestion d’erreurs est déléguée à la classe DataLoader.

mangetamain_analytics.data.cached_loaders.get_recipes_clean() Any

Charge les recettes depuis S3 avec cache (1h).

mangetamain_analytics.data.cached_loaders.get_ratings_longterm(min_interactions: int = 100, return_metadata: bool = False, verbose: bool = False) Any

Charge les ratings pour analyse long-terme depuis S3 avec cache (1h).

Fonctions Principales

  • get_recipes_clean() : Charge les recettes depuis S3 Parquet

  • get_ratings_longterm() : Charge les ratings pour analyse long-terme

Schéma des Données

get_recipes_clean() retourne:

  • id : Identifiant unique recette (int)

  • name : Nom de la recette (str)

  • minutes : Temps de préparation en minutes (int)

  • submitted : Date soumission (date)

  • year : Année soumission (int)

  • n_ingredients : Nombre d’ingrédients (int)

  • complexity_score : Score complexité 0-10 (float)

  • calories, protein, fat, sodium : Infos nutritionnelles (float)

  • tags : Liste tags recette (list[str])

  • day_of_week : Jour semaine (0=Lundi, 6=Dimanche)

  • season : Saison (Automne, Hiver, Printemps, Été)

Taille: 178,265 recettes, ~250 MB Parquet compressé

get_ratings_longterm() retourne:

  • user_id : Identifiant utilisateur (int)

  • recipe_id : Identifiant recette (int)

  • date : Date du rating (date)

  • rating : Note 0-5 étoiles (int)

  • review : Texte commentaire optionnel (str)

Taille: 1.1M+ ratings, ~180 MB Parquet compressé

Options Avancées

get_ratings_longterm() accepte:

  • min_interactions (int, défaut 100) : Filtrer recettes avec minimum interactions

  • return_metadata (bool, défaut False) : Retourner tuple (data, metadata)

  • verbose (bool, défaut False) : Afficher logs détaillés chargement

Metadata contient:

  • total_ratings : Nombre total ratings

  • total_users : Nombre utilisateurs uniques

  • total_recipes : Nombre recettes notées

  • date_range : Plage temporelle (min, max)

  • load_time_ms : Temps chargement en millisecondes

Mécanisme de Cache

Les fonctions utilisent le décorateur @st.cache_data avec :

  • TTL : 3600 secondes (1 heure)

  • Spinner : Message de chargement visible

  • Lazy imports : Compatibilité tests locaux

Exemples d’Utilisation

Chargement basique :

from data.cached_loaders import get_recipes_clean, get_ratings_longterm

# Chargé une seule fois par heure depuis S3
recipes = get_recipes_clean()  # DataFrame 178K recettes
ratings = get_ratings_longterm()  # DataFrame 1.1M+ ratings

print(f"Loaded {len(recipes)} recipes, {len(ratings)} ratings")

Avec options avancées :

# Filtrer recettes populaires + metadata
ratings, metadata = get_ratings_longterm(
    min_interactions=100,  # Minimum 100 ratings
    return_metadata=True,
    verbose=True
)

print(f"Total users: {metadata['total_users']:,}")
print(f"Date range: {metadata['date_range']}")
print(f"Load time: {metadata['load_time_ms']} ms")

Analyser les données :

import polars as pl

# Filtrer recettes par année
recipes_2018 = recipes.filter(pl.col('year') == 2018)

# Recettes rapides (< 30 min)
quick_recipes = recipes.filter(pl.col('minutes') < 30)

# Recettes par saison
winter_recipes = recipes.filter(pl.col('season') == 'Hiver')

# Top recettes notées
top_ratings = ratings.filter(pl.col('rating') == 5)

Joindre recettes et ratings :

# Join pour analyse combinée
recipes_with_ratings = recipes.join(
    ratings,
    left_on='id',
    right_on='recipe_id',
    how='inner'
)

# Calculer moyenne rating par recette
avg_ratings = recipes_with_ratings.group_by('id').agg([
    pl.col('rating').mean().alias('avg_rating'),
    pl.col('rating').count().alias('num_ratings')
])

Gestion du cache :

import streamlit as st

# Forcer rechargement programmatique
st.cache_data.clear()

# Recharger données fraîches
recipes = get_recipes_clean()

# Afficher info cache
st.info(f"Cache TTL: 1 heure. Dernière maj: {datetime.now()}")

Performance

  • Premier chargement : 5-10 secondes (depuis S3 Parquet)

  • Chargements suivants : <0.1 seconde (cache mémoire Streamlit)

  • Gain : 50-100x sur navigations répétées

Pour forcer le rechargement :

  1. Menu Streamlit → « Clear cache »

  2. Recharger la page

Optimisation Mémoire

Les données sont chargées en Polars (format columnar) pour:

  • Empreinte mémoire réduite vs Pandas

  • Performance filtres/agrégations 5-10x plus rapide

  • Lazy evaluation pour transformations complexes

Conversion Pandas si nécessaire:

recipes_pd = recipes.to_pandas()  # Polars → Pandas

Troubleshooting

Erreur: « No S3 credentials »

Solution: Vérifier fichier 96_keys/credentials existe avec format INI valide.

Voir: /s3 pour configuration S3 complète.

Erreur: « Cache data too large »

Si l’app consomme trop de mémoire:

  1. Réduire TTL cache dans code: @st.cache_data(ttl=1800) (30 min)

  2. Filtrer données avant mise en cache

  3. Augmenter RAM serveur (actuel: 32 GB dataia)

Chargement lent (> 30 secondes)

Causes possibles:

  1. Connexion S3 lente → Vérifier DNAT bypass (/s3)

  2. Premier chargement normal (création cache)

  3. Cache expiré → Rechargé toutes les heures

Colonnes manquantes dans DataFrame

Certaines colonnes sont calculées:

  • season : Dérivé de submitted (mois → saison)

  • day_of_week : Dérivé de submitted (0-6)

  • complexity_score : Calculé depuis n_steps, n_ingredients

Si absentes: vérifier version Parquet S3 est à jour.

Source des Données

  • Dataset original: Food.com (Kaggle)

  • Période: 1999-2018 (20 ans)

  • Preprocessing: Nettoyage, enrichissement, feature engineering

  • Format: Parquet compressé Snappy

  • Stockage: S3 Garage (s3fast.lafrance.io)

  • Total: ~450 MB compressé, ~2.5 GB décompressé

Voir: Documentation projet EDA (00_eda/) pour détails preprocessing.