{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Cours 5 — Du dictionnaire au DataFrame : premiers pas avec `pandas`\n",
    "\n",
    "Ce cours fait le pont entre les **dictionnaires** vus au cours precedent et la bibliotheque **`pandas`**, qui sert a manipuler des donnees comme un tableau Excel ou comme une table SQL.\n",
    "\n",
    "### Prerequis (cours 1 a 4)\n",
    "- Variables, types (`int`, `float`, `str`, `bool`).\n",
    "- Listes et indices (`liste[0]`).\n",
    "- Boucles `for` + conditions `if / elif / else`.\n",
    "- Dictionnaires (`cle -> valeur`) et listes de dictionnaires.\n",
    "\n",
    "### Objectifs de la seance\n",
    "- Comprendre qu un `DataFrame` est tres proche d une **liste de dictionnaires**.\n",
    "- Importer `pandas` et creer un mini `DataFrame` a la main.\n",
    "- Lire un fichier CSV ShopNow avec `pd.read_csv(...)`.\n",
    "- Explorer un `DataFrame` avec `head`, `tail`, `shape`, `columns`, `info`.\n",
    "- Selectionner des colonnes (`df['col']`, `df[['col1', 'col2']]`) comme un `SELECT` en SQL.\n",
    "\n",
    "### Plan\n",
    "0. Rappel express : dictionnaires et listes de dictionnaires.\n",
    "1. Du dictionnaire au `DataFrame`.\n",
    "2. Lire un CSV ShopNow.\n",
    "3. Explorer un `DataFrame` (`head`, `tail`, `shape`, `columns`).\n",
    "4. Selectionner des colonnes (parallele SQL `SELECT`).\n",
    "5. Corrections.\n",
    "6. Mini defi de fin de seance.\n",
    "7. Revue du cours."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 0. Rappel express : dictionnaires et listes de dictionnaires\n",
    "\n",
    "Au cours 4, on a vu qu un **dictionnaire** sert a stocker des donnees avec des **cles explicites** (`'nom'`, `'budget'`, ...).\n",
    "Et qu une **liste de dictionnaires** est tres pratique pour representer plusieurs campagnes (une par dictionnaire).\n",
    "\n",
    "On va rejouer ca en 30 secondes pour bien repartir."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Quick recap: a list of dictionaries representing marketing campaigns\n",
    "campagnes = [\n",
    "    {\"nom\": \"Brand FR\",       \"canal\": \"Google Ads\", \"budget\": 1000, \"clics\": 400, \"conversions\": 24},\n",
    "    {\"nom\": \"Acquisition UK\", \"canal\": \"LinkedIn\",   \"budget\": 1500, \"clics\": 500, \"conversions\": 30},\n",
    "    {\"nom\": \"Retargeting ES\", \"canal\": \"Facebook\",   \"budget\": 700,  \"clics\": 280, \"conversions\": 21},\n",
    "]\n",
    "\n",
    "for campagne in campagnes:\n",
    "    cpc = campagne[\"budget\"] / campagne[\"clics\"]\n",
    "    print(f\"{campagne['nom']} ({campagne['canal']}) | CPC={cpc:.2f} euros\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 0 — Mini rappel dictionnaires\n",
    "\n",
    "1. Cree une liste `campagnes_recap` avec **2 dictionnaires** de ton choix (champs : `nom`, `canal`, `budget`, `clics`).\n",
    "2. Parcours la liste avec une boucle `for`.\n",
    "3. Pour chaque campagne, affiche une phrase du type :\n",
    "   `Campagne <nom> sur <canal> : budget de <budget> euros, <clics> clics`.\n",
    "\n",
    "Objectif : etre sur que la notion de **liste de dictionnaires** est bien revue."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO - Exercice 0 (recap dict)\n",
    "pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Du dictionnaire au `DataFrame`\n",
    "\n",
    "En pratique, on ne fait pas tout a la main avec des dictionnaires et des boucles : on utilise **`pandas`**, une bibliotheque qui represente les donnees sous forme de **tableau** (lignes / colonnes), comme Excel ou comme une table SQL.\n",
    "\n",
    "L objet principal s appelle un **`DataFrame`**.\n",
    "\n",
    "Tres important :\n",
    "- une **ligne** du `DataFrame` = un **dictionnaire** (une campagne, un utilisateur, une session, ...)\n",
    "- une **colonne** du `DataFrame` = une **cle** commune a toutes les lignes (`nom`, `budget`, `clics`, ...)\n",
    "\n",
    "Donc passer d une liste de dictionnaires a un `DataFrame` est tres naturel."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Step 1: import pandas\n",
    "import pandas as pd\n",
    "\n",
    "# Step 2: build a DataFrame from a list of dictionaries\n",
    "campagnes = [\n",
    "    {\"nom\": \"Brand FR\",       \"canal\": \"Google Ads\", \"budget\": 1000, \"clics\": 400, \"conversions\": 24},\n",
    "    {\"nom\": \"Acquisition UK\", \"canal\": \"LinkedIn\",   \"budget\": 1500, \"clics\": 500, \"conversions\": 30},\n",
    "    {\"nom\": \"Retargeting ES\", \"canal\": \"Facebook\",   \"budget\": 700,  \"clics\": 280, \"conversions\": 21},\n",
    "]\n",
    "\n",
    "df_campagnes = pd.DataFrame(campagnes)\n",
    "df_campagnes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Quelques observations :\n",
    "- pandas a devine les **noms de colonnes** a partir des cles du dictionnaire.\n",
    "- chaque **ligne** correspond a **un** dictionnaire de la liste.\n",
    "- l affichage est beaucoup plus lisible qu un `print(campagnes)`.\n",
    "\n",
    "Petite question : combien y a-t-il de lignes et combien de colonnes dans ce `DataFrame` ?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 1 — Premier `DataFrame`\n",
    "\n",
    "1. Cree une liste `sessions_demo` de **3 dictionnaires** avec les cles :\n",
    "   - `session_id`\n",
    "   - `source`     (ex. `'Google Ads'`, `'Instagram Ads'`, `'Email'`)\n",
    "   - `device`     (ex. `'mobile'` ou `'desktop'`)\n",
    "   - `converted`  (0 ou 1)\n",
    "2. Construis un `DataFrame` `df_sessions_demo` a partir de cette liste.\n",
    "3. Affiche le `DataFrame`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO - Exercice 1 (DataFrame from list of dicts)\n",
    "pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Lire un CSV ShopNow avec `pd.read_csv`\n",
    "\n",
    "Construire des dictionnaires a la main, c est pratique pour apprendre mais pas realiste.\n",
    "En vrai, on a souvent un **fichier CSV** (export d outil marketing, base de donnees, etc.).\n",
    "\n",
    "Pour notre fil rouge **ShopNow**, on dispose de 4 fichiers, les memes que dans le module SQL :\n",
    "- `campaigns.csv`\n",
    "- `users.csv`\n",
    "- `sessions.csv`\n",
    "- `orders.csv`\n",
    "\n",
    "Pour lire un CSV avec `pandas`, on utilise `pd.read_csv(\"chemin/du/fichier.csv\")`.\n",
    "\n",
    "### Si tu travailles dans Google Colab\n",
    "1. Dans le menu de gauche, clique sur l icone **Fichiers** (le dossier).\n",
    "2. Glisse-depose le fichier `sessions.csv` dans Colab.\n",
    "3. Le fichier est alors accessible via `'sessions.csv'`.\n",
    "\n",
    "### Si tu travailles en local (Jupyter)\n",
    "- Mets le fichier `sessions.csv` dans le **meme dossier** que ton notebook.\n",
    "- Tu peux alors le lire avec `pd.read_csv('sessions.csv')`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Read the ShopNow sessions file\n",
    "import pandas as pd\n",
    "\n",
    "# Adjust the path if your file is somewhere else\n",
    "df_sessions = pd.read_csv(\"sessions.csv\")\n",
    "\n",
    "# Show the first rows\n",
    "df_sessions.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Si tu vois bien un tableau apparaitre avec des colonnes comme `session_id`, `user_id`, `source`, `device`, etc., c est gagne.\n",
    "Si tu as une erreur du type `FileNotFoundError`, c est que le fichier n est pas a l endroit attendu.\n",
    "\n",
    "Quelques regles a connaitre :\n",
    "- `pd.read_csv(...)` lit le fichier et **renvoie** un `DataFrame`.\n",
    "- On stocke ce `DataFrame` dans une variable, ici `df_sessions`.\n",
    "- A partir de la, on ne touche plus au CSV : on manipule `df_sessions`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Explorer un `DataFrame` : `head`, `tail`, `shape`, `columns`, `info`\n",
    "\n",
    "Quand on recoit un nouveau fichier, on fait **toujours** la meme chose : on regarde a quoi il ressemble.\n",
    "\n",
    "Les outils de base :\n",
    "- `df.head(n)` : les **n premieres** lignes (par defaut 5).\n",
    "- `df.tail(n)` : les **n dernieres** lignes.\n",
    "- `df.shape`   : un couple `(nb_lignes, nb_colonnes)`.\n",
    "- `df.columns` : la liste des **noms de colonnes**.\n",
    "- `df.info()`  : un resume avec les types de colonnes et le nombre de valeurs.\n",
    "\n",
    "Parallele SQL : c est l equivalent du `SELECT * FROM sessions LIMIT 5;` ou de la commande `DESCRIBE sessions;`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Explore the DataFrame\n",
    "print(\"Shape (rows, columns):\", df_sessions.shape)\n",
    "print(\"Columns:\", list(df_sessions.columns))\n",
    "\n",
    "print(\"\\nFirst 5 rows:\")\n",
    "print(df_sessions.head())\n",
    "\n",
    "print(\"\\nLast 3 rows:\")\n",
    "print(df_sessions.tail(3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Quick technical summary of the DataFrame\n",
    "df_sessions.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Questions de comprehension (mentalement) :\n",
    "1. Combien y a-t-il de lignes dans `df_sessions` ?\n",
    "2. Quelles sont les colonnes ?\n",
    "3. La colonne `converted` est-elle de type texte ou de type nombre ?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 2 — Explorer un autre CSV\n",
    "\n",
    "Avec un autre fichier du fil rouge (`users.csv`), entraine-toi a faire les memes manipulations.\n",
    "\n",
    "1. Lis le fichier dans un `DataFrame` `df_users`.\n",
    "2. Affiche les **5 premieres** lignes.\n",
    "3. Affiche la forme du `DataFrame` (`shape`) et la liste des colonnes.\n",
    "4. Affiche les **3 dernieres** lignes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO - Exercice 2 (read CSV and explore)\n",
    "pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Selectionner des colonnes (parallele SQL `SELECT`)\n",
    "\n",
    "En SQL on ecrit :\n",
    "```sql\n",
    "SELECT source, device, converted FROM sessions;\n",
    "```\n",
    "\n",
    "En `pandas`, on ecrit a peu pres la meme chose, mais avec des **crochets** :\n",
    "- une colonne : `df['source']`\n",
    "- plusieurs colonnes : `df[['source', 'device', 'converted']]`\n",
    "\n",
    "Points importants :\n",
    "- avec **une** paire de crochets et **un seul nom**, on obtient une **colonne** (= une `Series`).\n",
    "- avec **deux** paires de crochets et une **liste de noms**, on obtient un **sous-`DataFrame`**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Selection of one column\n",
    "sources = df_sessions[\"source\"]\n",
    "print(type(sources))\n",
    "print(sources.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Selection of several columns -> sub DataFrame\n",
    "df_sub = df_sessions[[\"source\", \"device\", \"converted\"]]\n",
    "print(type(df_sub))\n",
    "df_sub.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "On peut faire la lecture metier suivante : \n",
    "- `df_sessions[\"source\"]` = liste des **sources de trafic** ligne par ligne.\n",
    "- `df_sessions[[\"source\", \"device\", \"converted\"]]` = mini tableau avec les trois colonnes utiles pour analyser la **conversion par canal et par device**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 3 — Selection de colonnes\n",
    "\n",
    "A partir du `DataFrame` `df_sessions` :\n",
    "\n",
    "1. Affiche **uniquement** la colonne `device` (les 5 premieres valeurs suffisent).\n",
    "2. Cree un sous-`DataFrame` `df_kpi` qui contient seulement les colonnes :\n",
    "   - `source`\n",
    "   - `pages_viewed`\n",
    "   - `time_on_site`\n",
    "   - `converted`\n",
    "3. Affiche les 5 premieres lignes de `df_kpi`.\n",
    "4. Affiche le `shape` de `df_kpi` et compare-le au `shape` de `df_sessions` : qu est-ce qui change ?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO - Exercice 3 (column selection)\n",
    "pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Corrections proposees\n",
    "\n",
    "Compare tes solutions avec ces propositions. Plusieurs ecritures sont possibles, l essentiel est que le resultat soit le bon."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Correction - Exercice 0 (recap dict)\n",
    "campagnes_recap = [\n",
    "    {\"nom\": \"Promo Ete\",  \"canal\": \"Email\",      \"budget\": 800,  \"clics\": 250},\n",
    "    {\"nom\": \"Brand Q4\",   \"canal\": \"Google Ads\", \"budget\": 1200, \"clics\": 410},\n",
    "]\n",
    "\n",
    "for campagne in campagnes_recap:\n",
    "    print(\n",
    "        f\"Campagne {campagne['nom']} sur {campagne['canal']} : \"\n",
    "        f\"budget de {campagne['budget']} euros, {campagne['clics']} clics\"\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Correction - Exercice 1 (DataFrame from list of dicts)\n",
    "import pandas as pd\n",
    "\n",
    "sessions_demo = [\n",
    "    {\"session_id\": \"S0001\", \"source\": \"Google Ads\",    \"device\": \"mobile\",  \"converted\": 1},\n",
    "    {\"session_id\": \"S0002\", \"source\": \"Instagram Ads\", \"device\": \"mobile\",  \"converted\": 0},\n",
    "    {\"session_id\": \"S0003\", \"source\": \"Email\",         \"device\": \"desktop\", \"converted\": 1},\n",
    "]\n",
    "\n",
    "df_sessions_demo = pd.DataFrame(sessions_demo)\n",
    "df_sessions_demo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Correction - Exercice 2 (read CSV and explore)\n",
    "df_users = pd.read_csv(\"users.csv\")\n",
    "\n",
    "print(\"First 5 rows:\")\n",
    "print(df_users.head())\n",
    "\n",
    "print(\"\\nShape:\", df_users.shape)\n",
    "print(\"Columns:\", list(df_users.columns))\n",
    "\n",
    "print(\"\\nLast 3 rows:\")\n",
    "print(df_users.tail(3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Correction - Exercice 3 (column selection)\n",
    "print(\"Column device (5 first):\")\n",
    "print(df_sessions[\"device\"].head())\n",
    "\n",
    "df_kpi = df_sessions[[\"source\", \"pages_viewed\", \"time_on_site\", \"converted\"]]\n",
    "\n",
    "print(\"\\ndf_kpi.head():\")\n",
    "print(df_kpi.head())\n",
    "\n",
    "print(\"\\nShape of df_kpi:    \", df_kpi.shape)\n",
    "print(\"Shape of df_sessions:\", df_sessions.shape)\n",
    "# Same number of rows, fewer columns: we only kept the marketing KPI columns"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. Mini defi de fin de seance\n",
    "\n",
    "Objectif : enchainer **lecture CSV** + **exploration** + **selection de colonnes** sur le fichier `campaigns.csv` du fil rouge ShopNow.\n",
    "\n",
    "Marche a suivre :\n",
    "1. Lis le fichier `campaigns.csv` dans un `DataFrame` `df_campaigns`.\n",
    "2. Affiche son `shape` et la liste de ses colonnes.\n",
    "3. Affiche les 5 premieres lignes.\n",
    "4. Cree un sous-`DataFrame` `df_campaigns_short` qui ne contient que les colonnes :\n",
    "   - `campaign`\n",
    "   - `channel`\n",
    "   - `budget`\n",
    "5. Affiche les 5 premieres lignes de `df_campaigns_short`.\n",
    "\n",
    "Bonus oral / au tableau (le code n est pas demande aux etudiants ici) :\n",
    "- En SQL, ca correspondrait a quelle requete ?\n",
    "- Reponse type : `SELECT campaign, channel, budget FROM campaigns LIMIT 5;`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO - Mini defi (campaigns.csv)\n",
    "pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Correction - Mini defi (campaigns.csv)\n",
    "df_campaigns = pd.read_csv(\"campaigns.csv\")\n",
    "\n",
    "print(\"Shape:\", df_campaigns.shape)\n",
    "print(\"Columns:\", list(df_campaigns.columns))\n",
    "\n",
    "print(\"\\nFirst 5 rows:\")\n",
    "print(df_campaigns.head())\n",
    "\n",
    "df_campaigns_short = df_campaigns[[\"campaign\", \"channel\", \"budget\"]]\n",
    "\n",
    "print(\"\\ndf_campaigns_short.head():\")\n",
    "print(df_campaigns_short.head())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7. Revue du cours\n",
    "\n",
    "A la fin de ce cours 5, tu sais :\n",
    "- expliquer qu un **`DataFrame` est tres proche d une liste de dictionnaires** (lignes = dicts, colonnes = cles communes) ;\n",
    "- importer `pandas` avec `import pandas as pd` ;\n",
    "- creer un `DataFrame` a partir d une liste de dictionnaires (`pd.DataFrame(...)`) ;\n",
    "- **lire un fichier CSV** avec `pd.read_csv('fichier.csv')` ;\n",
    "- **explorer** un `DataFrame` avec `head`, `tail`, `shape`, `columns`, `info` ;\n",
    "- **selectionner des colonnes** avec `df['col']` ou `df[['col1', 'col2']]`, en faisant le parallele avec `SELECT col1, col2 FROM table;` en SQL.\n",
    "\n",
    "### Et apres ?\n",
    "Dans le **cours 6**, on apprendra a **filtrer** un `DataFrame` (equivalent du `WHERE` en SQL) puis a faire un **premier `groupby`** simple (compter / moyenner par source de trafic, par device, etc.)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
