{"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.12.12"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"datasetVersion","sourceId":14539412,"datasetId":9286395,"databundleVersionId":15369024}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false},"papermill":{"default_parameters":{},"duration":473.586387,"end_time":"2026-02-22T17:33:01.145505","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2026-02-22T17:25:07.559118","version":"2.6.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Machine learning 4 - Data processing (FR) v2_1 (version étudiant)\n\n```python\n# import de modules vus dans \"Machine learning 3 - Classification\"\n\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nimport pandas as pd\n\nimport plotly.express as px\nimport seaborn as sns\n\nfrom sklearn.metrics import *\nfrom sklearn.model_selection import train_test_split, cross_val_score\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.pipeline import Pipeline\n\nfrom sklearn.linear_model import LinearRegression\nfrom sklearn.neighbors import KNeighborsRegressor\nfrom sklearn.naive_bayes import BernoulliNB\nfrom sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor, plot_tree, export_text\nfrom sklearn.ensemble import RandomForestClassifier, RandomForestRegressor, GradientBoostingClassifier, GradientBoostingRegressor\nfrom lightgbm import LGBMClassifier, LGBMRegressor\nfrom xgboost import XGBClassifier, XGBRegressor\n```\n","metadata":{"papermill":{"duration":0.013991,"end_time":"2026-02-22T17:25:10.640733","exception":false,"start_time":"2026-02-22T17:25:10.626742","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# import de modules vus dans \"Machine learning 3 - Classification\"\n\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nimport pandas as pd\n\nimport plotly.express as px\nimport seaborn as sns\n\nfrom sklearn.metrics import *\nfrom sklearn.model_selection import train_test_split, cross_val_score\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.pipeline import Pipeline\n\nfrom sklearn.linear_model import LinearRegression\nfrom sklearn.neighbors import KNeighborsRegressor\nfrom sklearn.naive_bayes import BernoulliNB\nfrom sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor, plot_tree, export_text\nfrom sklearn.ensemble import RandomForestClassifier, RandomForestRegressor, GradientBoostingClassifier, GradientBoostingRegressor\nfrom lightgbm import LGBMClassifier, LGBMRegressor\nfrom xgboost import XGBClassifier, XGBRegressor","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:11:02.999087Z","iopub.execute_input":"2026-05-11T00:11:02.999435Z","iopub.status.idle":"2026-05-11T00:11:13.188806Z","shell.execute_reply.started":"2026-05-11T00:11:02.999394Z","shell.execute_reply":"2026-05-11T00:11:13.187692Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/penguins.csv')\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:15:37.194036Z","iopub.execute_input":"2026-05-11T00:15:37.194741Z","iopub.status.idle":"2026-05-11T00:15:37.244082Z","shell.execute_reply.started":"2026-05-11T00:15:37.194703Z","shell.execute_reply":"2026-05-11T00:15:37.242669Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:16:12.105918Z","iopub.execute_input":"2026-05-11T00:16:12.106487Z","iopub.status.idle":"2026-05-11T00:16:12.114074Z","shell.execute_reply.started":"2026-05-11T00:16:12.106454Z","shell.execute_reply":"2026-05-11T00:16:12.112963Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['island'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:17:13.980810Z","iopub.execute_input":"2026-05-11T00:17:13.981903Z","iopub.status.idle":"2026-05-11T00:17:13.990903Z","shell.execute_reply.started":"2026-05-11T00:17:13.981862Z","shell.execute_reply":"2026-05-11T00:17:13.989739Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"np.unique(df['species'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:17:47.359899Z","iopub.execute_input":"2026-05-11T00:17:47.361139Z","iopub.status.idle":"2026-05-11T00:17:47.368960Z","shell.execute_reply.started":"2026-05-11T00:17:47.361101Z","shell.execute_reply":"2026-05-11T00:17:47.367481Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Dataset: Palmer Penguins\n\nLe dataset **Palmer Penguins** est un jeu de données “classique” pour l’apprentissage automatique, souvent présenté comme une alternative moderne au dataset des Iris (fleurs). Il contient des **mesures morphologiques** de manchots observés dans l’archipel Palmer (Antarctique), avec quelques variables catégorielles utiles pour introduire le prétraitement. \n\nL’objectif le plus courant est de **prédire l’espèce** (`species`) à partir de caractéristiques physiques (bec, nageoire, poids) et éventuellement de variables contextuelles (`island`, `sex`). On est donc sur une **classification multiclasse** (3 espèces). \n\n![Penguins](https://upload.wikimedia.org/wikipedia/commons/f/fb/Penguin_in_Antarctica_jumping_out_of_the_water_%28cropped%29.jpg)\n\n### Colonnes du dataset\n\n#### Variable cible\n\n* `species` : espèce du manchot (3 classes) : **Adelie**, **Chinstrap**, **Gentoo**.\n\n#### Variables explicatives numériques\n\n* `bill_length_mm` : longueur du bec (mm).  \n* `bill_depth_mm` : profondeur/épaisseur du bec (mm). \n* `flipper_length_mm` : longueur de la nageoire (mm). \n* `body_mass_g` : masse du manchot (g).\n\n#### Variables explicatives catégorielles\n\n* `island` : île d’observation (**Biscoe**, **Dream**, **Torgersen**).  \n* `sex` : sexe (`male` / `female`) (avec parfois des valeurs manquantes).\n\n```python\ndf = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/penguins.csv')\ndf.head()\n```\n","metadata":{"papermill":{"duration":0.012796,"end_time":"2026-02-22T17:25:17.84992","exception":false,"start_time":"2026-02-22T17:25:17.837124","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Visualisation exploratoire avec coloration par classe\n\nDans les sections précédentes, nous avons introduit :\n\n* histogramme\n* boxplot\n* violin plot\n* scatter plot\n* KDE\n\nNous allons maintenant les utiliser pour un objectif central en classification :\n**analyser la séparation potentielle entre les espèces** (variable cible `species`).\n\nDans un problème de classification, l’enjeu est d’identifier des variables capables de discriminer les classes.\nPour Palmer Penguins, nous cherchons à comprendre si des variables morphologiques permettent de distinguer :\n\n* *Adelie*\n* *Chinstrap*\n* *Gentoo*\n\nNous utilisons Seaborn et le paramètre `hue` pour colorer les observations selon l’espèce.\n\n```python\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nsns.set_style(\"whitegrid\")\n```\n\n\n### 1. Histogramme par espèce\n\n```python\nplt.figure(figsize=(6,4))\n\nsns.histplot(\n    data=df,\n    x=\"bill_length_mm\",\n    hue=\"species\",\n    bins=30,\n    kde=True,\n    element=\"step\"\n)\n\nplt.title(\"Distribution de la longueur du bec selon l'espèce\")\nplt.show()\n```\n\nObjectif : observer si la longueur du bec diffère selon l’espèce.\n\n\n### 2. Boxplot par espèce\n\n```python\nplt.figure(figsize=(6,4))\n\nsns.boxplot(\n    data=df,\n    x=\"species\",\n    y=\"flipper_length_mm\"\n)\n\nplt.title(\"Longueur des nageoires selon l'espèce\")\nplt.show()\n```\n\nObjectif : comparer médiane, dispersion et valeurs atypiques entre espèces.\n\n\n### 3. Violin plot par espèce\n\n```python\nplt.figure(figsize=(6,4))\n\nsns.violinplot(\n    data=df,\n    x=\"species\",\n    y=\"body_mass_g\",\n    inner=\"quartile\"\n)\n\nplt.title(\"Distribution complète du poids selon l'espèce\")\nplt.show()\n```\n\nLe violin plot permet d’observer la structure interne de la distribution (densité + quartiles).\n\n\n### 4. KDE plot par espèce\n\n```python\nplt.figure(figsize=(6,4))\n\nsns.kdeplot(\n    data=df,\n    x=\"bill_depth_mm\",\n    hue=\"species\",\n    fill=True,\n    common_norm=False,\n    alpha=0.4\n)\n\nplt.title(\"Densité de la profondeur du bec selon l'espèce\")\nplt.show()\n```\n\nObjectif : comparer directement les distributions estimées.\n\n\n### 5. Scatter plot avec coloration\n\n```python\nplt.figure(figsize=(6,4))\n\nsns.scatterplot(\n    data=df,\n    x=\"bill_length_mm\",\n    y=\"bill_depth_mm\",\n    hue=\"species\"\n)\n\nplt.title(\"Relation longueur vs profondeur du bec\")\nplt.show()\n```\n\nObjectif : visualiser la séparation potentielle des espèces dans l’espace bidimensionnel.\n\nC’est souvent ici que la séparabilité devient visuellement évidente.\n\n\n### 6. Pairplot : vue multidimensionnelle\n\nLe `pairplot` permet d’examiner toutes les relations deux à deux entre variables numériques avec coloration par espèce.\n\n```python\nsns.pairplot(\n    df,\n    vars=[\n        \"bill_length_mm\",\n        \"bill_depth_mm\",\n        \"flipper_length_mm\",\n        \"body_mass_g\"\n    ],\n    hue=\"species\",\n    diag_kind=\"kde\"\n)\n```\n\n```python\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nsns.set_style(\"whitegrid\")\n\nplt.figure(figsize=(6,4))\n\nsns.histplot(\n    data=df,\n    x=\"bill_length_mm\",\n    hue=\"species\",\n    bins=30,\n    kde=True,\n    element=\"step\"\n)\n\nplt.title(\"Distribution de la longueur du bec selon l'espèce\")\nplt.show()\n```\n\n```python\nplt.figure(figsize=(6,4))\n\nsns.boxplot(\n    data=df,\n    x=\"species\",\n    y=\"flipper_length_mm\"\n)\n\nplt.title(\"Longueur des nageoires selon l'espèce\")\nplt.show()\n```\n\n```python\nplt.figure(figsize=(6,4))\n\nsns.violinplot(\n    data=df,\n    x=\"species\",\n    y=\"body_mass_g\",\n    inner=\"quartile\"\n)\n\nplt.title(\"Distribution complète du poids selon l'espèce\")\nplt.show()\n```\n\n```python\nplt.figure(figsize=(6,4))\n\nsns.scatterplot(\n    data=df,\n    x=\"bill_length_mm\",\n    y=\"bill_depth_mm\",\n    hue=\"species\"\n)\n\nplt.title(\"Relation longueur vs profondeur du bec\")\nplt.show()\n```\n\n```python\nsns.pairplot(\n    df,\n    vars=[\n        \"bill_length_mm\",\n        \"bill_depth_mm\",\n        \"flipper_length_mm\",\n        \"body_mass_g\"\n    ],\n    hue=\"species\",\n    diag_kind=\"kde\"\n)\n```\n","metadata":{"papermill":{"duration":0.01272,"end_time":"2026-02-22T17:25:17.948339","exception":false,"start_time":"2026-02-22T17:25:17.935619","status":"completed"},"tags":[]}},{"cell_type":"code","source":"df.columns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:19:55.976837Z","iopub.execute_input":"2026-05-11T00:19:55.978414Z","iopub.status.idle":"2026-05-11T00:19:55.985909Z","shell.execute_reply.started":"2026-05-11T00:19:55.978375Z","shell.execute_reply":"2026-05-11T00:19:55.984854Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sns.kdeplot(df, x='body_mass_g', hue='island')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:29:48.941337Z","iopub.execute_input":"2026-05-11T00:29:48.941845Z","iopub.status.idle":"2026-05-11T00:29:49.184410Z","shell.execute_reply.started":"2026-05-11T00:29:48.941813Z","shell.execute_reply":"2026-05-11T00:29:49.183373Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Exploratory Data Analysis : EDA","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df[df['island']=='Biscoe']['species'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:31:45.477564Z","iopub.execute_input":"2026-05-11T00:31:45.478211Z","iopub.status.idle":"2026-05-11T00:31:45.490805Z","shell.execute_reply.started":"2026-05-11T00:31:45.478173Z","shell.execute_reply":"2026-05-11T00:31:45.489260Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df[df['species']=='Gentoo']['island'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:32:42.401680Z","iopub.execute_input":"2026-05-11T00:32:42.402199Z","iopub.status.idle":"2026-05-11T00:32:42.412814Z","shell.execute_reply.started":"2026-05-11T00:32:42.402165Z","shell.execute_reply":"2026-05-11T00:32:42.411750Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sns.boxplot(df, y='flipper_length_mm', hue='species')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:25:03.843972Z","iopub.execute_input":"2026-05-11T00:25:03.844855Z","iopub.status.idle":"2026-05-11T00:25:04.303578Z","shell.execute_reply.started":"2026-05-11T00:25:03.844818Z","shell.execute_reply":"2026-05-11T00:25:04.302588Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sns.scatterplot(df, x='bill_depth_mm', y='body_mass_g', hue='species')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:27:14.935550Z","iopub.execute_input":"2026-05-11T00:27:14.936939Z","iopub.status.idle":"2026-05-11T00:27:15.160726Z","shell.execute_reply.started":"2026-05-11T00:27:14.936900Z","shell.execute_reply":"2026-05-11T00:27:15.159404Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sns.pairplot(df, hue='species')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:27:56.073639Z","iopub.execute_input":"2026-05-11T00:27:56.074009Z","iopub.status.idle":"2026-05-11T00:27:59.366159Z","shell.execute_reply.started":"2026-05-11T00:27:56.073980Z","shell.execute_reply":"2026-05-11T00:27:59.364872Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Scatter plot 3D avec Plotly\n\nNous utilisons trois variables morphologiques :\n\n* `bill_length_mm`\n* `bill_depth_mm`\n* `flipper_length_mm`\n\nLa couleur représente l’espèce.\n\n```python\nimport plotly.express as px\n\nfig = px.scatter_3d(\n    df,\n    x=\"bill_length_mm\",\n    y=\"bill_depth_mm\",\n    z=\"flipper_length_mm\",\n    color=\"species\",\n    opacity=0.8\n)\n\nfig.update_layout(\n    width=800,\n    height=600,\n    title=\"Séparation des espèces (visualisation 3D)\"\n)\n\nfig.show()\n```\n\nDans ce graphique :\n\n* chaque point représente un manchot\n* les axes correspondent aux trois variables morphologiques\n* la couleur indique l’espèce\n\nL’interactivité permet :\n\n* rotation libre du graphique\n* zoom\n* inspection individuelle des observations (hover)\n\n\n### Personnalisation avec `update_traces`\n\nOn peut affiner le rendu :\n\n```python\nfig.update_traces(\n    marker=dict(size=5)\n)\n```\n\n`update_traces` permet de modifier les propriétés graphiques après création :\n\n* taille des points\n* opacité\n* style des marqueurs\n* contours\n\n```python\nfig = px.scatter_3d(\n    df,\n    x=\"bill_length_mm\",\n    y=\"bill_depth_mm\",\n    z=\"flipper_length_mm\",\n    color=\"species\",\n    opacity=0.8\n)\n\nfig.update_layout(\n    width=800,\n    height=600,\n    title=\"Séparation des espèces (visualisation 3D)\"\n)\n\nfig.update_traces(\n    marker=dict(size=5)\n)\n\nfig.show()\n```\n","metadata":{"papermill":{"duration":0.021702,"end_time":"2026-02-22T17:25:22.179901","exception":false,"start_time":"2026-02-22T17:25:22.158199","status":"completed"},"tags":[]}},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/penguins.csv')\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:15:58.049592Z","iopub.execute_input":"2026-05-11T01:15:58.049962Z","iopub.status.idle":"2026-05-11T01:15:58.069273Z","shell.execute_reply.started":"2026-05-11T01:15:58.049933Z","shell.execute_reply":"2026-05-11T01:15:58.068064Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['sex'].map({'male':0, 'female':1})","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:16:09.905921Z","iopub.execute_input":"2026-05-11T01:16:09.906657Z","iopub.status.idle":"2026-05-11T01:16:09.918277Z","shell.execute_reply.started":"2026-05-11T01:16:09.906619Z","shell.execute_reply":"2026-05-11T01:16:09.917182Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['sex'] = df['sex'].map({'male':0, 'female':1})","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:56:13.427815Z","iopub.execute_input":"2026-05-11T00:56:13.428870Z","iopub.status.idle":"2026-05-11T00:56:13.436336Z","shell.execute_reply.started":"2026-05-11T00:56:13.428818Z","shell.execute_reply":"2026-05-11T00:56:13.434974Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['species'] = df['species'].map({'Adelie':0, 'Chinstrap':1, 'Gentoo':2})","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:57:43.664254Z","iopub.execute_input":"2026-05-11T00:57:43.665785Z","iopub.status.idle":"2026-05-11T00:57:43.673705Z","shell.execute_reply.started":"2026-05-11T00:57:43.665719Z","shell.execute_reply":"2026-05-11T00:57:43.672320Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.get_dummies(df, columns=['island'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:56:15.539025Z","iopub.execute_input":"2026-05-11T00:56:15.539894Z","iopub.status.idle":"2026-05-11T00:56:15.550315Z","shell.execute_reply.started":"2026-05-11T00:56:15.539853Z","shell.execute_reply":"2026-05-11T00:56:15.548898Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T00:57:48.445399Z","iopub.execute_input":"2026-05-11T00:57:48.445786Z","iopub.status.idle":"2026-05-11T00:57:48.463150Z","shell.execute_reply.started":"2026-05-11T00:57:48.445755Z","shell.execute_reply":"2026-05-11T00:57:48.461559Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/penguins.csv')\n\n# Traitement des données\n\n# Traitement des valeurs manquantes\ndf['sex'] = df['sex'].fillna('male')\ndf = df.dropna()\n\n# Traitement des valeurs non numériques\ndf['sex'] = df['sex'].map({'male':0, 'female':1})\ndf['species'] = df['species'].map({'Adelie':0, 'Chinstrap':1, 'Gentoo':2})\ndf = pd.get_dummies(df, columns=['island'])\n\nX = df.drop(columns=['species'])\ny = df['species']\n\nX_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=42)\n\nmodel = DecisionTreeClassifier()\nmodel.fit(X_train,y_train)\ny_hat = model.predict(X_test)\n\nprint(f\"Accuracy : {accuracy_score(y_test,y_hat):.2f}\")\n\nprint(confusion_matrix(y_test, y_hat))\n\nprint(classification_report(y_test, y_hat))\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:18:39.183562Z","iopub.execute_input":"2026-05-11T01:18:39.184417Z","iopub.status.idle":"2026-05-11T01:18:39.224809Z","shell.execute_reply.started":"2026-05-11T01:18:39.184382Z","shell.execute_reply":"2026-05-11T01:18:39.223422Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/penguins.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:05:29.244323Z","iopub.execute_input":"2026-05-11T01:05:29.244760Z","iopub.status.idle":"2026-05-11T01:05:29.255335Z","shell.execute_reply.started":"2026-05-11T01:05:29.244723Z","shell.execute_reply":"2026-05-11T01:05:29.253704Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.isna().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:05:29.903836Z","iopub.execute_input":"2026-05-11T01:05:29.904349Z","iopub.status.idle":"2026-05-11T01:05:29.912983Z","shell.execute_reply.started":"2026-05-11T01:05:29.904317Z","shell.execute_reply":"2026-05-11T01:05:29.911907Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['sex'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:05:52.629887Z","iopub.execute_input":"2026-05-11T01:05:52.630240Z","iopub.status.idle":"2026-05-11T01:05:52.643099Z","shell.execute_reply.started":"2026-05-11T01:05:52.630210Z","shell.execute_reply":"2026-05-11T01:05:52.641735Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['sex'] = df['sex'].fillna('male')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:07:12.157798Z","iopub.execute_input":"2026-05-11T01:07:12.158398Z","iopub.status.idle":"2026-05-11T01:07:12.165591Z","shell.execute_reply.started":"2026-05-11T01:07:12.158352Z","shell.execute_reply":"2026-05-11T01:07:12.164137Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.isna().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:07:32.203775Z","iopub.execute_input":"2026-05-11T01:07:32.204584Z","iopub.status.idle":"2026-05-11T01:07:32.213975Z","shell.execute_reply.started":"2026-05-11T01:07:32.204536Z","shell.execute_reply":"2026-05-11T01:07:32.212312Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['body_mass_g'].fillna(df['body_mass_g'].mean())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:09:41.971177Z","iopub.execute_input":"2026-05-11T01:09:41.971671Z","iopub.status.idle":"2026-05-11T01:09:41.982756Z","shell.execute_reply.started":"2026-05-11T01:09:41.971637Z","shell.execute_reply":"2026-05-11T01:09:41.981491Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Traitement des valeurs manquantes\n\nDans un jeu de données réel, certaines observations peuvent être **incomplètes**.  \nLe dataset **Penguins** contient volontairement des **valeurs manquantes**, ce qui en fait un bon support pédagogique pour introduire les stratégies de nettoyage des données.\n\n\n### Identifier les valeurs manquantes\n\nLa première étape consiste à **repérer les colonnes concernées** et à quantifier le problème.\n\n```python\ndf.isna().sum()\n````\n\nCette commande renvoie, pour chaque colonne, le **nombre de valeurs manquantes**.\n\nOn peut aussi vérifier s’il existe des lignes incomplètes :\n\n```python\ndf.isna().any(axis=1).sum()\n```\n\n\n### Colonnes concernées dans Penguins\n\nDans le dataset Penguins, les valeurs manquantes apparaissent typiquement dans :\n\n* `bill_length_mm`\n* `bill_depth_mm`\n* `flipper_length_mm`\n* `body_mass_g`\n* `sex`\n\nCes valeurs manquantes proviennent de **mesures absentes ou non exploitables** lors des observations sur le terrain.\n\n\n### Stratégie 1 : suppression des lignes (`dropna`)\n\nLa solution la plus simple consiste à **supprimer les lignes incomplètes**.\n\n```python\ndf_drop = df.dropna()\n```\n\n#### Avantages\n\n* Simple à comprendre\n* Pas d’hypothèse sur les données\n\n#### Inconvénients\n\n* Perte d’information\n* Peut introduire un biais si les valeurs manquantes ne sont pas aléatoires\n\nCette méthode est acceptable lorsque :\n\n* peu de lignes sont concernées\n* le dataset reste suffisamment grand après suppression\n\n\n\n### Stratégie 2 : imputation simple (`fillna`)\n\nUne autre approche consiste à **remplacer les valeurs manquantes** par une valeur plausible.\n\n#### Variables numériques\n\nImputation par la moyenne ou la médiane :\n\n```python\ndf[\"body_mass_g\"] = df[\"body_mass_g\"].fillna(df[\"body_mass_g\"].median())\n```\n\n#### Variables catégorielles\n\nImputation par la modalité la plus fréquente :\n\n```python\ndf[\"sex\"] = df[\"sex\"].fillna(df[\"sex\"].mode()[0])\n```\n\n#### Avantages\n\n* Rapide\n* Facile à expliquer\n\n#### Inconvénients\n\n* Réduit artificiellement la variance\n* Ne tient pas compte des relations entre variables\n\n\n\n### Stratégie 3 : imputation par les voisins (`KNNImputer`)\n\nUne méthode plus avancée consiste à estimer les valeurs manquantes à partir des **observations similaires**.\n\nPrincipe :\n\n> une valeur manquante est remplacée par une moyenne pondérée des valeurs observées chez les *k* individus les plus proches.\n\n```python\nfrom sklearn.impute import KNNImputer\n\nimputer = KNNImputer(n_neighbors=5)\nX_imputed = imputer.fit_transform(X)\n```\n\n#### Avantages\n\n* Exploite les relations entre variables\n* Souvent plus réaliste qu’une moyenne globale\n\n#### Inconvénients\n\n* Plus coûteux en calcul\n* Sensible à l’échelle des variables (normalisation recommandée)\n* Moins lisible pédagogiquement au premier abord\n\n","metadata":{"papermill":{"duration":0.021216,"end_time":"2026-02-22T17:25:25.936727","exception":false,"start_time":"2026-02-22T17:25:25.915511","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"> Quelle stratégie vous semble la plus appropriée pour le dataset penguins ?\n>\n> La tester\n\n```python\ndf.isna().sum()\n```\n\n```python\ndf = df.dropna()\n```\n\n```python\ndf.isna().sum()\n```\n","metadata":{"papermill":{"duration":0.020455,"end_time":"2026-02-22T17:25:25.978012","exception":false,"start_time":"2026-02-22T17:25:25.957557","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Conversion des variables non numériques\n\nLes algorithmes de machine learning classiques travaillent principalement avec des **variables numériques**.  \nLe dataset **Penguins** contient des variables **catégorielles** (`species`, `island`, `sex`) qui doivent être converties avant l’apprentissage.\n\n\n\n### Identifier les variables non numériques\n\n```python\ndf.dtypes\n````\n\nOn observe généralement :\n\n* variables numériques (`float`, `int`)\n* variables catégorielles (`object`)\n\n\n\n### Conversion simple avec `map`\n\nLorsque la variable prend **un petit nombre de modalités bien identifiées**, on peut utiliser un dictionnaire.\n\n#### Exemple : variable `sex`\n\n```python\ndf[\"sex_num\"] = df[\"sex\"].map({\"male\": 1, \"female\": 0})\n```\n\nCette méthode est adaptée lorsque :\n\n* l’ordre n’a pas d’importance\n* il n’y a que deux catégories\n\n\n\n### Conversion en catégories (`category`)\n\nPandas permet de déclarer explicitement une variable comme catégorielle.\n\n```python\ndf[\"island\"] = df[\"island\"].astype(\"category\")\n```\n\nCela ne change pas encore la représentation numérique, mais :\n\n* clarifie le type de donnée\n* prépare un encodage ultérieur (one-hot, ordinal…)\n\n\n\n### Encodage binaire (One-Hot Encoding)\n\nL’encodage binaire consiste à créer **une colonne par modalité**, prenant les valeurs 0 ou 1.\n\n#### Exemple : variable `island`\n\n```python\ndf_encoded = pd.get_dummies(df, columns=[\"island\"], drop_first=False)\n```\n\nSi `island` a 3 modalités, on obtient 3 colonnes :\n\n* `island_Biscoe`\n* `island_Dream`\n* `island_Torgersen`\n\n\n\n### Pourquoi l’encodage binaire est utile pour les arbres de décision\n\nLes **arbres de décision**, **forêts aléatoires** et **gradient boosting** effectuent des **tests simples** de type :\n\n> *feature ≤ seuil*\n\nAvec un encodage binaire :\n\n* le test devient clair et interprétable\n* exemple : `island_Biscoe == 1`\n\nAvantages pour les arbres et modèles dérivés :\n* aucune hypothèse d’ordre artificiel entre catégories\n* séparation nette des populations\n* interprétation intuitive des règles de décision\n* compatibilité directe avec les critères de split (Gini, entropie)\n\nÀ l’inverse, un encodage ordinal naïf (ex : Biscoe=0, Dream=1, Torgersen=2) impose un **ordre artificiel** qui n’a souvent **aucun sens**.\n\n\n\n### Cas particulier : variables binaires\n\nLorsque la variable est déjà binaire (`yes/no`, `male/female`), un simple `map` suffit :\n\n```python\ndf[\"sex\"] = df[\"sex\"].map({\"male\": 1, \"female\": 0})\n```\n\nCela évite de créer deux colonnes inutiles.\n","metadata":{"papermill":{"duration":0.020799,"end_time":"2026-02-22T17:25:26.217578","exception":false,"start_time":"2026-02-22T17:25:26.196779","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"> Quelle stratégies vous semblent les plus appropriées pour le dataset penguins ?\n> (En supposant que `species` est la cible)\n>\n> Mettre en oeuvre\n>","metadata":{"papermill":{"duration":0.02119,"end_time":"2026-02-22T17:25:26.260414","exception":false,"start_time":"2026-02-22T17:25:26.239224","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Arbres de décision et classification multiclasse\n\nLes méthodes basées sur les **arbres de décision** (arbres simples, forêts aléatoires, gradient boosting) gèrent **nativement** les problèmes de **classification multiclasse**.  \nIl n’est donc pas nécessaire de transformer le problème en plusieurs classifications binaires.\n\n\n### Principe général\n\nUn arbre de décision construit une suite de **règles conditionnelles** de la forme :\n\n> *si une condition est vraie, aller à gauche ; sinon, aller à droite*\n\nÀ chaque nœud, l’algorithme cherche la coupure qui **améliore le plus la pureté** des classes (par exemple via l’indice de Gini ou l’entropie), **quel que soit le nombre de classes**.\n\n\n\n### Multiclasse dans un nœud\n\nDans un problème multiclasse :\n* chaque nœud contient une **distribution de classes**\n* le critère de split (Gini ou entropie) est calculé sur **toutes les classes simultanément**\n\nExemple :\n> un nœud peut contenir 40 % Adelie, 35 % Gentoo, 25 % Chinstrap\n\nLe split choisi est celui qui rend les sous-nœuds **plus homogènes**, même avec plus de deux classes.\n\n\n\n### Décision dans les feuilles\n\nDans une feuille :\n* la classe prédite est la **classe majoritaire**\n* ou, plus généralement, la classe de **probabilité maximale**\n\nAinsi, une feuille peut prédire directement :\n* Adelie\n* Gentoo\n* ou Chinstrap\n\nsans transformation intermédiaire.\n\n\n\n### Cas des méthodes dérivées\n\nLes méthodes suivantes héritent de cette capacité multiclasse :\n\n* **DecisionTreeClassifier**\n* **RandomForestClassifier**\n* **GradientBoostingClassifier**\n* **XGBoost / LightGBM** (mode multiclass)\n\nElles utilisent :\n* plusieurs arbres\n* des votes (forêt aléatoire)\n* ou des corrections successives (boosting)\n\nmais le principe multiclasse reste identique.\n\n\n### Application au dataset Penguins\n\nLe dataset **Penguins** comporte **3 espèces**.  \nUn arbre ou une forêt peut apprendre directement des règles du type :\n\n> *si flipper_length_mm > 210 → Gentoo*  \n> *sinon si bill_depth_mm < 18 → Adelie*  \n> *sinon → Chinstrap*\n\nsans adaptation spécifique du modèle.\n\n\n```","metadata":{"papermill":{"duration":0.022792,"end_time":"2026-02-22T17:25:26.43289","exception":false,"start_time":"2026-02-22T17:25:26.410098","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"> #### Exercice 1 – Arbre de décision\n>\n> 1. Charger le dataset Penguins.\n> 2. Traiter les valeurs manquantes.\n> 3. Séparer variables explicatives et cible (`species`).\n> 4. Encoder les variables catégorielles.\n> 5. Entraîner un arbre de décision.\n> 6. Évaluer la performance sur un jeu de test.\n> 7. Afficher l’arbre et interpréter quelques règles.\n>\n> #### Exercice 2 – Forêt aléatoire\n>\n> 1. Entraîner une forêt aléatoire sur les mêmes données.\n> 2. Comparer la performance avec celle de l’arbre de décision.\n>\n","metadata":{"papermill":{"duration":0.021453,"end_time":"2026-02-22T17:25:26.475119","exception":false,"start_time":"2026-02-22T17:25:26.453666","status":"completed"},"tags":[]}},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/titanic.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:23:48.076003Z","iopub.execute_input":"2026-05-11T01:23:48.076635Z","iopub.status.idle":"2026-05-11T01:23:48.100242Z","shell.execute_reply.started":"2026-05-11T01:23:48.076598Z","shell.execute_reply":"2026-05-11T01:23:48.099089Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:23:54.078777Z","iopub.execute_input":"2026-05-11T01:23:54.079098Z","iopub.status.idle":"2026-05-11T01:23:54.096398Z","shell.execute_reply.started":"2026-05-11T01:23:54.079072Z","shell.execute_reply":"2026-05-11T01:23:54.095266Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Titanic Dataset\n\nLe dataset **Titanic** regroupe des informations sur les passagers du paquebot *Titanic* et vise à prédire leur **survie** lors du naufrage.\n\n\n### Variable cible\n\n* **`Survived`**\n\n  * `0` : le passager n’a pas survécu\n  * `1` : le passager a survécu\n\n\n### Variables descriptives\n\n#### Données socio-démographiques\n\n* **`Sex`** : sexe du passager\n* **`Age`** : âge (valeurs manquantes possibles)\n\n#### Conditions de voyage\n\n* **`Pclass`** : classe du billet (1re, 2e ou 3e classe)\n* **`Fare`** : prix du billet\n* **`Cabin`** : cabine ('C85' dénote la cabine 85 du pont C)\n* **`Embarked`** : port d’embarquement\n\n  * `C` : Cherbourg\n  * `Q` : Queenstown\n  * `S` : Southampton\n\n#### Situation familiale à bord\n\n* **`SibSp`** : nombre de frères/sœurs et/ou conjoint à bord\n* **`Parch`** : nombre de parents et/ou enfants à bord\n","metadata":{"papermill":{"duration":0.022895,"end_time":"2026-02-22T17:25:26.520736","exception":false,"start_time":"2026-02-22T17:25:26.497841","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"### 💡 Syntaxe à reprendre\n\n_Repère syntaxique pour aborder l'exercice ci-dessous._\n\n```python\ndf.head()\n```\n","metadata":{}},{"cell_type":"markdown","source":"> #### Exercice\n>\n> Prédire la survie pour le Titanic","metadata":{"papermill":{"duration":0.021573,"end_time":"2026-02-22T17:25:26.564432","exception":false,"start_time":"2026-02-22T17:25:26.542859","status":"completed"},"tags":[]}},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/titanic.csv')\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:34:36.686086Z","iopub.execute_input":"2026-05-11T01:34:36.686986Z","iopub.status.idle":"2026-05-11T01:34:36.712667Z","shell.execute_reply.started":"2026-05-11T01:34:36.686948Z","shell.execute_reply":"2026-05-11T01:34:36.711387Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.isna().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:34:07.285614Z","iopub.execute_input":"2026-05-11T01:34:07.286022Z","iopub.status.idle":"2026-05-11T01:34:07.296220Z","shell.execute_reply.started":"2026-05-11T01:34:07.285990Z","shell.execute_reply":"2026-05-11T01:34:07.294794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['Embarked'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:00:34.856277Z","iopub.execute_input":"2026-05-11T02:00:34.856687Z","iopub.status.idle":"2026-05-11T02:00:34.865582Z","shell.execute_reply.started":"2026-05-11T02:00:34.856656Z","shell.execute_reply":"2026-05-11T02:00:34.864371Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.columns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T01:58:02.923882Z","iopub.execute_input":"2026-05-11T01:58:02.924197Z","iopub.status.idle":"2026-05-11T01:58:02.930594Z","shell.execute_reply.started":"2026-05-11T01:58:02.924171Z","shell.execute_reply":"2026-05-11T01:58:02.929820Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/titanic.csv')\n\n# Traitement des données\n\n# Transformation de données\ndf['Family'] = df['SibSp'] + df['Parch']\ndf['Alone'] = (df['Family']==0)\n\n# Suppression de colonnes peu informatives\ndf = df.drop(columns=['PassengerId', 'Name', 'Ticket', 'Cabin', 'SibSp', 'Parch'])\n\n# Traitement des valeurs manquantes\ndf['Age'] = df['Age'].fillna(df['Age'].median())\n\n# Traitement des valeurs non numériques\ndf['Sex'] = df['Sex'].map({'male':0, 'female':1})\ndf = pd.get_dummies(df, columns=['Embarked'])\n\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:06:41.455703Z","iopub.execute_input":"2026-05-11T02:06:41.456172Z","iopub.status.idle":"2026-05-11T02:06:41.486336Z","shell.execute_reply.started":"2026-05-11T02:06:41.456140Z","shell.execute_reply":"2026-05-11T02:06:41.485582Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.isna().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:03:01.289174Z","iopub.execute_input":"2026-05-11T02:03:01.289613Z","iopub.status.idle":"2026-05-11T02:03:01.298024Z","shell.execute_reply.started":"2026-05-11T02:03:01.289581Z","shell.execute_reply":"2026-05-11T02:03:01.296949Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/titanic.csv')\n\n# Traitement des données\n\n# Transformation de données\ndf['Family'] = df['SibSp'] + df['Parch']\ndf['Alone'] = (df['Family']==0)\n\n# Suppression de colonnes peu informatives\ndf = df.drop(columns=['PassengerId', 'Name', 'Ticket', 'Cabin', 'SibSp', 'Parch'])\n\n# Traitement des valeurs manquantes\ndf['Age'] = df['Age'].fillna(df['Age'].median())\n\n# Traitement des valeurs non numériques\ndf['Sex'] = df['Sex'].map({'male':0, 'female':1})\ndf = pd.get_dummies(df, columns=['Embarked'])\n\n# Prediction\n\nX = df.drop(columns=['Survived'])\ny = df['Survived']\n\nX_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=42)\n\nmodel = DecisionTreeClassifier()\nmodel.fit(X_train,y_train)\ny_hat = model.predict(X_test)\n\nprint(f\"Accuracy : {accuracy_score(y_test,y_hat):.2f}\")\n\nprint(confusion_matrix(y_test, y_hat))\n\nprint(classification_report(y_test, y_hat))\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:07:10.592602Z","iopub.execute_input":"2026-05-11T02:07:10.592973Z","iopub.status.idle":"2026-05-11T02:07:10.633788Z","shell.execute_reply.started":"2026-05-11T02:07:10.592943Z","shell.execute_reply":"2026-05-11T02:07:10.632899Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/titanic.csv')\n\n# Traitement des données\n\n# Transformation de données\ndf['Family'] = df['SibSp'] + df['Parch']\ndf['Alone'] = (df['Family']==0)\n\n# Suppression de colonnes peu informatives\ndf = df.drop(columns=['PassengerId', 'Name', 'Ticket', 'Cabin', 'SibSp', 'Parch'])\n\n# Traitement des valeurs manquantes\ndf['Age'] = df['Age'].fillna(df['Age'].median())\n\n# Traitement des valeurs non numériques\ndf['Sex'] = df['Sex'].map({'male':0, 'female':1})\ndf = pd.get_dummies(df, columns=['Embarked'])\n\n# Prediction\n\nX = df.drop(columns=['Survived'])\ny = df['Survived']\n\nmodel = DecisionTreeClassifier()\nscores = cross_val_score(model, X, y, cv=10)\nprint(scores.mean())\n\nmodel = RandomForestClassifier()\nscores = cross_val_score(model, X, y, cv=10)\nprint(scores.mean())\n\nmodel = XGBClassifier()\nscores = cross_val_score(model, X, y, cv=10)\nprint(scores.mean())\n\nmodel = LGBMClassifier(verbose=-1)\nscores = cross_val_score(model, X, y, cv=10)\nprint(scores.mean())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:19:21.582394Z","iopub.execute_input":"2026-05-11T02:19:21.583555Z","iopub.status.idle":"2026-05-11T02:19:25.287824Z","shell.execute_reply.started":"2026-05-11T02:19:21.583467Z","shell.execute_reply":"2026-05-11T02:19:25.286807Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/mushrooms.csv')\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:19:54.975020Z","iopub.execute_input":"2026-05-11T02:19:54.975478Z","iopub.status.idle":"2026-05-11T02:19:55.038639Z","shell.execute_reply.started":"2026-05-11T02:19:54.975424Z","shell.execute_reply":"2026-05-11T02:19:55.037576Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"np.unique(df['class'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:20:30.935764Z","iopub.execute_input":"2026-05-11T02:20:30.936098Z","iopub.status.idle":"2026-05-11T02:20:30.947333Z","shell.execute_reply.started":"2026-05-11T02:20:30.936071Z","shell.execute_reply":"2026-05-11T02:20:30.946482Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.columns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:21:46.705238Z","iopub.execute_input":"2026-05-11T02:21:46.706356Z","iopub.status.idle":"2026-05-11T02:21:46.712734Z","shell.execute_reply.started":"2026-05-11T02:21:46.706307Z","shell.execute_reply":"2026-05-11T02:21:46.711907Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for col in df.columns:\n    print(col,' : ',np.unique(df[col]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:24:08.695395Z","iopub.execute_input":"2026-05-11T02:24:08.696160Z","iopub.status.idle":"2026-05-11T02:24:08.779327Z","shell.execute_reply.started":"2026-05-11T02:24:08.696124Z","shell.execute_reply":"2026-05-11T02:24:08.778256Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Le dataset `mushrooms`\n\n **Variables (colonnes) et signification (exemples) :**\n  * Chapeau : `cap-shape` (forme), `cap-surface` (texture), `cap-color` (couleur)\n  * `bruises` (Présence de bleuissement), `odor` (Odeur)\n  * Lamelles : `gill-attachment` (attache), `gill-spacing` (espacement), `gill-size` (taille), `gill-color` (couleur)\n  * Pied : `stalk-shape` (forme), `stalk-root` (base)\n  * Textures/couleurs du pied au-dessus et sous l’anneau : `stalk-surface-*`, `stalk-color-*`\n  * Voile : `veil-type`, `veil-color`\n  * Anneau : `ring-number` (nombre), `ring-type` (type)\n  * `spore-print-color` (couleur de l’empreinte sporale), `population` (densité), `habitat` (habitat)\n\n* **Cible :**\n  * `class` – Comestible (`e`) ou toxique (`p`) (les cas “unknown/not recommended” sont agrégés au toxique dans la description). \n\n","metadata":{"papermill":{"duration":0.021344,"end_time":"2026-02-22T17:25:26.854689","exception":false,"start_time":"2026-02-22T17:25:26.833345","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"> Quand le nombre de colonnes à afficher est important, certaines ne sont pas affichées avec `df.head()`\n> Pour afficher toutes les colonnes d'un dataset :\n>\n>```python\npd.set_option(\"display.max_columns\", None)\n```\n\n```python\ndf = pd.read_csv(\"/kaggle/input/datasets/pyim59/classic-datasets/mushrooms.csv\")\ndf.head()\n```\n\n```python\npd.set_option(\"display.max_columns\", None)\ndf.head()\n```\n","metadata":{"papermill":{"duration":0.022007,"end_time":"2026-02-22T17:25:26.898537","exception":false,"start_time":"2026-02-22T17:25:26.87653","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Nombre de valeurs distinctes dans une colonne\n\nAvant d’encoder des variables catégorielles, il est important de **comprendre combien de valeurs différentes** chaque colonne peut prendre.  \nCela permet d’anticiper :\n* la complexité de l’encodage (one-hot)\n* le nombre de colonnes créées\n* la pertinence de certaines variables\n\n### Méthode 1 : `numpy.unique`\n\nPour une colonne donnée, `np.unique` permet d’obtenir :\n* les valeurs distinctes\n* éventuellement leur fréquence\n\n```python\nimport numpy as np\n\nnp.unique(df[\"odor\"])\n````\n\nAvec comptage :\n\n```python\nvalues, counts = np.unique(df[\"odor\"], return_counts=True)\n```\n\n\n### Méthode 2 : `pandas.unique`\n\n```python\ndf[\"odor\"].unique()\n```\n\nCette méthode est plus simple lorsque seul le **nombre de modalités** nous intéresse.\n\n\n\n### Méthode 3 : `value_counts`\n\n```python\ndf[\"odor\"].value_counts()\n```\n\nElle est utile pour analyser la **répartition** des catégories.\n\n\n\n### Nombre de valeurs distinctes (`nunique`)\n\n```python\ndf[\"odor\"].nunique()\n```\n\nRenvoie directement le nombre de modalités.\n\n\n\n### Analyse globale du dataset Mushrooms\n\n","metadata":{"papermill":{"duration":0.031759,"end_time":"2026-02-22T17:25:27.110788","exception":false,"start_time":"2026-02-22T17:25:27.079029","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"> #### Exercice\n>\n> Analyser les colonnes du dataset de champignons\n> ","metadata":{"papermill":{"duration":0.026555,"end_time":"2026-02-22T17:25:27.181449","exception":false,"start_time":"2026-02-22T17:25:27.154894","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"> #### Exercice\n> **Feriez-vous confiance à un modèle de machine learning pour décider si un champignon est comestible ?**\n> ","metadata":{"papermill":{"duration":0.022609,"end_time":"2026-02-22T17:25:27.405421","exception":false,"start_time":"2026-02-22T17:25:27.382812","status":"completed"},"tags":[]}},{"cell_type":"code","source":"df.columns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:30:58.204654Z","iopub.execute_input":"2026-05-11T02:30:58.204996Z","iopub.status.idle":"2026-05-11T02:30:58.212591Z","shell.execute_reply.started":"2026-05-11T02:30:58.204970Z","shell.execute_reply":"2026-05-11T02:30:58.211292Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/mushrooms.csv')\n\n# Traitement des données\n\n# Transformation de données\n\n\n# Suppression de colonnes peu informatives\ndf = df.drop(columns=['veil-type'])\n\n# Traitement des valeurs non numériques\ndf['class'] = df['class'].map({'p':0, 'e':1})\ndf = pd.get_dummies(df, columns=['cap-shape', 'cap-surface', 'cap-color', 'bruises', 'odor',\n       'gill-attachment', 'gill-spacing', 'gill-size', 'gill-color',\n       'stalk-shape', 'stalk-root', 'stalk-surface-above-ring',\n       'stalk-surface-below-ring', 'stalk-color-above-ring',\n       'stalk-color-below-ring', 'veil-color', 'ring-number',\n       'ring-type', 'spore-print-color', 'population', 'habitat'])\n\n# Prediction\n\nX = df.drop(columns=['class'])\ny = df['class']\n\nX_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2)\n\nmodel = DecisionTreeClassifier()\nmodel.fit(X_train,y_train)\ny_hat = model.predict(X_test)\n\nprint(f\"Accuracy : {accuracy_score(y_test,y_hat):.2f}\")\n\nprint(confusion_matrix(y_test, y_hat))\n\nprint(classification_report(y_test, y_hat))\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:33:05.475151Z","iopub.execute_input":"2026-05-11T02:33:05.475519Z","iopub.status.idle":"2026-05-11T02:33:05.581015Z","shell.execute_reply.started":"2026-05-11T02:33:05.475473Z","shell.execute_reply":"2026-05-11T02:33:05.579612Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/mushrooms.csv')\n\n# Traitement des données\n\n# Transformation de données\n\n\n# Suppression de colonnes peu informatives\ndf = df.drop(columns=['veil-type'])\n\n# Traitement des valeurs non numériques\ndf['class'] = df['class'].map({'p':0, 'e':1})\ndf = pd.get_dummies(df, columns=['cap-shape', 'cap-surface', 'cap-color', 'bruises', 'odor',\n       'gill-attachment', 'gill-spacing', 'gill-size', 'gill-color',\n       'stalk-shape', 'stalk-root', 'stalk-surface-above-ring',\n       'stalk-surface-below-ring', 'stalk-color-above-ring',\n       'stalk-color-below-ring', 'veil-color', 'ring-number',\n       'ring-type', 'spore-print-color', 'population', 'habitat'])\n\n# Prediction\n\nX = df.drop(columns=['class'])\ny = df['class']\n\nmodel = XGBClassifier()\nscores = cross_val_score(model, X, y, cv=30)\nprint(scores.mean())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:34:03.854328Z","iopub.execute_input":"2026-05-11T02:34:03.854806Z","iopub.status.idle":"2026-05-11T02:34:10.892102Z","shell.execute_reply.started":"2026-05-11T02:34:03.854774Z","shell.execute_reply":"2026-05-11T02:34:10.891520Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n\ndf = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/mushrooms.csv')\n\n# Traitement des données\n\n# Transformation de données\n\n\n# Suppression de colonnes peu informatives\ndf = df.drop(columns=['veil-type'])\n\n# Traitement des valeurs non numériques\ndf['class'] = df['class'].map({'p':0, 'e':1})\n\n# Prediction\n\nX = df.drop(columns=['class'])\ny = df['class']\n\nX_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2)\n\nmodel = DecisionTreeClassifier()\nmodel.fit(X_train,y_train)\ny_hat = model.predict(X_test)\n\nprint(f\"Accuracy : {accuracy_score(y_test,y_hat):.2f}\")\n\nprint(confusion_matrix(y_test, y_hat))\n\nprint(classification_report(y_test, y_hat))\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## CatBoost\n\nLe dataset **Mushrooms** est constitué quasi exclusivement de **variables catégorielles**.  \nDans ce contexte, **CatBoost** est particulièrement intéressant, car il sait gérer les variables catégorielles **directement**, sans passer par un encodage one-hot systématique.\n\nAvec un modèle comme une forêt ou un boosting “classique”, on doit souvent faire :\n\n* `pd.get_dummies(...)` (one-hot)\n* ce qui peut créer beaucoup de colonnes\n\nCatBoost propose une autre approche :\n\n* on fournit les colonnes catégorielles telles quelles (strings ou catégories)\n* on indique à CatBoost quelles colonnes sont catégorielles\n* l’algorithme applique un encodage interne adapté (target statistics, ordres aléatoires, régularisation)\n\n### Principe de l'algorithme\n\nCatBoost est un algorithme de **gradient boosting sur arbres**, comme XGBoost ou LightGBM.\nSa spécificité est la **gestion native des variables catégorielles**.\n\nAu lieu d’un encodage one-hot, CatBoost utilise des **statistiques de cible régularisées** pour représenter les catégories.\nPour éviter toute **fuite d’information**, ces statistiques sont calculées selon des **ordres aléatoires des données** (ordered boosting), de sorte qu’une observation n’utilise jamais sa propre cible.\n\nCatBoost s’appuie en outre sur des **arbres symétriques** (profondeur fixe), ce qui améliore la stabilité et réduit le besoin de réglages fins.\n\n\n### CatBoostClassifier (classification)\n\n#### Import et modèle (API type sklearn)\n\n```python\nfrom catboost import CatBoostClassifier\n````\n\n```python\nmodel = CatBoostClassifier(\n    iterations=500,\n    learning_rate=0.05,\n    depth=6,\n    loss_function=\"Logloss\",\n    verbose=False\n)\n```\n\n#### Entraînement avec colonnes catégorielles\n\nCatBoost accepte :\n\n* soit les indices des colonnes catégorielles\n* soit leurs noms\n\n```python\ncat_features = X.columns.tolist()   # Mushrooms : toutes les colonnes sont catégorielles\n\nmodel.fit(\n    X_train, y_train,\n    cat_features=cat_features\n)\n```\n\n### CatBoostRegressor (régression)\n\nCatBoost peut aussi être utilisé en régression, avec la même logique (colonnes catégorielles gérées directement).\n\n#### Import et modèle\n\n```python\nfrom catboost import CatBoostRegressor\n```\n\n```python\nmodel = CatBoostRegressor(\n    iterations=500,\n    learning_rate=0.05,\n    depth=6,\n    loss_function=\"RMSE\",\n    verbose=False\n)\n```\n\n#### Entraînement\n\n```python\ncat_features = [i for i, col in enumerate(X.columns) if X[col].dtype == \"object\"]\n\nmodel.fit(\n    X_train, y_train,\n    cat_features=cat_features\n)\n```\n\n\n### Paramètres principaux \n\n* `iterations` : nombre d’arbres (comme `n_estimators`)\n* `learning_rate` : pas d’apprentissage\n* `depth` : profondeur des arbres\n* `loss_function` : fonction de perte (`Logloss`, `MultiClass`, `RMSE`, etc.)\n* `verbose` : affichage ou non du log d’entraînement\n\n","metadata":{"papermill":{"duration":0.022086,"end_time":"2026-02-22T17:25:28.213512","exception":false,"start_time":"2026-02-22T17:25:28.191426","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"### 💡 Syntaxe à reprendre\n\n_Repère syntaxique pour aborder l'exercice ci-dessous._\n\n```python\nfrom catboost import CatBoostClassifier\ncat_features = X.columns.tolist()\nmodel = model = CatBoostClassifier(verbose=False)\nmodel.fit(X_train, y_train, cat_features=cat_features)\ny_hat = model.predict(X_test)\n```\n","metadata":{}},{"cell_type":"markdown","source":"> #### Exercice\n> Utiliser `CatBoost` pour le dataset mushrooms\n> ","metadata":{"papermill":{"duration":0.022034,"end_time":"2026-02-22T17:25:28.25796","exception":false,"start_time":"2026-02-22T17:25:28.235926","status":"completed"},"tags":[]}},{"cell_type":"code","source":"df.head()\n\nX = df.drop(columns=['class'])\n\n[col for col in X.columns if X[col].dtype=='object']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:45:38.964123Z","iopub.execute_input":"2026-05-11T02:45:38.964479Z","iopub.status.idle":"2026-05-11T02:45:38.977783Z","shell.execute_reply.started":"2026-05-11T02:45:38.964452Z","shell.execute_reply":"2026-05-11T02:45:38.976937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X.columns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:46:41.424627Z","iopub.execute_input":"2026-05-11T02:46:41.425695Z","iopub.status.idle":"2026-05-11T02:46:41.431896Z","shell.execute_reply.started":"2026-05-11T02:46:41.425652Z","shell.execute_reply":"2026-05-11T02:46:41.430707Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from catboost import CatBoostClassifier\n\ndf = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/mushrooms.csv')\n\n# Traitement des données\n\n# Transformation de données\n\n\n# Suppression de colonnes peu informatives\ndf = df.drop(columns=['veil-type'])\n\n# Traitement des valeurs non numériques\ndf['class'] = df['class'].map({'p':0, 'e':1})\n\n# Prediction\n\nX = df.drop(columns=['class'])\ny = df['class']\n\nX_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2)\n\nmodel = CatBoostClassifier(verbose=False)\nmodel.fit(X_train,y_train, cat_features=list(X.columns))\ny_hat = model.predict(X_test)\n\nprint(f\"Accuracy : {accuracy_score(y_test,y_hat):.2f}\")\n\nprint(confusion_matrix(y_test, y_hat))\n\nprint(classification_report(y_test, y_hat))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:52:38.375336Z","iopub.execute_input":"2026-05-11T02:52:38.375718Z","iopub.status.idle":"2026-05-11T02:52:54.412827Z","shell.execute_reply.started":"2026-05-11T02:52:38.375689Z","shell.execute_reply":"2026-05-11T02:52:54.411687Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X.select_dtypes(\n    include=[\"object\", \"category\", \"bool\"]\n).columns.to_list()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:58:48.635936Z","iopub.execute_input":"2026-05-11T02:58:48.636740Z","iopub.status.idle":"2026-05-11T02:58:48.645427Z","shell.execute_reply.started":"2026-05-11T02:58:48.636703Z","shell.execute_reply":"2026-05-11T02:58:48.644418Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cat_features = X.select_dtypes(\n    include=[\"object\", \"category\", \"bool\"]\n).columns.tolist()\n\ncat_features","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T02:57:25.944530Z","iopub.execute_input":"2026-05-11T02:57:25.945052Z","iopub.status.idle":"2026-05-11T02:57:25.955171Z","shell.execute_reply.started":"2026-05-11T02:57:25.945018Z","shell.execute_reply":"2026-05-11T02:57:25.953815Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/student.csv')\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:01:19.604532Z","iopub.execute_input":"2026-05-11T03:01:19.605937Z","iopub.status.idle":"2026-05-11T03:01:19.646371Z","shell.execute_reply.started":"2026-05-11T03:01:19.605884Z","shell.execute_reply":"2026-05-11T03:01:19.645319Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Student Performance Dataset\n\nLe dataset **Student Performance** contient des données collectées auprès d’élèves de lycées portugais.\nChaque observation correspond à un élève et regroupe des informations **démographiques**, **familiales**, **scolaires** et **comportementales**.\n\n\n### Variable cible\n\n* **`G3`** : note de l’élève en dernière année (sur 20)\n\n\n### Variables descriptives\n\n#### Informations démographiques et familiales\n\n* **`school`** : établissement\n* **`sex`** : sexe\n* **`age`** : âge (en années)\n* **`address`** : type de résidence (urbaine ou rurale)\n* **`famsize`** : taille du foyer\n* **`Pstatus`** : parents vivant ensemble ou séparés\n* **`Medu`**, **`Fedu`** : niveau d’éducation de la mère et du père\n* **`Mjob`**, **`Fjob`** : profession de la mère et du père\n* **`guardian`** : responsable légal\n\n#### Contexte scolaire\n\n* **`reason`** : raison du choix de l’école\n* **`traveltime`** : temps de trajet domicile–école (catégories ordinales)\n* **`studytime`** : temps de travail hebdomadaire (catégories ordinales)\n* **`failures`** : nombre d’échecs scolaires antérieurs\n* **`schoolsup`** : soutien scolaire\n* **`famsup`** : soutien familial\n* **`paid`** : cours particuliers payants\n\n#### Mode de vie et environnement\n\n* **`activities`** : activités extrascolaires\n* **`nursery`** : scolarisation en maternelle\n* **`higher`** : intention de poursuivre des études supérieures\n* **`internet`** : accès à Internet à domicile\n* **`romantic`** : relation amoureuse\n* **`famrel`** : qualité des relations familiales (1 = très mauvaise, 5 = excellente)\n* **`freetime`** : temps libre après l’école (1 = très peu, 5 = beaucoup)\n* **`goout`** : fréquence des sorties avec des amis (1 = très rarement, 5 = très souvent)\n* **`Dalc`** : consommation d’alcool en semaine (1 à 5)\n* **`Walc`** : consommation d’alcool le week-end (1 à 5)\n* **`health`** : état de santé perçu (1 = très mauvais, 5 = très bon)\n* **`absences`** : nombre d’absences scolaires\n\n```python\ndf = pd.read_csv(\"/kaggle/input/datasets/pyim59/classic-datasets/student.csv\")\ndf.head()\n```\n","metadata":{"papermill":{"duration":0.022136,"end_time":"2026-02-22T17:25:43.286821","exception":false,"start_time":"2026-02-22T17:25:43.264685","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Types de variables, `dtype` et sélection des colonnes\n\nDans pandas, chaque colonne d’un DataFrame possède un **type de données** appelé **`dtype`** (*data type*).\nLe `dtype` indique la **nature des valeurs** stockées dans la colonne et conditionne la façon dont elles peuvent être traitées ou analysées.\n\n### Types (`dtype`) courants\n\n* `object` : chaînes de caractères (catégories textuelles)\n* `category` : catégories pandas (modalités finies, optimisées)\n* `bool` : variables booléennes (oui / non)\n* `int`, `float` : variables numériques (entiers, réels)\n\n\n\n## Sélection des colonnes par type : `select_dtypes`\n\nLa méthode `select_dtypes` permet de sélectionner automatiquement des colonnes en fonction de leur `dtype`.\n\n### Variables catégorielles\n\n```python\ncat_features = X.select_dtypes(\n    include=[\"object\", \"category\", \"bool\"]\n).columns.tolist()\n```\n\nCes colonnes représentent des **modalités** et non des grandeurs mesurables.\n\n\n\n### Variables numériques\n\nLes variables numériques peuvent être définies comme le **complément** des variables catégorielles :\n\n```python\nnum_features = [col for col in X.columns if col not in cat_features]\n```\n\nCette approche garantit une **partition claire** :\n\n* chaque variable est soit catégorielle, soit numérique\n* aucune colonne n’est oubliée ou comptée deux fois\n\n\n","metadata":{"papermill":{"duration":0.022968,"end_time":"2026-02-22T17:25:43.411943","exception":false,"start_time":"2026-02-22T17:25:43.388975","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 💡 Syntaxe à reprendre\n\n_Repère syntaxique pour aborder l'exercice ci-dessous._\n\n```python\ncat_features = X.select_dtypes(include=['object', 'category', 'bool']).columns.tolist()\ncat_features\n```\n","metadata":{}},{"cell_type":"markdown","source":"> #### Exercice\n> Comparer xgboost et catboost pour prédire la note finale d'un étudiant\n>\n> Analyse critique des résultats ?","metadata":{"papermill":{"duration":0.02616,"end_time":"2026-02-22T17:25:43.506689","exception":false,"start_time":"2026-02-22T17:25:43.480529","status":"completed"},"tags":[]}},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/student.csv')\n\nX = df.drop(columns=['G3'])\ny = df['G3']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:08:09.932011Z","iopub.execute_input":"2026-05-11T03:08:09.933072Z","iopub.status.idle":"2026-05-11T03:08:09.948743Z","shell.execute_reply.started":"2026-05-11T03:08:09.933023Z","shell.execute_reply":"2026-05-11T03:08:09.947662Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:08:35.634897Z","iopub.execute_input":"2026-05-11T03:08:35.636348Z","iopub.status.idle":"2026-05-11T03:08:35.655986Z","shell.execute_reply.started":"2026-05-11T03:08:35.636296Z","shell.execute_reply":"2026-05-11T03:08:35.654556Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cat_features = X.select_dtypes(\n    include=[\"object\"]\n).columns.tolist()\n\ncat_features","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:11:51.742242Z","iopub.execute_input":"2026-05-11T03:11:51.742655Z","iopub.status.idle":"2026-05-11T03:11:51.751214Z","shell.execute_reply.started":"2026-05-11T03:11:51.742622Z","shell.execute_reply":"2026-05-11T03:11:51.750225Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"num_features = [col for col in X.columns if col not in cat_features]\nnum_features","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:13:51.543968Z","iopub.execute_input":"2026-05-11T03:13:51.544373Z","iopub.status.idle":"2026-05-11T03:13:51.552889Z","shell.execute_reply.started":"2026-05-11T03:13:51.544342Z","shell.execute_reply":"2026-05-11T03:13:51.551488Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/student.csv')\n\n# Traitement des données\n\n# Transformation de données\n\n\n# Suppression de colonnes peu informatives\n# df = df.drop(columns=['veil-type'])\n\n# Traitement des valeurs non numériques\ncat_features = df.drop(columns=['G3']).select_dtypes(\n    include=[\"object\"]\n).columns.tolist()\n\ndf = pd.get_dummies(df, columns=cat_features)\n\n# Prediction\n\nX = df.drop(columns=['G3'])\ny = df['G3']\n\nX_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2)\n\nmodel = RandomForestRegressor()\nmodel.fit(X_train,y_train)\ny_hat = model.predict(X_test)\n\nprint(f\"MAE : {mean_absolute_error(y_test,y_hat):.2f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:25:16.734549Z","iopub.execute_input":"2026-05-11T03:25:16.735652Z","iopub.status.idle":"2026-05-11T03:25:17.306407Z","shell.execute_reply.started":"2026-05-11T03:25:16.735571Z","shell.execute_reply":"2026-05-11T03:25:17.305277Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from catboost import CatBoostRegressor\n\ndf = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/student.csv')\n\n# Traitement des données\n\n# Transformation de données\n\n\n# Suppression de colonnes peu informatives\n# df = df.drop(columns=['veil-type'])\n\n# Traitement des valeurs non numériques\n\n# Prediction\n\nX = df.drop(columns=['G3', 'G1', 'G2'])\ny = df['G3']\n\ncat_features = X.select_dtypes(\n    include=[\"object\"]\n).columns.tolist()\n\nX_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2)\n\nmodel = CatBoostRegressor(verbose=False)\nmodel.fit(X_train,y_train, cat_features=cat_features)\ny_hat = model.predict(X_test)\n\nprint(f\"MAE : {mean_absolute_error(y_test,y_hat):.2f}\")\nprint(f\"R2 score : {r2_score(y_test,y_hat):.2f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:29:55.840553Z","iopub.execute_input":"2026-05-11T03:29:55.840976Z","iopub.status.idle":"2026-05-11T03:29:58.913183Z","shell.execute_reply.started":"2026-05-11T03:29:55.840935Z","shell.execute_reply":"2026-05-11T03:29:58.911866Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/student.csv')\n\ncat_features = df.select_dtypes(\n    include=[\"object\"]\n).columns.tolist()\n\nnum_features = [col for col in df.columns if col not in cat_features]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:37:14.584972Z","iopub.execute_input":"2026-05-11T03:37:14.586029Z","iopub.status.idle":"2026-05-11T03:37:14.601625Z","shell.execute_reply.started":"2026-05-11T03:37:14.585988Z","shell.execute_reply":"2026-05-11T03:37:14.600594Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sns.clustermap(abs(df[num_features].corr()))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:39:33.718382Z","iopub.execute_input":"2026-05-11T03:39:33.718855Z","iopub.status.idle":"2026-05-11T03:39:34.226587Z","shell.execute_reply.started":"2026-05-11T03:39:33.718821Z","shell.execute_reply":"2026-05-11T03:39:34.225579Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{"papermill":{"duration":0.022987,"end_time":"2026-02-22T17:25:46.588745","exception":false,"start_time":"2026-02-22T17:25:46.565758","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## Corrélations \n\nUne **corrélation** mesure le degré d’association entre deux variables. Elle indique dans quelle mesure les variations de l’une sont liées aux variations de l’autre, sans présumer d’un lien causal.\nLes coefficients de corrélation sont généralement compris entre **−1 et +1**, où la valeur absolue reflète l’intensité de la relation et le signe son sens (positif ou négatif).\n\n\n### Principales mesures de corrélation\n\n* **Corrélation de Pearson**\n  Mesure une **relation linéaire** entre deux variables numériques continues. Elle est sensible aux valeurs extrêmes et suppose une relation approximativement linéaire.\n\n* **Corrélation de Spearman**\n  Basée sur les **rangs** des valeurs. Elle mesure une relation **monotone** (pas nécessairement linéaire) et est plus robuste aux outliers.\n\n* **Corrélation de Kendall**\n  Évalue la concordance entre paires d’observations. Elle est souvent utilisée pour des jeux de données plus petits ou fortement bruités.\n\nEn pandas, la corrélation de Pearson est utilisée par défaut, mais d’autres méthodes sont disponibles.\n\n\n\n### Calcul de la matrice de corrélation\n\n```python\ncorr = df.corr()                 # Pearson (par défaut)\ncorr_spearman = df.corr(method=\"spearman\")\ncorr_kendall = df.corr(method=\"kendall\")\n```\n\nSeules les **variables numériques** sont prises en compte.\n\n\n### Visualisation : heatmap\n\nUne **heatmap** permet de représenter la matrice de corrélation sous forme de carte de couleurs :\n\n```python\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nsns.heatmap(corr, cmap=\"coolwarm\", center=0)\nplt.show()\n```\n\nElle facilite l’identification rapide des corrélations fortes, positives ou négatives.\n\n\n\n### Visualisation : clustermap\n\nLa **clustermap** combine la matrice de corrélation avec un **clustering hiérarchique** des variables :\n\n```python\nsns.clustermap(corr, cmap=\"coolwarm\", center=0)\nplt.show()\n```\n\nLes variables sont automatiquement regroupées selon leur similarité, ce qui fait apparaître des blocs de variables corrélées.\n\n```python\ndf = pd.read_csv(\"/kaggle/input/datasets/pyim59/classic-datasets/student.csv\")\ndf.head()\n```\n\n```python\ndf = pd.read_csv(\"/kaggle/input/datasets/pyim59/classic-datasets/student.csv\")\n\ncat_features = df.select_dtypes(include=[\"object\", \"category\", \"bool\"]).columns.tolist()\n\nnum_features = [col for col in df.columns if col not in cat_features]\n\ncorr = df[num_features].corr()\n```\n\n```python\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nsns.heatmap(corr, cmap=\"coolwarm\", center=0)\nplt.show()\n```\n\n```python\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nsns.heatmap(corr.abs(), cmap=\"coolwarm\", center=0)\nplt.show()\n```\n\n```python\nsns.clustermap(corr, cmap=\"coolwarm\", center=0)\nplt.show()\n```\n\n```python\nsns.clustermap(corr.abs(), cmap=\"coolwarm\", center=0)\nplt.show()\n```\n","metadata":{"papermill":{"duration":0.022951,"end_time":"2026-02-22T17:25:46.634878","exception":false,"start_time":"2026-02-22T17:25:46.611927","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/datasets/pyim59/classic-datasets/creditcard.csv')\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:42:29.127711Z","iopub.execute_input":"2026-05-11T03:42:29.128140Z","iopub.status.idle":"2026-05-11T03:42:32.673927Z","shell.execute_reply.started":"2026-05-11T03:42:29.128106Z","shell.execute_reply":"2026-05-11T03:42:32.672789Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df[df['Class']==1]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T03:43:44.135873Z","iopub.execute_input":"2026-05-11T03:43:44.136303Z","iopub.status.idle":"2026-05-11T03:43:44.168919Z","shell.execute_reply.started":"2026-05-11T03:43:44.136270Z","shell.execute_reply":"2026-05-11T03:43:44.167697Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"d","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Dataset Credit Card Fraud Detection\n\nLe dataset **Credit Card Fraud Detection** contient des transactions effectuées par des titulaires de cartes bancaires européennes sur une période de deux jours.  \nIl est conçu pour étudier et illustrer un problème réel de **détection de fraude**, caractérisé par un **déséquilibre extrême des classes**.\n\n\n### Objectif de prédiction\n\n* **Cible :** `Class`\n  * `0` : transaction légitime\n  * `1` : transaction frauduleuse\n\nLa tâche consiste à prédire si une transaction est frauduleuse ou non à partir de ses caractéristiques.\n\n\n#### Variables explicatives\n\n* `Time`  \n  Temps écoulé (en secondes) depuis la première transaction du jeu de données.  \n  Il ne correspond pas à une date réelle mais à un index temporel relatif.\n\n* `V1` à `V28`  \n  Variables numériques obtenues par **Analyse en Composantes Principales (PCA)**.  \n  Elles résultent d’une transformation linéaire appliquée aux variables originales afin de :\n  * protéger la confidentialité des données\n  * conserver l’information statistique utile à la détection de fraude\n\n  Leur interprétation directe n’est pas accessible.\n\n* `Amount`  \n  Montant de la transaction.  \n","metadata":{"papermill":{"duration":0.026324,"end_time":"2026-02-22T17:25:48.4703","exception":false,"start_time":"2026-02-22T17:25:48.443976","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"### 💡 Syntaxe à reprendre\n\n_Repère syntaxique pour aborder l'exercice ci-dessous._\n\n```python\nmodel = DecisionTreeClassifier()\nmodel.fit(X_train, y_train)\ny_hat = model.predict(X_test)\n```\n","metadata":{}},{"cell_type":"markdown","source":"> #### Exercice\n>\n> Prédire la fraude avec un modèle simple (arbre de décision par exemple)","metadata":{"papermill":{"duration":0.027866,"end_time":"2026-02-22T17:25:48.524153","exception":false,"start_time":"2026-02-22T17:25:48.496287","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Pourquoi l’accuracy semble bonne dans la détection de fraude\n\nDans le dataset **Credit Card Fraud**, la proportion de fraudes est extrêmement faible  \n(≈ 0,17 % des transactions).\n\n### Exemple simple\n\nSi un modèle prédit systématiquement :\n\n> « aucune transaction n’est frauduleuse »\n\nalors :\n* il classe correctement **99,83 %** des transactions\n* son **accuracy est très élevée**\n* mais il **ne détecte aucune fraude**\n\nCe modèle est pourtant **inutile en pratique**.\n\n\n### Limite de l’accuracy\n\nL’accuracy mesure :\n\n$$\n\\text{accuracy} = \\frac{\\text{nombre de prédictions correctes}}{\\text{nombre total d’observations}}\n$$\n\nDans un dataset **déséquilibré** :\n* la classe majoritaire domine ce calcul\n* les erreurs sur la classe rare ont peu d’impact sur l’accuracy\n* un modèle peut être performant selon l’accuracy tout en échouant sur l’objectif réel\n\n\n### Problème du déséquilibre de données\n\nUn dataset est dit **déséquilibré** lorsque :\n* une classe est très majoritaire\n* l’autre est rare mais **critique**\n\nDans la fraude bancaire :\n* classe majoritaire : transactions normales\n* classe minoritaire : fraudes (mais coût élevé)\n\nConséquences :\n* les modèles apprennent surtout la classe majoritaire\n* les frontières de décision sont biaisées\n* les probabilités prédites sont souvent mal calibrées\n\n","metadata":{"papermill":{"duration":0.026815,"end_time":"2026-02-22T17:26:24.185158","exception":false,"start_time":"2026-02-22T17:26:24.158343","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"### Sous-échantillonnage (undersampling)\n\nLe sous-échantillonnage consiste à **réduire artificiellement la classe majoritaire**\nafin d’obtenir un dataset plus équilibré, sans utiliser de librairie dédiée\n(comme `imblearn`).\n\nDans le dataset **Credit Card Fraud** :\n\n* classe majoritaire : `Class = 0` (transactions normales)\n* classe minoritaire : `Class = 1` (fraudes)\n\nL’idée est de :\n1. conserver **toutes** les fraudes\n2. tirer aléatoirement autant de transactions normales\n3. concaténer les deux sous-ensembles\n\n","metadata":{"papermill":{"duration":0.02609,"end_time":"2026-02-22T17:26:24.238279","exception":false,"start_time":"2026-02-22T17:26:24.212189","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## La librairie `imblearn` (imbalanced-learn)\n\nLa librairie **imbalanced-learn** (`imblearn`) fournit des outils pour traiter les **datasets déséquilibrés** (classe rare vs classe majoritaire), en proposant des méthodes de :\n* **sous-échantillonnage** (réduire la classe majoritaire)\n* **sur-échantillonnage** (augmenter la classe minoritaire)\n* combinaisons des deux\n* pipelines compatibles scikit-learn\n\n\n### Installation (Kaggle)\n\n```python\n!pip install -U imbalanced-learn\n````\n\nAprès installation, redémarrer la session Kaggle si nécessaire.\n\n\n### 1) Sous-échantillonnage (undersampling)\n\n* `RandomUnderSampler`\n  Réduit aléatoirement la classe majoritaire.\n\n\nExemple :\n\n```python\nfrom imblearn.under_sampling import RandomUnderSampler\n\nsampler = RandomUnderSampler()\nX_res, y_res = sampler.fit_resample(X, y)\n```\n\n\n### 2) Sur-échantillonnage (oversampling)\n\n* `RandomOverSampler`\n  Duplique aléatoirement des observations de la classe minoritaire.\n\n* `SMOTE`\n  Génère de nouveaux points synthétiques par interpolation (variables numériques).\n\n* `ADASYN`\n  Variante de SMOTE qui génère davantage d’exemples dans les zones difficiles.\n\nExemple :\n\n```python\nfrom imblearn.over_sampling import SMOTE\n\nsampler = SMOTE()\nX_res, y_res = sampler.fit_resample(X, y)\n```\n\n\n### 3) Méthodes combinées\n\n* `SMOTEENN`\n  SMOTE + nettoyage par Edited Nearest Neighbours.\n\n* `SMOTETomek`\n  SMOTE + suppression de paires Tomek (nettoyage des frontières).\n\n### Attention\n\nLe rééchantillonnage peut être réalisé sur le dataset de **train** mais pas sur le **test**  \nPourquoi ?\n\n### Usage recommandé : `Pipeline` (imblearn)\n\nLa bonne pratique est d’intégrer l’échantillonnage dans une **pipeline** pour éviter les erreurs de procédure.\n\n```python\nfrom imblearn.pipeline import Pipeline\nfrom imblearn.over_sampling import SMOTE\n\nmodel = Pipeline([\n    (\"smote\", SMOTE()),\n    (\"dtc\", DecisionTreeClassifier(random_state=42))\n])\n```\n\n\n\n","metadata":{"papermill":{"duration":0.026718,"end_time":"2026-02-22T17:26:24.29104","exception":false,"start_time":"2026-02-22T17:26:24.264322","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"### Le paramètre `stratify` dans `train_test_split`\n\nLe paramètre **`stratify`** permet de **conserver la proportion des classes** lors de la séparation des données en jeux d’entraînement et de test.\n\n```python\nfrom sklearn.model_selection import train_test_split\n\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y,\n    test_size=0.2,\n    random_state=42,\n    stratify=y\n)\n```\n\n\n#### Principe\n\nSans `stratify`, la séparation est **aléatoire**.\nSur des jeux de données **déséquilibrés**, cela peut conduire à :\n\n* un jeu de test avec trop peu (voire aucun) exemples de la classe minoritaire\n* une évaluation instable ou trompeuse\n\nAvec `stratify=y` :\n\n* chaque classe est représentée **dans les mêmes proportions** que dans le dataset initial\n* le déséquilibre naturel est **préservé**, mais réparti équitablement\n\n\n#### Attention\n\n* `stratify=y` **ne rééquilibre pas** les classes\n* il garantit uniquement une **répartition proportionnelle** entre train et test\n\n\n","metadata":{"papermill":{"duration":0.027365,"end_time":"2026-02-22T17:26:24.34517","exception":false,"start_time":"2026-02-22T17:26:24.317805","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"### 💡 Syntaxe à reprendre\n\n_Repère syntaxique pour aborder l'exercice ci-dessous._\n\n```python\nfrom imblearn.under_sampling import RandomUnderSampler\nfrom imblearn.pipeline import Pipeline\nmodel = Pipeline([('dtc', DecisionTreeClassifier())])\nmodel.fit(X_train, y_train)\ny_hat = model.predict(X_test)\ny_score = model.predict_proba(X_test)[:, 1]\n(fpr, tpr, thresholds) = roc_curve(y_test, y_score)\nauc = roc_auc_score(y_test, y_score)\n```\n","metadata":{}},{"cell_type":"markdown","source":"> #### Exercice : sous-échantillonnage et prédiction de fraude\n> Prédire la fraude\n>\n> Tester sous-échantillonnage et suréchantillonnage\n>\n> Faire varier le seuil (probabilité) pour la prédiction\n","metadata":{"papermill":{"duration":0.026429,"end_time":"2026-02-22T17:26:24.398035","exception":false,"start_time":"2026-02-22T17:26:24.371606","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Pondération des classes\n\nLa pondération des classes consiste à **donner plus de poids aux erreurs sur la classe minoritaire** dans la fonction de perte, sans modifier les données.\n\nAlternative au sur-/sous-échantillonnage.\n\n\n### DecisionTreeClassifier\n\nLe **`DecisionTreeClassifier`** permet de gérer le déséquilibre des classes via le paramètre **`class_weight`**.\n\n#### Pondération automatique des classes\n\n```python\nDecisionTreeClassifier(\n    class_weight=\"balanced\"\n)\n```\n\n* les poids sont calculés automatiquement à partir des fréquences des classes\n* les erreurs sur la classe minoritaire sont davantage pénalisées\n* la construction de l’arbre (Gini / entropie) est modifiée en conséquence\n\n\n#### Pondération manuelle\n\n```python\nDecisionTreeClassifier(\n    class_weight={0: 1, 1: 5}\n)\n```\n\n\n### Random Forest\n\n```python\nfrom sklearn.ensemble import RandomForestClassifier\n\nmodel = RandomForestClassifier(\n    class_weight=\"balanced\"\n)\n```\n\nOu pondération manuelle :\n\n```python\nclass_weight = {0: 1, 1: 5}\n```\n\n\n### XGBoost\n\nXGBoost n'utilise pas `class_weight`, mais le **poids de la classe positive**.\n\n```python\nfrom xgboost import XGBClassifier\n\nmodel = XGBClassifier(\n    scale_pos_weight = n_negative / n_positive\n)\n```\n\n\n### LightGBM\n\nDeux options possibles :\n\n#### Option 1 : automatique\n\n```python\nis_unbalance=True\n```\n\n#### Option 2 : explicite (recommandée)\n\n```python\nclass_weight = {0: 1, 1: 5}\n```\n\n\n### CatBoost\n\n#### Option 1 : poids automatiques\n\n```python\nauto_class_weights=\"Balanced\"\n```\n\n#### Option 2 : poids explicites\n\n```python\nclass_weights=[1, 5]\n```\n\n\n\n## Tableau récapitulatif\n\n| Modèle                      | Équivalent de `class_weight=\"balanced\"` |\n| --------------------------- | --------------------------------------- |\n| Decision Tree               | `class_weight=\"balanced\"`               |\n| Random Forest               | `class_weight=\"balanced\"`               |\n| XGBoost                     | `scale_pos_weight`                      |\n| LightGBM                    | `class_weight` ou `is_unbalance`        |\n| CatBoost                    | `auto_class_weights=\"Balanced\"`         |\n\n\n> La pondération des classes modifie la **fonction de coût**, pas les données.\n\n```python\nfrom imblearn.under_sampling import RandomUnderSampler\nfrom imblearn.pipeline import Pipeline\n\ndf = pd.read_csv(\"/kaggle/input/datasets/pyim59/classic-datasets/creditcard.csv\")\n\nX = df.drop(columns=['Class'])\ny = df['Class']\n\nX_train, X_test, y_train, y_test = train_test_split(\n    X,\n    y,\n    test_size=0.2,\n    stratify=y\n)\n\nDecisionTreeClassifier(\n    class_weight=\"balanced\"\n)\nmodel.fit(X_train, y_train)\ny_hat = model.predict(X_test)\n\nprint(\"Accuracy  =\", accuracy_score(y_test, y_hat))\nprint(classification_report(y_test, y_hat))\n\nprint(confusion_matrix(y_test, y_hat))\n\ny_score = model.predict_proba(X_test)[:, 1]\nfpr, tpr, thresholds = roc_curve(y_test, y_score)\nauc = roc_auc_score(y_test, y_score)\nprint(f\"AUC  : {auc:.2f}\")\n\nplt.plot(fpr, tpr)\nplt.show()\n```\n","metadata":{"papermill":{"duration":0.026661,"end_time":"2026-02-22T17:29:33.576574","exception":false,"start_time":"2026-02-22T17:29:33.549913","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Telecom Churn Dataset\n\nLe dataset **Telecom Churn** contient des informations clients issues d’un opérateur de télécommunications.\nChaque ligne correspond à un client et décrit son **profil**, son **usage des services** et ses **interactions avec le support**, avec pour objectif de prédire le **churn**, c’est-à-dire le départ du client (*attrition* en français).\n\n\n### Variable cible\n\n* **`Churn`**\n\n  * `True` / `False` (ou `Yes` / `No`)\n    Indique si le client a résilié ou quitté le service.\n\n\n### Variables descriptives\n\n#### Informations générales\n\n* **`State`** : État de résidence\n* **`Area code`** : indicatif régional\n* **`Account length`** : ancienneté du compte (en jours)\n\n#### Options et abonnements\n\n* **`International plan`** : option internationale\n* **`Voice mail plan`** : option messagerie vocale\n* **`Number vmail messages`** : nombre de messages vocaux\n\n#### Usage des services\n\n* **`Total day minutes`**, **`Total eve minutes`**, **`Total night minutes`**, **`Total intl minutes`**\n* **`Total day calls`**, **`Total eve calls`**, **`Total night calls`**, **`Total intl calls`**\n\n#### Facturation\n\n* **`Total day charge`**, **`Total eve charge`**, **`Total night charge`**, **`Total intl charge`**\n\n#### Relation client\n\n* **`Customer service calls`** : nombre d’appels au service client","metadata":{"papermill":{"duration":0.027367,"end_time":"2026-02-22T17:30:52.090689","exception":false,"start_time":"2026-02-22T17:30:52.063322","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"### 💡 Syntaxe à reprendre\n\n_Repère syntaxique pour aborder l'exercice ci-dessous._\n\n```python\ndf.head()\n```\n","metadata":{}},{"cell_type":"markdown","source":"> #### Exercice\n> \n> Prédire l'attrition client (churn)\n","metadata":{"papermill":{"duration":0.02839,"end_time":"2026-02-22T17:30:52.146375","exception":false,"start_time":"2026-02-22T17:30:52.117985","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{"papermill":{"duration":0.028711,"end_time":"2026-02-22T17:30:59.249183","exception":false,"start_time":"2026-02-22T17:30:59.220472","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## Adult Census Income Dataset\n\nLe dataset **Adult Census** (aussi appelé *Census Income*) provient du recensement américain.\nL’objectif est de **prédire la tranche de revenu** d’un individu à partir de caractéristiques démographiques, éducatives et professionnelles.\n\n### Variable cible\n\n* **`income`**\n\n  * `<=50K`\n  * `>50K`\n\n\n### Principales variables explicatives\n\n#### Variables numériques\n\n* **`age`** : âge de l’individu\n* **`education.num`** : niveau d’éducation codé numériquement\n* **`capital.gain`**, **`capital.loss`** : gains et pertes en capital\n* **`hours.per.week`** : nombre d’heures travaillées par semaine\n* **`fnlwgt`** : poids d’échantillonnage (nombre de personnes représentées)\n\n#### Variables catégorielles\n\n* **`workclass`** : type d’emploi (privé, public, indépendant, etc.)\n* **`education`** : niveau d’éducation (libellé textuel)\n* **`marital.status`** : statut marital\n* **`occupation`** : catégorie de profession\n* **`relationship`** : rôle dans le foyer\n* **`race`**, **`sex`**\n* **`native.country`** : pays d’origine\n","metadata":{"papermill":{"duration":0.028455,"end_time":"2026-02-22T17:30:59.305841","exception":false,"start_time":"2026-02-22T17:30:59.277386","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"### 💡 Syntaxe à reprendre\n\n_Repère syntaxique pour aborder l'exercice ci-dessous._\n\n```python\ncat_features = X.select_dtypes(include=['object', 'category', 'bool']).columns.tolist()\ncat_features\n```\n","metadata":{}},{"cell_type":"markdown","source":"> #### Exercice\n> Prédire la tranche de salaire","metadata":{"papermill":{"duration":0.139712,"end_time":"2026-02-22T17:30:59.474023","exception":false,"start_time":"2026-02-22T17:30:59.334311","status":"completed"},"tags":[]}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null}]}