{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":9994,"databundleVersionId":752467,"sourceType":"competition"}],"dockerImageVersionId":31239,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.ensemble import IsolationForest\nDATA_PATH = \"/kaggle/input/ashrae-energy-prediction/\"\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:28:52.935638Z","iopub.execute_input":"2025-12-20T15:28:52.935944Z","iopub.status.idle":"2025-12-20T15:28:57.518743Z","shell.execute_reply.started":"2025-12-20T15:28:52.935922Z","shell.execute_reply":"2025-12-20T15:28:57.517641Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"building = pd.read_csv(DATA_PATH + \"building_metadata.csv\")\nweather = pd.read_csv(DATA_PATH + \"weather_train.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:29:16.084292Z","iopub.execute_input":"2025-12-20T15:29:16.085211Z","iopub.status.idle":"2025-12-20T15:29:16.223314Z","shell.execute_reply.started":"2025-12-20T15:29:16.085177Z","shell.execute_reply":"2025-12-20T15:29:16.222182Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"chunksize = 1_000_000\ntrain_chunks = pd.read_csv(\n    DATA_PATH + \"train.csv\",\n    chunksize=chunksize\n)\n\nsample_list = []\n\nfor chunk in train_chunks:\n    # Électricité uniquement\n    chunk = chunk[chunk[\"meter\"] == 0]\n\n    # Jointure pour filtrer Office\n    chunk = chunk.merge(\n        building[[\"building_id\", \"primary_use\"]],\n        on=\"building_id\",\n        how=\"left\"\n    )\n    chunk = chunk[chunk[\"primary_use\"] == \"Office\"]\n\n    # Échantillon 1 %\n    if len(chunk) > 0:\n        chunk = chunk.sample(frac=0.01, random_state=42)\n        sample_list.append(chunk)\n\ntrain = pd.concat(sample_list, ignore_index=True)\nprint(\"Dataset après échantillonnage :\", train.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:29:40.910126Z","iopub.execute_input":"2025-12-20T15:29:40.910447Z","iopub.status.idle":"2025-12-20T15:29:54.9939Z","shell.execute_reply.started":"2025-12-20T15:29:40.910424Z","shell.execute_reply":"2025-12-20T15:29:54.992801Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"chunksize = 1_000_000\ntrain_chunks = pd.read_csv(\n    DATA_PATH + \"train.csv\",\n    chunksize=chunksize\n)\n\nsample_list = []\n\nfor chunk in train_chunks:\n    # Électricité uniquement\n    chunk = chunk[chunk[\"meter\"] == 0]\n\n    # Merge CORRIGÉ avec site_id\n    chunk = chunk.merge(\n        building[[\"building_id\", \"site_id\", \"primary_use\"]],\n        on=\"building_id\",\n        how=\"left\"\n    )\n\n    # Filtrer bureaux\n    chunk = chunk[chunk[\"primary_use\"] == \"Office\"]\n\n    # Échantillon 1 %\n    if len(chunk) > 0:\n        chunk = chunk.sample(frac=0.01, random_state=42)\n        sample_list.append(chunk)\n\ntrain = pd.concat(sample_list, ignore_index=True)\nprint(\"Colonnes disponibles :\", train.columns)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:34:08.886508Z","iopub.execute_input":"2025-12-20T15:34:08.886874Z","iopub.status.idle":"2025-12-20T15:34:20.31394Z","shell.execute_reply.started":"2025-12-20T15:34:08.886851Z","shell.execute_reply":"2025-12-20T15:34:20.312937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = train.merge(\n    weather,\n    on=[\"site_id\", \"timestamp\"],\n    how=\"left\"\n)\n\nprint(\"Colonnes après merge météo :\")\nprint(train.columns)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:35:20.158164Z","iopub.execute_input":"2025-12-20T15:35:20.158516Z","iopub.status.idle":"2025-12-20T15:35:20.211177Z","shell.execute_reply.started":"2025-12-20T15:35:20.158489Z","shell.execute_reply":"2025-12-20T15:35:20.210097Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train[\"timestamp\"] = pd.to_datetime(train[\"timestamp\"])\ntrain[\"hour\"] = train[\"timestamp\"].dt.hour\ntrain[\"weekday\"] = train[\"timestamp\"].dt.weekday\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:35:44.985701Z","iopub.execute_input":"2025-12-20T15:35:44.986873Z","iopub.status.idle":"2025-12-20T15:35:45.007578Z","shell.execute_reply.started":"2025-12-20T15:35:44.986838Z","shell.execute_reply":"2025-12-20T15:35:45.006519Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Simulation occupancy\ndef simulate_occupancy(row):\n    if row[\"weekday\"] >= 5:  # week-end\n        return 0\n    elif 8 <= row[\"hour\"] < 12 or 13 <= row[\"hour\"] < 18:\n        return 1\n    else:\n        return 0\n\ntrain[\"occupancy\"] = train.apply(simulate_occupancy, axis=1)\n\n# Bruit capteur (10%)\nnoise = np.random.choice([0, 1], size=len(train), p=[0.1, 0.9])\ntrain[\"occupancy\"] = train[\"occupancy\"] * noise\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:36:59.864548Z","iopub.execute_input":"2025-12-20T15:36:59.865122Z","iopub.status.idle":"2025-12-20T15:37:00.100983Z","shell.execute_reply.started":"2025-12-20T15:36:59.865095Z","shell.execute_reply":"2025-12-20T15:37:00.100069Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train[\"air_temperature\"] = train[\"air_temperature\"].fillna(\n    train[\"air_temperature\"].mean()\n)\n\ntrain[\"meter_reading\"] = train[\"meter_reading\"].fillna(0)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:37:16.206185Z","iopub.execute_input":"2025-12-20T15:37:16.206542Z","iopub.status.idle":"2025-12-20T15:37:16.213897Z","shell.execute_reply.started":"2025-12-20T15:37:16.206518Z","shell.execute_reply":"2025-12-20T15:37:16.212789Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X = train[\n    [\"meter_reading\", \"air_temperature\", \"hour\"]\n]\n+","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:38:24.94428Z","iopub.execute_input":"2025-12-20T15:38:24.945636Z","iopub.status.idle":"2025-12-20T15:38:24.951175Z","shell.execute_reply.started":"2025-12-20T15:38:24.945576Z","shell.execute_reply":"2025-12-20T15:38:24.950008Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"features = [\"meter_reading\", \"air_temperature\", \"hour\"]\nX = train[features]\n\nfrom sklearn.preprocessing import StandardScaler\n\nscaler = StandardScaler()\nX_scaled = pd.DataFrame(\n    scaler.fit_transform(X),\n    columns=features,\n    index=train.index\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:40:46.757224Z","iopub.execute_input":"2025-12-20T15:40:46.757514Z","iopub.status.idle":"2025-12-20T15:40:46.774865Z","shell.execute_reply.started":"2025-12-20T15:40:46.757495Z","shell.execute_reply":"2025-12-20T15:40:46.773873Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings(\"ignore\", category=UserWarning)\n\n\nfrom sklearn.ensemble import IsolationForest\nfrom sklearn.preprocessing import StandardScaler\n\nfeatures = [\"meter_reading\", \"air_temperature\", \"hour\"]\n\n# Sélection features\nX = train[features]\n\n# Normalisation\nscaler = StandardScaler()\nX_scaled = pd.DataFrame(\n    scaler.fit_transform(X),\n    columns=features,\n    index=train.index\n)\n\n# Modèle non supervisé\niso = IsolationForest(\n    n_estimators=100,\n    contamination=0.05,\n    random_state=42\n)\n\n# FIT + PREDICT ENSEMBLE (clé pour éviter le warning)\ntrain[\"anomaly\"] = iso.fit_predict(X_scaled)\n\n# Conversion labels\ntrain[\"anomaly\"] = train[\"anomaly\"].map({1: 0, -1: 1})\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:45:27.782338Z","iopub.execute_input":"2025-12-20T15:45:27.783495Z","iopub.status.idle":"2025-12-20T15:45:29.428783Z","shell.execute_reply.started":"2025-12-20T15:45:27.78346Z","shell.execute_reply":"2025-12-20T15:45:29.4278Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train[\"anomaly\"].value_counts(normalize=True)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:46:03.040164Z","iopub.execute_input":"2025-12-20T15:46:03.040822Z","iopub.status.idle":"2025-12-20T15:46:03.05386Z","shell.execute_reply.started":"2025-12-20T15:46:03.040795Z","shell.execute_reply":"2025-12-20T15:46:03.052701Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train[\"waste\"] = (\n    (train[\"anomaly\"] == 1) & \n    (train[\"occupancy\"] == 0)\n).astype(int)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:48:20.210802Z","iopub.execute_input":"2025-12-20T15:48:20.211127Z","iopub.status.idle":"2025-12-20T15:48:20.218572Z","shell.execute_reply.started":"2025-12-20T15:48:20.211106Z","shell.execute_reply":"2025-12-20T15:48:20.217538Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"total_kwh = train[\"meter_reading\"].sum()\nwasted_kwh = train.loc[train[\"waste\"] == 1, \"meter_reading\"].sum()\nsaving_pct = (wasted_kwh / total_kwh) * 100\n\nprint(f\"Consommation totale : {total_kwh:.2f} kWh\")\nprint(f\"Gaspillage détecté : {wasted_kwh:.2f} kWh\")\nprint(f\"Économie potentielle : {saving_pct:.2f} %\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:48:33.238323Z","iopub.execute_input":"2025-12-20T15:48:33.238795Z","iopub.status.idle":"2025-12-20T15:48:33.24718Z","shell.execute_reply.started":"2025-12-20T15:48:33.238761Z","shell.execute_reply":"2025-12-20T15:48:33.246269Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -------------------------------\n# 🔹 1️⃣ Copier la consommation actuelle\n# -------------------------------\ntrain[\"optimized_reading\"] = train[\"meter_reading\"].copy()\n\n# -------------------------------\n# 🔹 2️⃣ Règle 1 : éteindre clim/lumière si salle vide\n# -------------------------------\ntrain.loc[train[\"occupancy\"]==0, \"optimized_reading\"] *= 0.5\n# On simule qu’on économise 50% si salle vide\n\n# -------------------------------\n# 🔹 3️⃣ Règle 2 : réduire consommation si température confortable\n# Température confortable : 20°C à 24°C\n# -------------------------------\nmask_comfort = (train[\"air_temperature\"] >= 20) & (train[\"air_temperature\"] <= 24)\ntrain.loc[mask_comfort, \"optimized_reading\"] *= 0.8\n# On simule 20% économie si température confortable\n\n# -------------------------------\n# 🔹 4️⃣ Calcul KPI consommation optimisée\n# -------------------------------\noptimized_total = train[\"optimized_reading\"].sum()\noptimized_saving = total_kwh - optimized_total\noptimized_saving_pct = (optimized_saving / total_kwh) * 100\n\nprint(f\"Consommation totale avant optimisation : {total_kwh:.2f} kWh\")\nprint(f\"Consommation totale après optimisation : {optimized_total:.2f} kWh\")\nprint(f\"Économie potentielle : {optimized_saving_pct:.2f} %\")\n\n# -------------------------------\n# 🔹 5️⃣ Visualisation comparaison\n# -------------------------------\nplt.figure(figsize=(12,5))\nplt.plot(train[\"timestamp\"], train[\"meter_reading\"], label=\"Consommation réelle\")\nplt.plot(train[\"timestamp\"], train[\"optimized_reading\"], label=\"Consommation optimisée\", alpha=0.8)\nplt.scatter(\n    train.loc[train[\"waste\"]==1, \"timestamp\"],\n    train.loc[train[\"waste\"]==1, \"meter_reading\"],\n    color=\"red\", s=10, label=\"Gaspillage détecté\"\n)\nplt.legend()\nplt.title(\"Optimisation automatique de la consommation énergétique\")\nplt.xlabel(\"Temps\")\nplt.ylabel(\"kWh\")\nplt.show()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T15:50:28.003161Z","iopub.execute_input":"2025-12-20T15:50:28.003488Z","iopub.status.idle":"2025-12-20T15:50:28.781027Z","shell.execute_reply.started":"2025-12-20T15:50:28.003465Z","shell.execute_reply":"2025-12-20T15:50:28.779767Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Sauvegarder le DataFrame préparé pour le dashboard\ntrain.to_csv(\"/kaggle/working/train_prepared.csv\", index=False)\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-20T16:13:40.307929Z","iopub.execute_input":"2025-12-20T16:13:40.308223Z","iopub.status.idle":"2025-12-20T16:13:40.563503Z","shell.execute_reply.started":"2025-12-20T16:13:40.308203Z","shell.execute_reply":"2025-12-20T16:13:40.562244Z"}},"outputs":[],"execution_count":null}]}