- Ajout des 10 TPs d'évaluation (sans PDF) - Création GLOSSAIRE.md et AMELIORATIONS.md - Corrections f-strings, eval(), sommaires Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
501 lines
15 KiB
Plaintext
501 lines
15 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-0",
|
|
"metadata": {},
|
|
"source": [
|
|
"# TP Évaluation - Catalogue Netflix\n",
|
|
"\n",
|
|
"**Durée : 1h30**\n",
|
|
"\n",
|
|
"**Nom :** \n",
|
|
"\n",
|
|
"**Prénom :**\n",
|
|
"\n",
|
|
"---\n",
|
|
"\n",
|
|
"Dans ce TP, vous allez manipuler un catalogue de films et séries inspiré de Netflix.\n",
|
|
"\n",
|
|
"**Compétences évaluées :**\n",
|
|
"- Manipulation de listes de dictionnaires\n",
|
|
"- Filtrage et tri de données\n",
|
|
"- Algorithmes de recherche"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-1",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Données initiales\n",
|
|
"\n",
|
|
"**Exécutez cette cellule avant de commencer.**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-2",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Catalogue de contenus\n",
|
|
"# type: \"film\" ou \"serie\"\n",
|
|
"# duree: en minutes (pour les films)\n",
|
|
"# saisons et duree_moy: pour les series (duree moyenne par episode)\n",
|
|
"catalogue = [\n",
|
|
" {\"titre\": \"Stranger Things\", \"type\": \"serie\", \"genre\": [\"SF\", \"Horreur\"], \"annee\": 2016, \"note\": 8.7, \"saisons\": 4, \"duree_moy\": 50},\n",
|
|
" {\"titre\": \"Breaking Bad\", \"type\": \"serie\", \"genre\": [\"Drame\", \"Thriller\"], \"annee\": 2008, \"note\": 9.5, \"saisons\": 5, \"duree_moy\": 47},\n",
|
|
" {\"titre\": \"The Crown\", \"type\": \"serie\", \"genre\": [\"Drame\", \"Historique\"], \"annee\": 2016, \"note\": 8.6, \"saisons\": 6, \"duree_moy\": 58},\n",
|
|
" {\"titre\": \"Squid Game\", \"type\": \"serie\", \"genre\": [\"Thriller\", \"Drame\"], \"annee\": 2021, \"note\": 8.0, \"saisons\": 1, \"duree_moy\": 55},\n",
|
|
" {\"titre\": \"Wednesday\", \"type\": \"serie\", \"genre\": [\"Comedie\", \"Fantastique\"], \"annee\": 2022, \"note\": 8.1, \"saisons\": 1, \"duree_moy\": 45},\n",
|
|
" {\"titre\": \"Inception\", \"type\": \"film\", \"genre\": [\"SF\", \"Action\"], \"annee\": 2010, \"note\": 8.8, \"duree\": 148},\n",
|
|
" {\"titre\": \"The Dark Knight\", \"type\": \"film\", \"genre\": [\"Action\", \"Drame\"], \"annee\": 2008, \"note\": 9.0, \"duree\": 152},\n",
|
|
" {\"titre\": \"Pulp Fiction\", \"type\": \"film\", \"genre\": [\"Drame\", \"Thriller\"], \"annee\": 1994, \"note\": 8.9, \"duree\": 154},\n",
|
|
" {\"titre\": \"Interstellar\", \"type\": \"film\", \"genre\": [\"SF\", \"Drame\"], \"annee\": 2014, \"note\": 8.6, \"duree\": 169},\n",
|
|
" {\"titre\": \"The Matrix\", \"type\": \"film\", \"genre\": [\"SF\", \"Action\"], \"annee\": 1999, \"note\": 8.7, \"duree\": 136},\n",
|
|
" {\"titre\": \"Parasite\", \"type\": \"film\", \"genre\": [\"Thriller\", \"Comedie\"], \"annee\": 2019, \"note\": 8.5, \"duree\": 132},\n",
|
|
" {\"titre\": \"Don't Look Up\", \"type\": \"film\", \"genre\": [\"Comedie\", \"SF\"], \"annee\": 2021, \"note\": 7.2, \"duree\": 138}\n",
|
|
"]\n",
|
|
"\n",
|
|
"# Historique de visionnage\n",
|
|
"historique = [\n",
|
|
" {\"titre\": \"Stranger Things\", \"episodes_vus\": 34, \"note_perso\": 9},\n",
|
|
" {\"titre\": \"Inception\", \"note_perso\": 10},\n",
|
|
" {\"titre\": \"The Matrix\", \"note_perso\": 8},\n",
|
|
" {\"titre\": \"Wednesday\", \"episodes_vus\": 8, \"note_perso\": 7}\n",
|
|
"]\n",
|
|
"\n",
|
|
"# Ma liste (watchlist)\n",
|
|
"ma_liste = [\"Breaking Bad\", \"Interstellar\", \"Parasite\"]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-3",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"\n",
|
|
"## Exercice 1 - Exploration du catalogue (25 min)\n",
|
|
"\n",
|
|
"### 1.1 Afficher un contenu (4 pts)\n",
|
|
"\n",
|
|
"Écrivez une fonction `afficher_contenu(contenu)` qui affiche les informations d'un film ou d'une série.\n",
|
|
"\n",
|
|
"Pour un film : `Inception (2010) - Film | 2h28 | Note: 8.8`\n",
|
|
"\n",
|
|
"Pour une série : `Stranger Things (2016) - Serie | 4 saisons | Note: 8.7`\n",
|
|
"\n",
|
|
"*Aide : pour convertir les minutes en heures, utilisez `duree // 60` et `duree % 60`*"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-4",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def afficher_contenu(contenu):\n",
|
|
" titre = contenu[\"titre\"]\n",
|
|
" annee = contenu[\"annee\"]\n",
|
|
" note = contenu[\"note\"]\n",
|
|
" \n",
|
|
" if contenu[\"type\"] == \"film\":\n",
|
|
" duree = contenu[\"duree\"]\n",
|
|
" heures = duree // 60\n",
|
|
" minutes = duree % 60\n",
|
|
" # Afficher les infos du film\n",
|
|
" # Votre code ici\n",
|
|
" pass\n",
|
|
" else:\n",
|
|
" saisons = contenu[\"saisons\"]\n",
|
|
" # Afficher les infos de la serie\n",
|
|
" # Votre code ici\n",
|
|
" pass\n",
|
|
"\n",
|
|
"# Tests\n",
|
|
"afficher_contenu(catalogue[0]) # Serie\n",
|
|
"afficher_contenu(catalogue[5]) # Film"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-5",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 1.2 Compter films et séries (4 pts)\n",
|
|
"\n",
|
|
"Écrivez une fonction `compter_par_type(catalogue)` qui renvoie un dictionnaire avec le nombre de films et de séries."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-6",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def compter_par_type(catalogue):\n",
|
|
" compteur = {\"film\": 0, \"serie\": 0}\n",
|
|
" \n",
|
|
" for contenu in catalogue:\n",
|
|
" # Votre code ici\n",
|
|
" pass\n",
|
|
" \n",
|
|
" return compteur\n",
|
|
"\n",
|
|
"# Test\n",
|
|
"print(\"Contenu du catalogue :\", compter_par_type(catalogue))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-7",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 1.3 Liste des genres (4 pts)\n",
|
|
"\n",
|
|
"Écrivez une fonction `tous_les_genres(catalogue)` qui renvoie la liste de tous les genres présents dans le catalogue, sans doublons, triée par ordre alphabétique."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-8",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def tous_les_genres(catalogue):\n",
|
|
" genres = []\n",
|
|
" \n",
|
|
" for contenu in catalogue:\n",
|
|
" for genre in contenu[\"genre\"]:\n",
|
|
" if genre not in genres:\n",
|
|
" # Votre code ici\n",
|
|
" pass\n",
|
|
" \n",
|
|
" genres.sort()\n",
|
|
" return genres\n",
|
|
"\n",
|
|
"# Test\n",
|
|
"print(\"Genres disponibles :\", tous_les_genres(catalogue))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-9",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"\n",
|
|
"## Exercice 2 - Recherche et filtrage (35 min)\n",
|
|
"\n",
|
|
"### 2.1 Rechercher par genre (5 pts)\n",
|
|
"\n",
|
|
"Écrivez une fonction `rechercher_par_genre(catalogue, genre)` qui renvoie la liste des contenus ayant ce genre."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-10",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def rechercher_par_genre(catalogue, genre):\n",
|
|
" resultats = []\n",
|
|
" \n",
|
|
" for contenu in catalogue:\n",
|
|
" if genre in contenu[\"genre\"]:\n",
|
|
" # Votre code ici\n",
|
|
" pass\n",
|
|
" \n",
|
|
" return resultats\n",
|
|
"\n",
|
|
"# Test\n",
|
|
"print(\"Contenus SF :\")\n",
|
|
"for c in rechercher_par_genre(catalogue, \"SF\"):\n",
|
|
" afficher_contenu(c)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-11",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 2.2 Filtrer par note minimum (5 pts)\n",
|
|
"\n",
|
|
"Écrivez une fonction `filtrer_par_note(catalogue, note_min)` qui renvoie la liste des contenus ayant une note supérieure ou égale à `note_min`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-12",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def filtrer_par_note(catalogue, note_min):\n",
|
|
" resultats = []\n",
|
|
" \n",
|
|
" for contenu in catalogue:\n",
|
|
" # Votre code ici\n",
|
|
" pass\n",
|
|
" \n",
|
|
" return resultats\n",
|
|
"\n",
|
|
"# Test\n",
|
|
"print(\"Contenus avec note >= 8.5 :\")\n",
|
|
"for c in filtrer_par_note(catalogue, 8.5):\n",
|
|
" afficher_contenu(c)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-13",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 2.3 Trier par note (6 pts)\n",
|
|
"\n",
|
|
"Écrivez une fonction `trier_par_note(catalogue)` qui renvoie une nouvelle liste triée par note décroissante.\n",
|
|
"\n",
|
|
"*Aide : utilisez `sorted(liste, key=lambda x: x[\"note\"], reverse=True)`*"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-14",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def trier_par_note(catalogue):\n",
|
|
" # Votre code ici\n",
|
|
" pass\n",
|
|
"\n",
|
|
"# Test\n",
|
|
"print(\"Top 5 par note :\")\n",
|
|
"for c in trier_par_note(catalogue)[:5]:\n",
|
|
" afficher_contenu(c)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-15",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 2.4 Recherche combinée (6 pts)\n",
|
|
"\n",
|
|
"Écrivez une fonction `recherche_avancee(catalogue, type_contenu, genre, note_min)` qui filtre selon plusieurs critères.\n",
|
|
"\n",
|
|
"- `type_contenu` : \"film\", \"serie\" ou None (tous)\n",
|
|
"- `genre` : un genre ou None (tous)\n",
|
|
"- `note_min` : note minimum ou None (pas de filtre)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-16",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def recherche_avancee(catalogue, type_contenu, genre, note_min):\n",
|
|
" resultats = []\n",
|
|
" \n",
|
|
" for contenu in catalogue:\n",
|
|
" # Verifier le type (si specifie)\n",
|
|
" if type_contenu != None and contenu[\"type\"] != type_contenu:\n",
|
|
" continue\n",
|
|
" \n",
|
|
" # Verifier le genre (si specifie)\n",
|
|
" if genre != None and genre not in contenu[\"genre\"]:\n",
|
|
" continue\n",
|
|
" \n",
|
|
" # Verifier la note (si specifiee)\n",
|
|
" # Votre code ici\n",
|
|
" \n",
|
|
" resultats.append(contenu)\n",
|
|
" \n",
|
|
" return resultats\n",
|
|
"\n",
|
|
"# Test\n",
|
|
"print(\"Films SF avec note >= 8.5 :\")\n",
|
|
"for c in recherche_avancee(catalogue, \"film\", \"SF\", 8.5):\n",
|
|
" afficher_contenu(c)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-17",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"\n",
|
|
"## Exercice 3 - Bonus (20 min)\n",
|
|
"\n",
|
|
"### 3.1 Temps de visionnage (5 pts)\n",
|
|
"\n",
|
|
"Écrivez une fonction `temps_visionne(historique, catalogue)` qui calcule le temps total de visionnage en minutes.\n",
|
|
"\n",
|
|
"Pour un film : la durée complète.\n",
|
|
"Pour une série : `episodes_vus * duree_moy`"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-18",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def temps_visionne(historique, catalogue):\n",
|
|
" total_minutes = 0\n",
|
|
" \n",
|
|
" for h in historique:\n",
|
|
" # Trouver le contenu dans le catalogue\n",
|
|
" contenu = None\n",
|
|
" for c in catalogue:\n",
|
|
" if c[\"titre\"] == h[\"titre\"]:\n",
|
|
" contenu = c\n",
|
|
" break\n",
|
|
" \n",
|
|
" if contenu == None:\n",
|
|
" continue\n",
|
|
" \n",
|
|
" if contenu[\"type\"] == \"film\":\n",
|
|
" # Ajouter la duree du film\n",
|
|
" # Votre code ici\n",
|
|
" pass\n",
|
|
" else:\n",
|
|
" # Ajouter duree des episodes vus\n",
|
|
" # Votre code ici\n",
|
|
" pass\n",
|
|
" \n",
|
|
" return total_minutes\n",
|
|
"\n",
|
|
"# Test\n",
|
|
"minutes = temps_visionne(historique, catalogue)\n",
|
|
"heures = minutes // 60\n",
|
|
"print(\"Temps total visionne :\", heures, \"h\", minutes % 60, \"min\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-19",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 3.2 Recommandation simple (5 pts)\n",
|
|
"\n",
|
|
"Écrivez une fonction `recommander(historique, catalogue)` qui recommande un contenu basé sur les genres préférés de l'utilisateur.\n",
|
|
"\n",
|
|
"1. Trouvez les genres des contenus dans l'historique\n",
|
|
"2. Trouvez un contenu non vu qui a au moins un genre en commun\n",
|
|
"3. Renvoyez le contenu avec la meilleure note"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-20",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def recommander(historique, catalogue):\n",
|
|
" # Collecter les genres des contenus vus\n",
|
|
" genres_aimes = []\n",
|
|
" titres_vus = []\n",
|
|
" \n",
|
|
" for h in historique:\n",
|
|
" titres_vus.append(h[\"titre\"])\n",
|
|
" # Trouver le contenu pour recuperer ses genres\n",
|
|
" for c in catalogue:\n",
|
|
" if c[\"titre\"] == h[\"titre\"]:\n",
|
|
" for g in c[\"genre\"]:\n",
|
|
" if g not in genres_aimes:\n",
|
|
" genres_aimes.append(g)\n",
|
|
" \n",
|
|
" # Trouver le meilleur contenu non vu avec un genre en commun\n",
|
|
" meilleur = None\n",
|
|
" meilleure_note = 0\n",
|
|
" \n",
|
|
" for c in catalogue:\n",
|
|
" # Verifier que non vu\n",
|
|
" if c[\"titre\"] in titres_vus:\n",
|
|
" continue\n",
|
|
" \n",
|
|
" # Verifier qu'il a un genre en commun\n",
|
|
" # Votre code ici\n",
|
|
" pass\n",
|
|
" \n",
|
|
" return meilleur\n",
|
|
"\n",
|
|
"# Test\n",
|
|
"reco = recommander(historique, catalogue)\n",
|
|
"if reco:\n",
|
|
" print(\"Recommandation :\")\n",
|
|
" afficher_contenu(reco)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cell-21",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 3.3 Note moyenne par genre (4 pts)\n",
|
|
"\n",
|
|
"Écrivez une fonction `note_moyenne_par_genre(catalogue)` qui renvoie un dictionnaire `{genre: note_moyenne}`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cell-22",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def note_moyenne_par_genre(catalogue):\n",
|
|
" # Dictionnaire pour stocker somme et compteur par genre\n",
|
|
" sommes = {}\n",
|
|
" compteurs = {}\n",
|
|
" \n",
|
|
" for contenu in catalogue:\n",
|
|
" for genre in contenu[\"genre\"]:\n",
|
|
" if genre not in sommes:\n",
|
|
" sommes[genre] = 0\n",
|
|
" compteurs[genre] = 0\n",
|
|
" sommes[genre] = sommes[genre] + contenu[\"note\"]\n",
|
|
" compteurs[genre] = compteurs[genre] + 1\n",
|
|
" \n",
|
|
" # Calculer les moyennes\n",
|
|
" moyennes = {}\n",
|
|
" for genre in sommes:\n",
|
|
" moyennes[genre] = round(sommes[genre] / compteurs[genre], 1)\n",
|
|
" \n",
|
|
" return moyennes\n",
|
|
"\n",
|
|
"# Test\n",
|
|
"print(\"Note moyenne par genre :\")\n",
|
|
"for genre, note in note_moyenne_par_genre(catalogue).items():\n",
|
|
" print(\" \", genre, \":\", note)"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"name": "python",
|
|
"version": "3.9.0"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|