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 :
objectClasse 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 Parquetload_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 :
DataLoader: Logique métier + gestion erreurs (testable)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 Parquetget_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 interactionsreturn_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 ratingstotal_users: Nombre utilisateurs uniquestotal_recipes: Nombre recettes notéesdate_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 :
Menu Streamlit → « Clear cache »
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:
Réduire TTL cache dans code:
@st.cache_data(ttl=1800)(30 min)Filtrer données avant mise en cache
Augmenter RAM serveur (actuel: 32 GB dataia)
Chargement lent (> 30 secondes)
Causes possibles:
Connexion S3 lente → Vérifier DNAT bypass (/s3)
Premier chargement normal (création cache)
Cache expiré → Rechargé toutes les heures
Colonnes manquantes dans DataFrame
Certaines colonnes sont calculées:
season: Dérivé desubmitted(mois → saison)day_of_week: Dérivé desubmitted(0-6)complexity_score: Calculé depuisn_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.