{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "initial_id",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hit:1 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64  InRelease\n",
      "Hit:2 http://archive.ubuntu.com/ubuntu jammy InRelease                         \n",
      "Hit:3 http://security.ubuntu.com/ubuntu jammy-security InRelease               \n",
      "Hit:4 http://archive.ubuntu.com/ubuntu jammy-updates InRelease\n",
      "Hit:5 http://archive.ubuntu.com/ubuntu jammy-backports InRelease\n",
      "Reading package lists... Done\n",
      "Reading package lists... Done\n",
      "Building dependency tree... Done\n",
      "Reading state information... Done\n",
      "graphviz is already the newest version (2.42.2-6ubuntu0.1).\n",
      "0 upgraded, 0 newly installed, 0 to remove and 125 not upgraded.\n",
      "Requirement already satisfied: tensorflow in /usr/local/lib/python3.11/dist-packages (2.14.0)\n",
      "Requirement already satisfied: absl-py>=1.0.0 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (2.0.0)\n",
      "Requirement already satisfied: astunparse>=1.6.0 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (1.6.3)\n",
      "Requirement already satisfied: flatbuffers>=23.5.26 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (23.5.26)\n",
      "Requirement already satisfied: gast!=0.5.0,!=0.5.1,!=0.5.2,>=0.2.1 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (0.5.4)\n",
      "Requirement already satisfied: google-pasta>=0.1.1 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (0.2.0)\n",
      "Requirement already satisfied: h5py>=2.9.0 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (3.9.0)\n",
      "Requirement already satisfied: libclang>=13.0.0 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (16.0.6)\n",
      "Requirement already satisfied: ml-dtypes==0.2.0 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (0.2.0)\n",
      "Requirement already satisfied: numpy>=1.23.5 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (1.26.0)\n",
      "Requirement already satisfied: opt-einsum>=2.3.2 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (3.3.0)\n",
      "Requirement already satisfied: packaging in /usr/local/lib/python3.11/dist-packages (from tensorflow) (23.1)\n",
      "Requirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.20.3 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (4.24.3)\n",
      "Requirement already satisfied: setuptools in /usr/local/lib/python3.11/dist-packages (from tensorflow) (68.2.2)\n",
      "Requirement already satisfied: six>=1.12.0 in /usr/lib/python3/dist-packages (from tensorflow) (1.16.0)\n",
      "Requirement already satisfied: termcolor>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (2.3.0)\n",
      "Requirement already satisfied: typing-extensions>=3.6.6 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (4.8.0)\n",
      "Requirement already satisfied: wrapt<1.15,>=1.11.0 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (1.14.1)\n",
      "Requirement already satisfied: tensorflow-io-gcs-filesystem>=0.23.1 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (0.37.1)\n",
      "Requirement already satisfied: grpcio<2.0,>=1.24.3 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (1.58.0)\n",
      "Requirement already satisfied: tensorboard<2.15,>=2.14 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (2.14.0)\n",
      "Requirement already satisfied: tensorflow-estimator<2.15,>=2.14.0 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (2.14.0)\n",
      "Requirement already satisfied: keras<2.15,>=2.14.0 in /usr/local/lib/python3.11/dist-packages (from tensorflow) (2.14.0)\n",
      "Requirement already satisfied: wheel<1.0,>=0.23.0 in /usr/local/lib/python3.11/dist-packages (from astunparse>=1.6.0->tensorflow) (0.41.2)\n",
      "Requirement already satisfied: google-auth<3,>=1.6.3 in /usr/local/lib/python3.11/dist-packages (from tensorboard<2.15,>=2.14->tensorflow) (2.23.1)\n",
      "Requirement already satisfied: google-auth-oauthlib<1.1,>=0.5 in /usr/local/lib/python3.11/dist-packages (from tensorboard<2.15,>=2.14->tensorflow) (1.0.0)\n",
      "Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.11/dist-packages (from tensorboard<2.15,>=2.14->tensorflow) (3.4.4)\n",
      "Requirement already satisfied: requests<3,>=2.21.0 in /usr/local/lib/python3.11/dist-packages (from tensorboard<2.15,>=2.14->tensorflow) (2.31.0)\n",
      "Requirement already satisfied: tensorboard-data-server<0.8.0,>=0.7.0 in /usr/local/lib/python3.11/dist-packages (from tensorboard<2.15,>=2.14->tensorflow) (0.7.1)\n",
      "Requirement already satisfied: werkzeug>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from tensorboard<2.15,>=2.14->tensorflow) (2.3.7)\n",
      "Requirement already satisfied: cachetools<6.0,>=2.0.0 in /usr/local/lib/python3.11/dist-packages (from google-auth<3,>=1.6.3->tensorboard<2.15,>=2.14->tensorflow) (5.3.1)\n",
      "Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.11/dist-packages (from google-auth<3,>=1.6.3->tensorboard<2.15,>=2.14->tensorflow) (0.3.0)\n",
      "Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.11/dist-packages (from google-auth<3,>=1.6.3->tensorboard<2.15,>=2.14->tensorflow) (4.9)\n",
      "Requirement already satisfied: urllib3>=2.0.5 in /usr/local/lib/python3.11/dist-packages (from google-auth<3,>=1.6.3->tensorboard<2.15,>=2.14->tensorflow) (2.0.5)\n",
      "Requirement already satisfied: requests-oauthlib>=0.7.0 in /usr/local/lib/python3.11/dist-packages (from google-auth-oauthlib<1.1,>=0.5->tensorboard<2.15,>=2.14->tensorflow) (1.3.1)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests<3,>=2.21.0->tensorboard<2.15,>=2.14->tensorflow) (3.2.0)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests<3,>=2.21.0->tensorboard<2.15,>=2.14->tensorflow) (3.4)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/dist-packages (from requests<3,>=2.21.0->tensorboard<2.15,>=2.14->tensorflow) (2023.7.22)\n",
      "Requirement already satisfied: MarkupSafe>=2.1.1 in /usr/local/lib/python3.11/dist-packages (from werkzeug>=1.0.1->tensorboard<2.15,>=2.14->tensorflow) (2.1.3)\n",
      "Requirement already satisfied: pyasn1<0.6.0,>=0.4.6 in /usr/local/lib/python3.11/dist-packages (from pyasn1-modules>=0.2.1->google-auth<3,>=1.6.3->tensorboard<2.15,>=2.14->tensorflow) (0.5.0)\n",
      "Requirement already satisfied: oauthlib>=3.0.0 in /usr/lib/python3/dist-packages (from requests-oauthlib>=0.7.0->google-auth-oauthlib<1.1,>=0.5->tensorboard<2.15,>=2.14->tensorflow) (3.2.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: numpy in /usr/local/lib/python3.11/dist-packages (1.26.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: pandas in /usr/local/lib/python3.11/dist-packages (2.2.3)\n",
      "Requirement already satisfied: numpy>=1.23.2 in /usr/local/lib/python3.11/dist-packages (from pandas) (1.26.0)\n",
      "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/dist-packages (from pandas) (2.8.2)\n",
      "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas) (2024.2)\n",
      "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas) (2024.2)\n",
      "Requirement already satisfied: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.8.2->pandas) (1.16.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: keras in /usr/local/lib/python3.11/dist-packages (2.14.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: scikit-learn in /usr/local/lib/python3.11/dist-packages (1.6.0)\n",
      "Requirement already satisfied: numpy>=1.19.5 in /usr/local/lib/python3.11/dist-packages (from scikit-learn) (1.26.0)\n",
      "Requirement already satisfied: scipy>=1.6.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn) (1.14.1)\n",
      "Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn) (1.4.2)\n",
      "Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn) (3.5.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: matplotlib in /usr/local/lib/python3.11/dist-packages (3.8.0)\n",
      "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (1.1.1)\n",
      "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (0.11.0)\n",
      "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (4.42.1)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (1.4.5)\n",
      "Requirement already satisfied: numpy<2,>=1.21 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (1.26.0)\n",
      "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (23.1)\n",
      "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (10.0.1)\n",
      "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (3.2.0)\n",
      "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (2.8.2)\n",
      "Requirement already satisfied: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: joblib in /usr/local/lib/python3.11/dist-packages (1.4.2)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: pyarrow in /usr/local/lib/python3.11/dist-packages (18.1.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: fastparquet in /usr/local/lib/python3.11/dist-packages (2024.11.0)\n",
      "Requirement already satisfied: pandas>=1.5.0 in /usr/local/lib/python3.11/dist-packages (from fastparquet) (2.2.3)\n",
      "Requirement already satisfied: numpy in /usr/local/lib/python3.11/dist-packages (from fastparquet) (1.26.0)\n",
      "Requirement already satisfied: cramjam>=2.3 in /usr/local/lib/python3.11/dist-packages (from fastparquet) (2.9.1)\n",
      "Requirement already satisfied: fsspec in /usr/local/lib/python3.11/dist-packages (from fastparquet) (2024.12.0)\n",
      "Requirement already satisfied: packaging in /usr/local/lib/python3.11/dist-packages (from fastparquet) (23.1)\n",
      "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.5.0->fastparquet) (2.8.2)\n",
      "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.5.0->fastparquet) (2024.2)\n",
      "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.5.0->fastparquet) (2024.2)\n",
      "Requirement already satisfied: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.8.2->pandas>=1.5.0->fastparquet) (1.16.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: scipy in /usr/local/lib/python3.11/dist-packages (1.14.1)\n",
      "Requirement already satisfied: numpy<2.3,>=1.23.5 in /usr/local/lib/python3.11/dist-packages (from scipy) (1.26.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: seaborn in /usr/local/lib/python3.11/dist-packages (0.13.2)\n",
      "Requirement already satisfied: numpy!=1.24.0,>=1.20 in /usr/local/lib/python3.11/dist-packages (from seaborn) (1.26.0)\n",
      "Requirement already satisfied: pandas>=1.2 in /usr/local/lib/python3.11/dist-packages (from seaborn) (2.2.3)\n",
      "Requirement already satisfied: matplotlib!=3.6.1,>=3.4 in /usr/local/lib/python3.11/dist-packages (from seaborn) (3.8.0)\n",
      "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (1.1.1)\n",
      "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (0.11.0)\n",
      "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (4.42.1)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (1.4.5)\n",
      "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (23.1)\n",
      "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (10.0.1)\n",
      "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (3.2.0)\n",
      "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (2.8.2)\n",
      "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.2->seaborn) (2024.2)\n",
      "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.2->seaborn) (2024.2)\n",
      "Requirement already satisfied: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.7->matplotlib!=3.6.1,>=3.4->seaborn) (1.16.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: tqdm in /usr/local/lib/python3.11/dist-packages (4.67.1)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: pydot in /usr/local/lib/python3.11/dist-packages (3.0.3)\n",
      "Requirement already satisfied: pyparsing>=3.0.9 in /usr/local/lib/python3.11/dist-packages (from pydot) (3.2.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: tensorflow-io in /usr/local/lib/python3.11/dist-packages (0.37.1)\n",
      "Requirement already satisfied: tensorflow-io-gcs-filesystem==0.37.1 in /usr/local/lib/python3.11/dist-packages (from tensorflow-io) (0.37.1)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: tensorflow-addons in /usr/local/lib/python3.11/dist-packages (0.23.0)\n",
      "Requirement already satisfied: packaging in /usr/local/lib/python3.11/dist-packages (from tensorflow-addons) (23.1)\n",
      "Requirement already satisfied: typeguard<3.0.0,>=2.7 in /usr/local/lib/python3.11/dist-packages (from tensorflow-addons) (2.13.3)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "!apt-get update\n",
    "!apt-get install graphviz -y\n",
    "\n",
    "!pip install tensorflow\n",
    "!pip install numpy\n",
    "!pip install pandas\n",
    "\n",
    "!pip install keras\n",
    "!pip install scikit-learn\n",
    "!pip install matplotlib\n",
    "!pip install joblib\n",
    "!pip install pyarrow\n",
    "!pip install fastparquet\n",
    "!pip install scipy\n",
    "!pip install seaborn\n",
    "!pip install tqdm\n",
    "!pip install pydot\n",
    "!pip install tensorflow-io\n",
    "!pip install tensorflow-addons"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a467d3f0dfd9beab",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-12-19 23:39:55.304410: E tensorflow/compiler/xla/stream_executor/cuda/cuda_dnn.cc:9342] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
      "2024-12-19 23:39:55.304484: E tensorflow/compiler/xla/stream_executor/cuda/cuda_fft.cc:609] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
      "2024-12-19 23:39:55.304521: E tensorflow/compiler/xla/stream_executor/cuda/cuda_blas.cc:1518] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
      "2024-12-19 23:39:55.314601: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n",
      "To enable the following instructions: AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Keras version: 2.14.0\n",
      "TensorFlow version: 2.14.0\n",
      "CUDA available: True\n",
      "GPU devices: [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]\n",
      "1 Physical GPUs, 1 Logical GPUs\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-12-19 23:39:58.323709: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1886] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 43086 MB memory:  -> device: 0, name: NVIDIA L40S, pci bus id: 0000:01:00.0, compute capability: 8.9\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import tensorflow as tf\n",
    "import keras\n",
    "\n",
    "# Print versions and system information\n",
    "print(f\"Keras version: {keras.__version__}\")\n",
    "print(f\"TensorFlow version: {tf.__version__}\")\n",
    "print(f\"CUDA available: {tf.test.is_built_with_cuda()}\")\n",
    "print(f\"GPU devices: {tf.config.list_physical_devices('GPU')}\")\n",
    "\n",
    "# GPU memory configuration\n",
    "gpus = tf.config.experimental.list_physical_devices('GPU')\n",
    "if gpus:\n",
    "    try:\n",
    "        for gpu in gpus:\n",
    "            tf.config.experimental.set_memory_growth(gpu, True)\n",
    "\n",
    "        logical_gpus = tf.config.experimental.list_logical_devices('GPU')\n",
    "        print(len(gpus), \"Physical GPUs,\", len(logical_gpus), \"Logical GPUs\")\n",
    "    except RuntimeError as e:\n",
    "        print(e)\n",
    "\n",
    "# Reduce TensorFlow logging verbosity\n",
    "os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'\n",
    "\n",
    "# Set global precision policy\n",
    "tf.keras.mixed_precision.set_global_policy('float32')\n",
    "\n",
    "# Uncomment to set seed for reproducibility\n",
    "#tf.random.set_seed(42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c0155cde4740b0a3",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.11/dist-packages/tensorflow_addons/utils/tfa_eol_msg.py:23: UserWarning: \n",
      "\n",
      "TensorFlow Addons (TFA) has ended development and introduction of new features.\n",
      "TFA has entered a minimal maintenance and release mode until a planned end of life in May 2024.\n",
      "Please modify downstream libraries to take dependencies from other repositories in our TensorFlow community (e.g. Keras, Keras-CV, and Keras-NLP). \n",
      "\n",
      "For more information see: https://github.com/tensorflow/addons/issues/2807 \n",
      "\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "from datetime import datetime\n",
    "import os\n",
    "from typing import List\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "import tensorflow_addons as tfa\n",
    "import joblib\n",
    "import re\n",
    "\n",
    "# Set random state value (None for non-deterministic behavior)\n",
    "random_state_value = None\n",
    "\n",
    "# Create execution timestamp for model versioning and logging\n",
    "execute_name = datetime.now().strftime(\"%Y-%m-%d_%H-%M\")\n",
    "\n",
    "# Define directory paths\n",
    "base_project_dir = './'\n",
    "data_dir = '../../sources/'\n",
    "models_project_dir = base_project_dir\n",
    "\n",
    "# Create required directories if they don't exist\n",
    "os.makedirs(base_project_dir, exist_ok=True)\n",
    "os.makedirs(models_project_dir, exist_ok=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "1347fb59-50cc-4aa8-b805-ca9403037af5",
   "metadata": {},
   "outputs": [],
   "source": [
    "def clean_column_name(name: str) -> str:\n",
    "    \"\"\"\n",
    "    Cleans column names by removing special characters and converting to snake_case with abbreviations.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    name : str\n",
    "        Column name to clean\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    str\n",
    "        Cleaned column name\n",
    "    \"\"\"\n",
    "    # Remove special characters\n",
    "    name = re.sub(r'[^a-zA-Z0-9\\s]', '', name)\n",
    "\n",
    "    # Convert to snake_case\n",
    "    name = name.lower().replace(' ', '_')\n",
    "\n",
    "    # Common abbreviations mapping\n",
    "    abbreviations = {\n",
    "        'production': 'prod',\n",
    "        'percentage': 'pct',\n",
    "        'hectare': 'ha',\n",
    "        'tonnes': 't',\n",
    "        'litres': 'l',\n",
    "        'minimum': 'min',\n",
    "        'maximum': 'max',\n",
    "        'average': 'avg'\n",
    "    }\n",
    "\n",
    "    for full, abbr in abbreviations.items():\n",
    "        name = name.replace(full, abbr)\n",
    "\n",
    "    return name\n",
    "\n",
    "\n",
    "def clean_column_names(df: pd.DataFrame) -> List[str]:\n",
    "    \"\"\"\n",
    "    Cleans all column names in a DataFrame.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    df : pd.DataFrame\n",
    "        DataFrame whose columns need cleaning\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    list\n",
    "        List of cleaned column names\n",
    "    \"\"\"\n",
    "    new_columns = []\n",
    "\n",
    "    for col in df.columns:\n",
    "        # Extract variety patterns using regex\n",
    "        varieties = re.findall(r'([a-z]+)_([a-z_]+)', col)\n",
    "        if varieties:\n",
    "            new_columns.append(f\"{varieties[0][0]}_{varieties[0][1]}\")\n",
    "        else:\n",
    "            new_columns.append(col)\n",
    "\n",
    "    return new_columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "4da1f1bb67343e3e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def save_plot(plt, title, output_dir=f'{base_project_dir}/{execute_name}_plots'):\n",
    "    os.makedirs(output_dir, exist_ok=True)\n",
    "    filename = \"\".join(x for x in title if x.isalnum() or x in [' ', '-', '_']).rstrip()\n",
    "    filename = filename.replace(' ', '_').lower()\n",
    "    filepath = os.path.join(output_dir, f\"{filename}.png\")\n",
    "    plt.savefig(filepath, bbox_inches='tight', dpi=300)\n",
    "    print(f\"Plot salvato come: {filepath}\")\n",
    "\n",
    "\n",
    "def encode_techniques(df, mapping_path=f'{data_dir}technique_mapping.joblib'):\n",
    "    if not os.path.exists(mapping_path):\n",
    "        raise FileNotFoundError(f\"Mapping not found at {mapping_path}. Run create_technique_mapping first.\")\n",
    "\n",
    "    technique_mapping = joblib.load(mapping_path)\n",
    "\n",
    "    tech_columns = [col for col in df.columns if col.endswith('_tech')]\n",
    "\n",
    "    # Mapping apply to all tech columns\n",
    "    for col in tech_columns:\n",
    "        df[col] = df[col].str.lower().map(technique_mapping).fillna(0).astype(int)\n",
    "\n",
    "    return df\n",
    "\n",
    "\n",
    "def decode_single_technique(technique_value, mapping_path=f'{data_dir}technique_mapping.joblib'):\n",
    "    if not os.path.exists(mapping_path):\n",
    "        raise FileNotFoundError(f\"Mapping not found at {mapping_path}\")\n",
    "\n",
    "    technique_mapping = joblib.load(mapping_path)\n",
    "    reverse_mapping = {v: k for k, v in technique_mapping.items()}\n",
    "    reverse_mapping[0] = ''\n",
    "\n",
    "    return reverse_mapping.get(technique_value, '')\n",
    "\n",
    "\n",
    "def prepare_comparison_data(simulated_data, olive_varieties):\n",
    "\n",
    "    df = simulated_data.copy()\n",
    "\n",
    "    df.columns = clean_column_names(df)\n",
    "    df = encode_techniques(df)\n",
    "\n",
    "    all_varieties = olive_varieties['Varietà di Olive'].unique()\n",
    "    varieties = [clean_column_name(variety) for variety in all_varieties]\n",
    "    comparison_data = []\n",
    "\n",
    "    for variety in varieties:\n",
    "        olive_prod_col = next((col for col in df.columns if col.startswith(f'{variety}_') and col.endswith('_olive_prod')), None)\n",
    "        oil_prod_col = next((col for col in df.columns if col.startswith(f'{variety}_') and col.endswith('_avg_oil_prod')), None)\n",
    "        tech_col = next((col for col in df.columns if col.startswith(f'{variety}_') and col.endswith('_tech')), None)\n",
    "        water_need_col = next((col for col in df.columns if col.startswith(f'{variety}_') and col.endswith('_water_need')), None)\n",
    "\n",
    "        if olive_prod_col and oil_prod_col and tech_col and water_need_col:\n",
    "            variety_data = df[[olive_prod_col, oil_prod_col, tech_col, water_need_col]]\n",
    "            variety_data = variety_data[variety_data[tech_col] != 0]  # Esclude le righe dove la tecnica è 0\n",
    "\n",
    "            if not variety_data.empty:\n",
    "                avg_olive_prod = pd.to_numeric(variety_data[olive_prod_col], errors='coerce').mean()\n",
    "                avg_oil_prod = pd.to_numeric(variety_data[oil_prod_col], errors='coerce').mean()\n",
    "                avg_water_need = pd.to_numeric(variety_data[water_need_col], errors='coerce').mean()\n",
    "                efficiency = avg_oil_prod / avg_olive_prod if avg_olive_prod > 0 else 0\n",
    "                water_efficiency = avg_oil_prod / avg_water_need if avg_water_need > 0 else 0\n",
    "\n",
    "                comparison_data.append({\n",
    "                    'Variety': variety,\n",
    "                    'Avg Olive Production (kg/ha)': avg_olive_prod,\n",
    "                    'Avg Oil Production (L/ha)': avg_oil_prod,\n",
    "                    'Avg Water Need (m³/ha)': avg_water_need,\n",
    "                    'Oil Efficiency (L/kg)': efficiency,\n",
    "                    'Water Efficiency (L oil/m³ water)': water_efficiency\n",
    "                })\n",
    "\n",
    "    return pd.DataFrame(comparison_data)\n",
    "\n",
    "\n",
    "def plot_variety_comparison(comparison_data, metric):\n",
    "    plt.figure(figsize=(12, 6))\n",
    "    bars = plt.bar(comparison_data['Variety'], comparison_data[metric])\n",
    "    plt.title(f'Comparison of {metric} across Olive Varieties')\n",
    "    plt.xlabel('Variety')\n",
    "    plt.ylabel(metric)\n",
    "    plt.xticks(rotation=45, ha='right')\n",
    "\n",
    "    for bar in bars:\n",
    "        height = bar.get_height()\n",
    "        plt.text(bar.get_x() + bar.get_width() / 2., height,\n",
    "                 f'{height:.2f}',\n",
    "                 ha='center', va='bottom')\n",
    "\n",
    "    plt.tight_layout()\n",
    "    plt.show()\n",
    "    save_plot(plt, f'variety_comparison_{metric.lower().replace(\" \", \"_\").replace(\"/\", \"_\").replace(\"(\", \"\").replace(\")\", \"\")}')\n",
    "    plt.close()\n",
    "\n",
    "\n",
    "def plot_efficiency_vs_production(comparison_data):\n",
    "    plt.figure(figsize=(10, 6))\n",
    "\n",
    "    plt.scatter(comparison_data['Avg Olive Production (kg/ha)'],\n",
    "                comparison_data['Oil Efficiency (L/kg)'],\n",
    "                s=100)\n",
    "\n",
    "    for i, row in comparison_data.iterrows():\n",
    "        plt.annotate(row['Variety'],\n",
    "                     (row['Avg Olive Production (kg/ha)'], row['Oil Efficiency (L/kg)']),\n",
    "                     xytext=(5, 5), textcoords='offset points')\n",
    "\n",
    "    plt.title('Oil Efficiency vs Olive Production by Variety')\n",
    "    plt.xlabel('Average Olive Production (kg/ha)')\n",
    "    plt.ylabel('Oil Efficiency (L oil / kg olives)')\n",
    "    plt.tight_layout()\n",
    "    save_plot(plt, 'efficiency_vs_production')\n",
    "    plt.close()\n",
    "\n",
    "\n",
    "def plot_water_efficiency_vs_production(comparison_data):\n",
    "    plt.figure(figsize=(10, 6))\n",
    "\n",
    "    plt.scatter(comparison_data['Avg Olive Production (kg/ha)'],\n",
    "                comparison_data['Water Efficiency (L oil/m³ water)'],\n",
    "                s=100)\n",
    "\n",
    "    for i, row in comparison_data.iterrows():\n",
    "        plt.annotate(row['Variety'],\n",
    "                     (row['Avg Olive Production (kg/ha)'], row['Water Efficiency (L oil/m³ water)']),\n",
    "                     xytext=(5, 5), textcoords='offset points')\n",
    "\n",
    "    plt.title('Water Efficiency vs Olive Production by Variety')\n",
    "    plt.xlabel('Average Olive Production (kg/ha)')\n",
    "    plt.ylabel('Water Efficiency (L oil / m³ water)')\n",
    "    plt.tight_layout()\n",
    "    plt.show()\n",
    "    save_plot(plt, 'water_efficiency_vs_production')\n",
    "    plt.close()\n",
    "\n",
    "\n",
    "def plot_water_need_vs_oil_production(comparison_data):\n",
    "    plt.figure(figsize=(10, 6))\n",
    "\n",
    "    plt.scatter(comparison_data['Avg Water Need (m³/ha)'],\n",
    "                comparison_data['Avg Oil Production (L/ha)'],\n",
    "                s=100)\n",
    "\n",
    "    for i, row in comparison_data.iterrows():\n",
    "        plt.annotate(row['Variety'],\n",
    "                     (row['Avg Water Need (m³/ha)'], row['Avg Oil Production (L/ha)']),\n",
    "                     xytext=(5, 5), textcoords='offset points')\n",
    "\n",
    "    plt.title('Oil Production vs Water Need by Variety')\n",
    "    plt.xlabel('Average Water Need (m³/ha)')\n",
    "    plt.ylabel('Average Oil Production (L/ha)')\n",
    "    plt.tight_layout()\n",
    "    plt.show()\n",
    "    save_plot(plt, 'water_need_vs_oil_production')\n",
    "    plt.close()\n",
    "\n",
    "\n",
    "def analyze_by_technique(simulated_data, olive_varieties):\n",
    "\n",
    "    df = simulated_data.copy()\n",
    "\n",
    "    df.columns = clean_column_names(df)\n",
    "    df = encode_techniques(df)\n",
    "    all_varieties = olive_varieties['Varietà di Olive'].unique()\n",
    "    varieties = [clean_column_name(variety) for variety in all_varieties]\n",
    "\n",
    "    technique_data = []\n",
    "\n",
    "    for variety in varieties:\n",
    "        olive_prod_col = next((col for col in df.columns if col.startswith(f'{variety}_') and col.endswith('_olive_prod')), None)\n",
    "        oil_prod_col = next((col for col in df.columns if col.startswith(f'{variety}_') and col.endswith('_avg_oil_prod')), None)\n",
    "        tech_col = next((col for col in df.columns if col.startswith(f'{variety}_') and col.endswith('_tech')), None)\n",
    "        water_need_col = next((col for col in df.columns if col.startswith(f'{variety}_') and col.endswith('_water_need')), None)\n",
    "\n",
    "        if olive_prod_col and oil_prod_col and tech_col and water_need_col:\n",
    "            variety_data = df[[olive_prod_col, oil_prod_col, tech_col, water_need_col]]\n",
    "            variety_data = variety_data[variety_data[tech_col] != 0]\n",
    "\n",
    "            if not variety_data.empty:\n",
    "                for tech in variety_data[tech_col].unique():\n",
    "                    tech_data = variety_data[variety_data[tech_col] == tech]\n",
    "\n",
    "                    avg_olive_prod = pd.to_numeric(tech_data[olive_prod_col], errors='coerce').mean()\n",
    "                    avg_oil_prod = pd.to_numeric(tech_data[oil_prod_col], errors='coerce').mean()\n",
    "                    avg_water_need = pd.to_numeric(tech_data[water_need_col], errors='coerce').mean()\n",
    "\n",
    "                    efficiency = avg_oil_prod / avg_olive_prod if avg_olive_prod > 0 else 0\n",
    "                    water_efficiency = avg_oil_prod / avg_water_need if avg_water_need > 0 else 0\n",
    "\n",
    "                    technique_data.append({\n",
    "                        'Variety': variety,\n",
    "                        'Technique': tech,\n",
    "                        'Technique String': decode_single_technique(tech),\n",
    "                        'Avg Olive Production (kg/ha)': avg_olive_prod,\n",
    "                        'Avg Oil Production (L/ha)': avg_oil_prod,\n",
    "                        'Avg Water Need (m³/ha)': avg_water_need,\n",
    "                        'Oil Efficiency (L/kg)': efficiency,\n",
    "                        'Water Efficiency (L oil/m³ water)': water_efficiency\n",
    "                    })\n",
    "\n",
    "    return pd.DataFrame(technique_data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "9aa4bf176c4affb9",
   "metadata": {},
   "outputs": [],
   "source": [
    "def calculate_real_error(model, test_data, test_targets, scaler_y):\n",
    "\n",
    "    predictions = model.predict(test_data)\n",
    "\n",
    "    # Denormalize predictions and target values\n",
    "    predictions_real = scaler_y.inverse_transform(predictions)\n",
    "    targets_real = scaler_y.inverse_transform(test_targets)\n",
    "\n",
    "    # Calculate percentage error for each target\n",
    "    percentage_errors = []\n",
    "    absolute_errors = []\n",
    "\n",
    "    for i in range(predictions_real.shape[1]):\n",
    "        mae = np.mean(np.abs(predictions_real[:, i] - targets_real[:, i]))\n",
    "        mape = np.mean(np.abs((predictions_real[:, i] - targets_real[:, i]) / targets_real[:, i])) * 100\n",
    "        percentage_errors.append(mape)\n",
    "        absolute_errors.append(mae)\n",
    "\n",
    "    target_names = ['olive_prod', 'min_oil_prod', 'max_oil_prod', 'avg_oil_prod', 'total_water_need']\n",
    "\n",
    "    print(\"\\nErrori per target:\")\n",
    "    print(\"-\" * 50)\n",
    "    for i, target in enumerate(target_names):\n",
    "        print(f\"{target}:\")\n",
    "        print(f\"MAE assoluto: {absolute_errors[i]:.2f}\")\n",
    "        print(f\"Errore percentuale medio: {percentage_errors[i]:.2f}%\")\n",
    "        print(f\"Precisione: {100 - percentage_errors[i]:.2f}%\")\n",
    "        print(\"-\" * 50)\n",
    "\n",
    "    return percentage_errors, absolute_errors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "b3ba2b96ba678389",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 73736 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plot salvato come: .//2024-12-19_23-39_plots/variety_comparison_avg_olive_production_kg_ha.png\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 67196 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plot salvato come: .//2024-12-19_23-39_plots/variety_comparison_avg_oil_production_l_ha.png\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 70344 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plot salvato come: .//2024-12-19_23-39_plots/variety_comparison_avg_water_need_m³_ha.png\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 56556 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plot salvato come: .//2024-12-19_23-39_plots/variety_comparison_oil_efficiency_l_kg.png\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 59960 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plot salvato come: .//2024-12-19_23-39_plots/variety_comparison_water_efficiency_l_oil_m³_water.png\n",
      "Plot salvato come: .//2024-12-19_23-39_plots/efficiency_vs_production.png\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 51404 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plot salvato come: .//2024-12-19_23-39_plots/water_efficiency_vs_production.png\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 51512 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plot salvato come: .//2024-12-19_23-39_plots/water_need_vs_oil_production.png\n",
      "               Variety  Technique Technique String  \\\n",
      "0   nocellara_delletna          2   superintensiva   \n",
      "1   nocellara_delletna          3     tradizionale   \n",
      "2   nocellara_delletna          1        intensiva   \n",
      "3              leccino          3     tradizionale   \n",
      "4              leccino          1        intensiva   \n",
      "5              leccino          2   superintensiva   \n",
      "6             frantoio          2   superintensiva   \n",
      "7             frantoio          1        intensiva   \n",
      "8             frantoio          3     tradizionale   \n",
      "9             coratina          3     tradizionale   \n",
      "10            coratina          1        intensiva   \n",
      "11            coratina          2   superintensiva   \n",
      "12           taggiasca          1        intensiva   \n",
      "13           taggiasca          2   superintensiva   \n",
      "14           taggiasca          3     tradizionale   \n",
      "15           pendolino          2   superintensiva   \n",
      "16           pendolino          3     tradizionale   \n",
      "17           pendolino          1        intensiva   \n",
      "18            moraiolo          3     tradizionale   \n",
      "19            moraiolo          2   superintensiva   \n",
      "20            moraiolo          1        intensiva   \n",
      "\n",
      "    Avg Olive Production (kg/ha)  Avg Oil Production (L/ha)  \\\n",
      "0                   17727.298661                3870.709391   \n",
      "1                    9563.406694                2088.211185   \n",
      "2                   13667.805614                2984.246320   \n",
      "3                   10938.684057                2149.430161   \n",
      "4                   16371.651842                3216.842318   \n",
      "5                   20544.147125                4037.062548   \n",
      "6                   24663.572247                6058.337502   \n",
      "7                   20516.024787                5039.266103   \n",
      "8                   13673.948225                3358.771782   \n",
      "9                   12299.616734                3155.538475   \n",
      "10                  16410.475160                4210.501916   \n",
      "11                  19156.162270                4914.756321   \n",
      "12                  10933.864174                2208.344627   \n",
      "13                  16408.233777                3314.030124   \n",
      "14                   6833.214251                1380.020941   \n",
      "15                  19153.020538                3450.403695   \n",
      "16                  10951.390291                1972.852549   \n",
      "17                  13704.478410                2468.577580   \n",
      "18                   8756.527000                1912.018469   \n",
      "19                  17789.470297                3884.014946   \n",
      "20                  13119.074364                2864.192536   \n",
      "\n",
      "    Avg Water Need (m³/ha)  Oil Efficiency (L/kg)  \\\n",
      "0             12131.560516               0.218347   \n",
      "1             12158.140744               0.218354   \n",
      "2             12163.565060               0.218341   \n",
      "3              9819.115536               0.196498   \n",
      "4              9801.126450               0.196489   \n",
      "5              9838.437036               0.196507   \n",
      "6             10989.828820               0.245639   \n",
      "7             10968.425693               0.245626   \n",
      "8             10965.353268               0.245633   \n",
      "9             13708.071663               0.256556   \n",
      "10            13715.117102               0.256574   \n",
      "11            13721.617765               0.256563   \n",
      "12             9953.737673               0.201973   \n",
      "13             9958.298782               0.201974   \n",
      "14             9950.943918               0.201958   \n",
      "15            10266.579633               0.180149   \n",
      "16            10277.884893               0.180146   \n",
      "17            10288.302212               0.180129   \n",
      "18            11992.446013               0.218354   \n",
      "19            11993.120349               0.218332   \n",
      "20            11980.845607               0.218323   \n",
      "\n",
      "    Water Efficiency (L oil/m³ water)  \n",
      "0                            0.319061  \n",
      "1                            0.171754  \n",
      "2                            0.245343  \n",
      "3                            0.218903  \n",
      "4                            0.328211  \n",
      "5                            0.410336  \n",
      "6                            0.551268  \n",
      "7                            0.459434  \n",
      "8                            0.306308  \n",
      "9                            0.230196  \n",
      "10                           0.306997  \n",
      "11                           0.358176  \n",
      "12                           0.221861  \n",
      "13                           0.332791  \n",
      "14                           0.138682  \n",
      "15                           0.336081  \n",
      "16                           0.191951  \n",
      "17                           0.239940  \n",
      "18                           0.159435  \n",
      "19                           0.323854  \n",
      "20                           0.239064  \n",
      "Comparison by Variety:\n",
      "                    Avg Olive Production (kg/ha)  Avg Oil Production (L/ha)  \\\n",
      "Variety                                                                       \n",
      "nocellara_delletna                  13661.848435                2983.023191   \n",
      "leccino                             15949.725702                3134.097415   \n",
      "frantoio                            19617.660163                4818.745399   \n",
      "coratina                            15957.184888                4094.052239   \n",
      "taggiasca                           11385.861672                2299.605028   \n",
      "pendolino                           14600.902596                2630.240053   \n",
      "moraiolo                            13223.690511                2887.178517   \n",
      "\n",
      "                    Avg Water Need (m³/ha)  Oil Efficiency (L/kg)  \\\n",
      "Variety                                                             \n",
      "nocellara_delletna            12151.058320               0.218347   \n",
      "leccino                        9819.553079               0.196499   \n",
      "frantoio                      10974.527808               0.245633   \n",
      "coratina                      13714.938951               0.256565   \n",
      "taggiasca                      9954.322217               0.201970   \n",
      "pendolino                     10277.592837               0.180142   \n",
      "moraiolo                      11988.799794               0.218334   \n",
      "\n",
      "                    Water Efficiency (L oil/m³ water)  \n",
      "Variety                                                \n",
      "nocellara_delletna                           0.245495  \n",
      "leccino                                      0.319169  \n",
      "frantoio                                     0.439085  \n",
      "coratina                                     0.298510  \n",
      "taggiasca                                    0.231016  \n",
      "pendolino                                    0.255920  \n",
      "moraiolo                                     0.240823  \n",
      "\n",
      "Best Varieties by Water Efficiency:\n",
      "              Variety  Avg Olive Production (kg/ha)  \\\n",
      "2            frantoio                  19617.660163   \n",
      "1             leccino                  15949.725702   \n",
      "3            coratina                  15957.184888   \n",
      "5           pendolino                  14600.902596   \n",
      "0  nocellara_delletna                  13661.848435   \n",
      "\n",
      "   Avg Oil Production (L/ha)  Avg Water Need (m³/ha)  Oil Efficiency (L/kg)  \\\n",
      "2                4818.745399            10974.527808               0.245633   \n",
      "1                3134.097415             9819.553079               0.196499   \n",
      "3                4094.052239            13714.938951               0.256565   \n",
      "5                2630.240053            10277.592837               0.180142   \n",
      "0                2983.023191            12151.058320               0.218347   \n",
      "\n",
      "   Water Efficiency (L oil/m³ water)  \n",
      "2                           0.439085  \n",
      "1                           0.319169  \n",
      "3                           0.298510  \n",
      "5                           0.255920  \n",
      "0                           0.245495  \n"
     ]
    }
   ],
   "source": [
    "simulated_data = pd.read_parquet(f\"{data_dir}olive_training_dataset.parquet\")\n",
    "olive_varieties = pd.read_parquet(f\"{data_dir}olive_varieties.parquet\")\n",
    "# Esecuzione dell'analisi\n",
    "comparison_data = prepare_comparison_data(simulated_data, olive_varieties)\n",
    "\n",
    "# Genera i grafici\n",
    "plot_variety_comparison(comparison_data, 'Avg Olive Production (kg/ha)')\n",
    "plot_variety_comparison(comparison_data, 'Avg Oil Production (L/ha)')\n",
    "plot_variety_comparison(comparison_data, 'Avg Water Need (m³/ha)')\n",
    "plot_variety_comparison(comparison_data, 'Oil Efficiency (L/kg)')\n",
    "plot_variety_comparison(comparison_data, 'Water Efficiency (L oil/m³ water)')\n",
    "plot_efficiency_vs_production(comparison_data)\n",
    "plot_water_efficiency_vs_production(comparison_data)\n",
    "plot_water_need_vs_oil_production(comparison_data)\n",
    "\n",
    "technique_data = analyze_by_technique(simulated_data, olive_varieties)\n",
    "\n",
    "print(technique_data)\n",
    "\n",
    "# Stampa un sommario statistico\n",
    "print(\"Comparison by Variety:\")\n",
    "print(comparison_data.set_index('Variety'))\n",
    "print(\"\\nBest Varieties by Water Efficiency:\")\n",
    "print(comparison_data.sort_values('Water Efficiency (L oil/m³ water)', ascending=False).head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "bbe87b415168368",
   "metadata": {},
   "outputs": [],
   "source": [
    "def prepare_transformer_data(df, olive_varieties_df):\n",
    "    # Crea una copia del DataFrame per evitare modifiche all'originale\n",
    "    df = df.copy()\n",
    "\n",
    "    # Definisci le feature\n",
    "    temporal_features = ['temp_mean', 'precip_sum', 'solar_energy_sum']\n",
    "    static_features = ['ha']  # Feature statiche base\n",
    "    target_features = ['olive_prod', 'min_oil_prod', 'max_oil_prod', 'avg_oil_prod', 'total_water_need']\n",
    "\n",
    "    # Ottieni le varietà pulite\n",
    "    all_varieties = olive_varieties_df['Varietà di Olive'].unique()\n",
    "    varieties = [clean_column_name(variety) for variety in all_varieties]\n",
    "\n",
    "    # Crea la struttura delle feature per ogni varietà\n",
    "    variety_features = [\n",
    "        'tech', 'pct', 'prod_t_ha', 'oil_prod_t_ha', 'oil_prod_l_ha',\n",
    "        'min_yield_pct', 'max_yield_pct', 'min_oil_prod_l_ha', 'max_oil_prod_l_ha',\n",
    "        'avg_oil_prod_l_ha', 'l_per_t', 'min_l_per_t', 'max_l_per_t', 'avg_l_per_t'\n",
    "    ]\n",
    "\n",
    "    # Prepara dizionari per le nuove colonne\n",
    "    new_columns = {}\n",
    "\n",
    "    # Prepara le feature per ogni varietà\n",
    "    for variety in varieties:\n",
    "        # Feature esistenti\n",
    "        for feature in variety_features:\n",
    "            col_name = f\"{variety}_{feature}\"\n",
    "            if col_name in df.columns:\n",
    "                if feature != 'tech':  # Non includere la colonna tech direttamente\n",
    "                    static_features.append(col_name)\n",
    "\n",
    "        # Feature binarie per le tecniche di coltivazione\n",
    "        for technique in ['tradizionale', 'intensiva', 'superintensiva']:\n",
    "            col_name = f\"{variety}_{technique}\"\n",
    "            new_columns[col_name] = df[f\"{variety}_tech\"].notna() & (\n",
    "                    df[f\"{variety}_tech\"].str.lower() == technique\n",
    "            ).fillna(False)\n",
    "            static_features.append(col_name)\n",
    "\n",
    "    # Aggiungi tutte le nuove colonne in una volta sola\n",
    "    df = pd.concat([df] + [pd.Series(v, name=k) for k, v in new_columns.items()], axis=1)\n",
    "\n",
    "    # Prepara X e y\n",
    "    X_temporal = df[temporal_features].values\n",
    "    X_static = df[static_features].values\n",
    "    y = df[target_features].values\n",
    "\n",
    "    print(f\"Dataset completo - Temporal: {X_temporal.shape}, Static: {X_static.shape}, Target: {y.shape}\")\n",
    "\n",
    "    # Split dei dati (usando indici casuali per una migliore distribuzione)\n",
    "    indices = np.random.permutation(len(X_temporal))\n",
    "    train_idx = int(len(indices) * 0.65)    # 65% training\n",
    "    val_idx = int(len(indices) * 0.85)      # 20% validation\n",
    "    # Il resto rimane 15% test\n",
    "\n",
    "    train_indices = indices[:train_idx]\n",
    "    val_indices = indices[train_idx:val_idx]\n",
    "    test_indices = indices[val_idx:]\n",
    "\n",
    "    # Split dei dati\n",
    "    X_temporal_train = X_temporal[train_indices]\n",
    "    X_temporal_val = X_temporal[val_indices]\n",
    "    X_temporal_test = X_temporal[test_indices]\n",
    "\n",
    "    X_static_train = X_static[train_indices]\n",
    "    X_static_val = X_static[val_indices]\n",
    "    X_static_test = X_static[test_indices]\n",
    "\n",
    "    y_train = y[train_indices]\n",
    "    y_val = y[val_indices]\n",
    "    y_test = y[test_indices]\n",
    "\n",
    "    # Standardizzazione\n",
    "    scaler_temporal = StandardScaler()\n",
    "    scaler_static = StandardScaler()\n",
    "    scaler_y = StandardScaler()\n",
    "\n",
    "    # Standardizzazione dei dati\n",
    "    X_temporal_train = scaler_temporal.fit_transform(X_temporal_train)\n",
    "    X_temporal_val = scaler_temporal.transform(X_temporal_val)\n",
    "    X_temporal_test = scaler_temporal.transform(X_temporal_test)\n",
    "\n",
    "    X_static_train = scaler_static.fit_transform(X_static_train)\n",
    "    X_static_val = scaler_static.transform(X_static_val)\n",
    "    X_static_test = scaler_static.transform(X_static_test)\n",
    "\n",
    "    y_train = scaler_y.fit_transform(y_train)\n",
    "    y_val = scaler_y.transform(y_val)\n",
    "    y_test = scaler_y.transform(y_test)\n",
    "\n",
    "    print(\"\\nShape dopo lo split e standardizzazione:\")\n",
    "    print(f\"Train - Temporal: {X_temporal_train.shape}, Static: {X_static_train.shape}, Target: {y_train.shape}\")\n",
    "    print(f\"Val - Temporal: {X_temporal_val.shape}, Static: {X_static_val.shape}, Target: {y_val.shape}\")\n",
    "    print(f\"Test - Temporal: {X_temporal_test.shape}, Static: {X_static_test.shape}, Target: {y_test.shape}\")\n",
    "\n",
    "    # Reshape per il transformer (aggiunge la dimensione del sequence length = 1)\n",
    "    X_temporal_train = X_temporal_train.reshape(X_temporal_train.shape[0], 1, -1)\n",
    "    X_temporal_val = X_temporal_val.reshape(X_temporal_val.shape[0], 1, -1)\n",
    "    X_temporal_test = X_temporal_test.reshape(X_temporal_test.shape[0], 1, -1)\n",
    "\n",
    "    # Prepara i dizionari di input\n",
    "    train_data = {'temporal': X_temporal_train, 'static': X_static_train}\n",
    "    val_data = {'temporal': X_temporal_val, 'static': X_static_val}\n",
    "    test_data = {'temporal': X_temporal_test, 'static': X_static_test}\n",
    "\n",
    "    # Salva gli scaler\n",
    "    joblib.dump(scaler_temporal, os.path.join(base_project_dir, f'{execute_name}_scaler_temporal.joblib'))\n",
    "    joblib.dump(scaler_static, os.path.join(base_project_dir, f'{execute_name}_scaler_static.joblib'))\n",
    "    joblib.dump(scaler_y, os.path.join(base_project_dir, f'{execute_name}_scaler_y.joblib'))\n",
    "\n",
    "    return (train_data, y_train), (val_data, y_val), (test_data, y_test), (scaler_temporal, scaler_static, scaler_y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "9c4d5f0f3fafdc2d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset completo - Temporal: (4080000, 3), Static: (4080000, 113), Target: (4080000, 5)\n",
      "\n",
      "Shape dopo lo split e standardizzazione:\n",
      "Train - Temporal: (2652000, 3), Static: (2652000, 113), Target: (2652000, 5)\n",
      "Val - Temporal: (816000, 3), Static: (816000, 113), Target: (816000, 5)\n",
      "Test - Temporal: (612000, 3), Static: (612000, 113), Target: (612000, 5)\n",
      "Temporal data shape: (2652000, 1, 3)\n",
      "Static data shape: (2652000, 113)\n",
      "Target shape: (2652000, 5)\n"
     ]
    }
   ],
   "source": [
    "simulated_data = pd.read_parquet(f\"{data_dir}olive_training_dataset.parquet\")\n",
    "olive_varieties = pd.read_parquet(f\"{data_dir}olive_varieties.parquet\")\n",
    "\n",
    "(train_data, train_targets), (val_data, val_targets), (test_data, test_targets), scalers = prepare_transformer_data(simulated_data, olive_varieties)\n",
    "\n",
    "scaler_temporal, scaler_static, scaler_y = scalers\n",
    "\n",
    "print(\"Temporal data shape:\", train_data['temporal'].shape)\n",
    "print(\"Static data shape:\", train_data['static'].shape)\n",
    "print(\"Target shape:\", train_targets.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "604c952c7195f40c",
   "metadata": {},
   "outputs": [],
   "source": [
    "@keras.saving.register_keras_serializable()\n",
    "class DataAugmentation(tf.keras.layers.Layer):\n",
    "    \"\"\"Custom layer per l'augmentation dei dati\"\"\"\n",
    "\n",
    "    def __init__(self, noise_stddev=0.03, **kwargs):\n",
    "        super().__init__(**kwargs)\n",
    "        self.noise_stddev = noise_stddev\n",
    "\n",
    "    def call(self, inputs, training=None):\n",
    "        if training:\n",
    "            return inputs + tf.random.normal(\n",
    "                shape=tf.shape(inputs),\n",
    "                mean=0.0,\n",
    "                stddev=self.noise_stddev\n",
    "            )\n",
    "        return inputs\n",
    "\n",
    "    def get_config(self):\n",
    "        config = super().get_config()\n",
    "        config.update({\"noise_stddev\": self.noise_stddev})\n",
    "        return config\n",
    "\n",
    "\n",
    "@keras.saving.register_keras_serializable()\n",
    "class PositionalEncoding(tf.keras.layers.Layer):\n",
    "    \"\"\"Custom layer per l'encoding posizionale\"\"\"\n",
    "\n",
    "    def __init__(self, d_model, **kwargs):\n",
    "        super().__init__(**kwargs)\n",
    "        self.d_model = d_model\n",
    "\n",
    "    def build(self, input_shape):\n",
    "        _, seq_length, _ = input_shape\n",
    "\n",
    "        # Crea la matrice di encoding posizionale\n",
    "        position = tf.range(seq_length, dtype=tf.float32)[:, tf.newaxis]\n",
    "        div_term = tf.exp(\n",
    "            tf.range(0, self.d_model, 2, dtype=tf.float32) *\n",
    "            (-tf.math.log(10000.0) / self.d_model)\n",
    "        )\n",
    "\n",
    "        # Calcola sin e cos\n",
    "        pos_encoding = tf.zeros((1, seq_length, self.d_model))\n",
    "        pos_encoding_even = tf.sin(position * div_term)\n",
    "        pos_encoding_odd = tf.cos(position * div_term)\n",
    "\n",
    "        # Assegna i valori alle posizioni pari e dispari\n",
    "        pos_encoding = tf.concat(\n",
    "            [tf.expand_dims(pos_encoding_even, -1),\n",
    "             tf.expand_dims(pos_encoding_odd, -1)],\n",
    "            axis=-1\n",
    "        )\n",
    "        pos_encoding = tf.reshape(pos_encoding, (1, seq_length, -1))\n",
    "        pos_encoding = pos_encoding[:, :, :self.d_model]\n",
    "\n",
    "        # Salva l'encoding come peso non trainabile\n",
    "        self.pos_encoding = self.add_weight(\n",
    "            shape=(1, seq_length, self.d_model),\n",
    "            initializer=tf.keras.initializers.Constant(pos_encoding),\n",
    "            trainable=False,\n",
    "            name='positional_encoding'\n",
    "        )\n",
    "\n",
    "        super().build(input_shape)\n",
    "\n",
    "    def call(self, inputs):\n",
    "        # Broadcast l'encoding posizionale sul batch\n",
    "        batch_size = tf.shape(inputs)[0]\n",
    "        pos_encoding_tiled = tf.tile(self.pos_encoding, [batch_size, 1, 1])\n",
    "        return inputs + pos_encoding_tiled\n",
    "\n",
    "    def get_config(self):\n",
    "        config = super().get_config()\n",
    "        config.update({\"d_model\": self.d_model})\n",
    "        return config\n",
    "\n",
    "\n",
    "@keras.saving.register_keras_serializable()\n",
    "class WarmUpLearningRateSchedule(tf.keras.optimizers.schedules.LearningRateSchedule):\n",
    "    \"\"\"Custom learning rate schedule with linear warmup and exponential decay.\"\"\"\n",
    "\n",
    "    def __init__(self, initial_learning_rate=1e-3, warmup_steps=500, decay_steps=5000):\n",
    "        super().__init__()\n",
    "        self.initial_learning_rate = initial_learning_rate\n",
    "        self.warmup_steps = warmup_steps\n",
    "        self.decay_steps = decay_steps\n",
    "\n",
    "    def __call__(self, step):\n",
    "        warmup_pct = tf.cast(step, tf.float32) / self.warmup_steps\n",
    "        warmup_lr = self.initial_learning_rate * warmup_pct\n",
    "        decay_factor = tf.pow(0.1, tf.cast(step, tf.float32) / self.decay_steps)\n",
    "        decayed_lr = self.initial_learning_rate * decay_factor\n",
    "        return tf.where(step < self.warmup_steps, warmup_lr, decayed_lr)\n",
    "\n",
    "    def get_config(self):\n",
    "        return {\n",
    "            'initial_learning_rate': self.initial_learning_rate,\n",
    "            'warmup_steps': self.warmup_steps,\n",
    "            'decay_steps': self.decay_steps\n",
    "        }\n",
    "\n",
    "\n",
    "def create_olive_oil_transformer(temporal_shape, static_shape, num_outputs,\n",
    "                                 d_model=128, num_heads=8, ff_dim=256,\n",
    "                                 num_transformer_blocks=4, mlp_units=None,\n",
    "                                 dropout=0.2):\n",
    "    if mlp_units is None:\n",
    "        mlp_units = [256, 128, 64]\n",
    "\n",
    "    temporal_input = tf.keras.layers.Input(shape=temporal_shape, name='temporal')\n",
    "    static_input = tf.keras.layers.Input(shape=static_shape, name='static')\n",
    "\n",
    "    # === TEMPORAL PATH ===\n",
    "    x = tf.keras.layers.LayerNormalization(epsilon=1e-6)(temporal_input)\n",
    "    x = DataAugmentation()(x)\n",
    "\n",
    "    # Temporal projection con dimensione aumentata per compensare la sequenza corta\n",
    "    x = tf.keras.layers.Dense(\n",
    "        d_model,\n",
    "        activation='swish',\n",
    "        kernel_regularizer=tf.keras.regularizers.l2(1e-5)\n",
    "    )(x)\n",
    "    x = tf.keras.layers.Dropout(dropout)(x)\n",
    "\n",
    "    # Additional feature extraction prima del transformer\n",
    "    x = tf.keras.layers.Dense(\n",
    "        d_model * 2,\n",
    "        activation='swish',\n",
    "        kernel_regularizer=tf.keras.regularizers.l2(1e-5)\n",
    "    )(x)\n",
    "\n",
    "    x = PositionalEncoding(d_model * 2)(x)\n",
    "\n",
    "    skip_connection = x\n",
    "    for _ in range(num_transformer_blocks):\n",
    "        # Multi-head self-attention con più heads per compensare la sequenza corta\n",
    "        attention_output = tf.keras.layers.MultiHeadAttention(\n",
    "            num_heads=num_heads * 2,\n",
    "            key_dim=d_model // num_heads,\n",
    "            value_dim=d_model // num_heads\n",
    "        )(x, x)\n",
    "        attention_output = tf.keras.layers.Dropout(dropout)(attention_output)\n",
    "\n",
    "        # Residual connection con gating mechanism\n",
    "        gate = tf.keras.layers.Dense(d_model * 2, activation='sigmoid')(x)\n",
    "        x = x + gate * attention_output\n",
    "        x = tf.keras.layers.LayerNormalization(epsilon=1e-6)(x)\n",
    "\n",
    "        # Feed-forward network potenziato\n",
    "        ffn = tf.keras.Sequential([\n",
    "            tf.keras.layers.Dense(ff_dim * 2, activation=\"swish\"),  # Raddoppiato\n",
    "            tf.keras.layers.Dropout(dropout),\n",
    "            tf.keras.layers.Dense(ff_dim, activation=\"swish\"),\n",
    "            tf.keras.layers.Dropout(dropout),\n",
    "            tf.keras.layers.Dense(d_model * 2)\n",
    "        ])\n",
    "        ffn_output = ffn(x)\n",
    "\n",
    "        # Gated residual connection\n",
    "        gate = tf.keras.layers.Dense(d_model * 2, activation='sigmoid')(x)\n",
    "        x = x + gate * ffn_output\n",
    "        x = tf.keras.layers.LayerNormalization(epsilon=1e-6)(x)\n",
    "\n",
    "    # Global feature attention\n",
    "    x = tf.keras.layers.MultiHeadAttention(\n",
    "        num_heads=num_heads,\n",
    "        key_dim=d_model // num_heads\n",
    "    )(x, x)\n",
    "\n",
    "    # Feature pooling\n",
    "    x = tf.keras.layers.GlobalAveragePooling1D()(x)\n",
    "\n",
    "    # === STATIC PATH ===\n",
    "    s = tf.keras.layers.LayerNormalization(epsilon=1e-6)(static_input)\n",
    "    for units in [512, 256, 128]:  # Aumentate le dimensioni\n",
    "        s = tf.keras.layers.Dense(\n",
    "            units,\n",
    "            activation='swish',\n",
    "            kernel_regularizer=tf.keras.regularizers.l2(1e-5)\n",
    "        )(s)\n",
    "        s = tf.keras.layers.BatchNormalization()(s)\n",
    "        s = tf.keras.layers.Dropout(dropout)(s)\n",
    "\n",
    "\n",
    "    # === FEATURE FUSION con attention ===\n",
    "    # Project features to same dimensionality\n",
    "    x = tf.keras.layers.Dense(256)(x)\n",
    "    s = tf.keras.layers.Dense(256)(s)\n",
    "\n",
    "    # Cross-attention between temporal and static features\n",
    "    combined = tf.keras.layers.Concatenate()([x, s])\n",
    "    combined = tf.keras.layers.Dense(256, activation='swish')(combined)\n",
    "\n",
    "    # MLP head with residual connections\n",
    "    for units in mlp_units:\n",
    "        skip = combined\n",
    "        combined = tf.keras.layers.BatchNormalization()(combined)\n",
    "        combined = tf.keras.layers.Dense(units, activation=\"swish\")(combined)\n",
    "        combined = tf.keras.layers.Dropout(dropout)(combined)\n",
    "        if units == skip.shape[-1]:  # Se le dimensioni combaciano\n",
    "            combined = combined + skip\n",
    "\n",
    "    # Apply final normalization to output\n",
    "    outputs = tf.keras.layers.BatchNormalization()(combined)\n",
    "    outputs = tf.keras.layers.Dense(\n",
    "        num_outputs,\n",
    "        activation='linear',\n",
    "        kernel_regularizer=tf.keras.regularizers.l2(1e-5)\n",
    "    )(outputs)\n",
    "\n",
    "    # Create model\n",
    "    model = tf.keras.Model(\n",
    "        inputs={'temporal': temporal_input, 'static': static_input},\n",
    "        outputs=outputs,\n",
    "        name='OilTransformer'\n",
    "    )\n",
    "\n",
    "    return model\n",
    "\n",
    "\n",
    "def create_transformer_callbacks(target_names, val_data, val_targets):\n",
    "    \"\"\"\n",
    "    Crea i callbacks per il training del modello single-step.\n",
    "    \"\"\"\n",
    "    class TargetSpecificMetric(tf.keras.callbacks.Callback):\n",
    "        def __init__(self, validation_data, target_names):\n",
    "            super().__init__()\n",
    "            self.validation_data = validation_data\n",
    "            self.target_names = target_names\n",
    "            self.best_metrics = {name: float('inf') for name in target_names}\n",
    "    \n",
    "        def on_epoch_end(self, epoch, logs=None):\n",
    "            logs = logs or {}\n",
    "            \n",
    "            # Esegui il calcolo solo ogni 5 epoche\n",
    "            if epoch % 5 == 0:\n",
    "                x_val, y_val = self.validation_data\n",
    "                y_pred = self.model.predict(x_val, verbose=0)\n",
    "    \n",
    "                # Calcola e logga le metriche per ogni target\n",
    "                for i, name in enumerate(self.target_names):\n",
    "                    mae = np.mean(np.abs(y_val[:, i] - y_pred[:, i]))\n",
    "                    mape = np.mean(np.abs((y_val[:, i] - y_pred[:, i]) / np.clip(np.abs(y_val[:, i]), 1e-7, None))) * 100\n",
    "                    logs[f'val_{name}_mae'] = mae\n",
    "                    logs[f'val_{name}_mape'] = mape\n",
    "    \n",
    "                    # Traccia i migliori risultati\n",
    "                    if mae < self.best_metrics[name]:\n",
    "                        self.best_metrics[name] = mae\n",
    "                        logs[f'best_{name}_mae'] = mae\n",
    "\n",
    "\n",
    "    callbacks = [\n",
    "        # Early Stopping ottimizzato\n",
    "        tf.keras.callbacks.EarlyStopping(\n",
    "            monitor='val_loss',\n",
    "            patience=25,  # Aumentato per dare più chance al modello\n",
    "            restore_best_weights=True,\n",
    "            min_delta=0.0001,  # Più sensibile ai miglioramenti\n",
    "            mode='min'\n",
    "        ),\n",
    "\n",
    "        # Model Checkpoint con monitoraggio multiplo\n",
    "        tf.keras.callbacks.ModelCheckpoint(\n",
    "            filepath=f'{execute_name}_best_oil_model.h5',\n",
    "            monitor='val_loss',\n",
    "            save_best_only=True,\n",
    "            mode='min',\n",
    "            save_weights_only=True\n",
    "        ),\n",
    "\n",
    "        # Metric per target specifici\n",
    "        TargetSpecificMetric(\n",
    "            validation_data=(val_data, val_targets),\n",
    "            target_names=target_names\n",
    "        ),\n",
    "\n",
    "        # LR reduction ottimizzato per single-step\n",
    "        tf.keras.callbacks.ReduceLROnPlateau(\n",
    "            monitor='val_loss',\n",
    "            factor=0.2,  # Riduzione più aggressiva\n",
    "            patience=15,\n",
    "            min_lr=1e-7,\n",
    "            verbose=1,\n",
    "            cooldown=5  # Periodo di cool-down per stabilizzazione\n",
    "        ),\n",
    "\n",
    "        # TensorBoard con più metriche\n",
    "        tf.keras.callbacks.TensorBoard(\n",
    "            log_dir=f'./logs_{execute_name}',\n",
    "            histogram_freq=1,\n",
    "            write_graph=True,\n",
    "            write_images=True,\n",
    "            update_freq='epoch',\n",
    "            profile_batch='500,520'  # Profile per ottimizzazione\n",
    "        )\n",
    "    ]\n",
    "\n",
    "    return callbacks\n",
    "\n",
    "def compile_model(model, learning_rate=5e-4):  # Learning rate ridotto\n",
    "    \"\"\"\n",
    "    Compila il modello con ottimizzazioni per single-step.\n",
    "    \"\"\"\n",
    "    lr_schedule = WarmUpLearningRateSchedule(\n",
    "        initial_learning_rate=learning_rate,\n",
    "        warmup_steps=1000,  # Aumentato per stabilità\n",
    "        decay_steps=7000    # Aumentato per permettere più esplorazione\n",
    "    )\n",
    "\n",
    "    @keras.saving.register_keras_serializable()\n",
    "    def weighted_huber_loss(y_true, y_pred):\n",
    "        # Pesi per diversi output\n",
    "        weights = tf.constant([1.0, 0.8, 0.8, 1.0, 0.6], dtype=tf.float32)\n",
    "        huber = tf.keras.losses.Huber(delta=1.0)\n",
    "        loss = huber(y_true, y_pred)\n",
    "        weighted_loss = tf.reduce_mean(loss * weights)\n",
    "        return weighted_loss\n",
    "\n",
    "    model.compile(\n",
    "        optimizer=tf.keras.optimizers.AdamW(\n",
    "            learning_rate=lr_schedule,\n",
    "            weight_decay=0.01,\n",
    "            clipnorm=1.0,  # Gradient clipping\n",
    "            epsilon=1e-7    # Aumentato per stabilità numerica\n",
    "        ),\n",
    "        loss=weighted_huber_loss,\n",
    "        metrics=['mae', 'mape']\n",
    "    )\n",
    "\n",
    "    return model\n",
    "\n",
    "def setup_transformer_training(train_data, train_targets, val_data, val_targets):\n",
    "    \"\"\"\n",
    "    Configura il single-step transformer.\n",
    "    \"\"\"\n",
    "    # Estrai le shape dai dati\n",
    "    temporal_shape = (1, train_data['temporal'].shape[2])\n",
    "    static_shape = (train_data['static'].shape[1],)\n",
    "    num_outputs = train_targets.shape[1]\n",
    "\n",
    "    print(f\"Shape rilevate:\")\n",
    "    print(f\"- Temporal shape: {temporal_shape}\")\n",
    "    print(f\"- Static shape: {static_shape}\")\n",
    "    print(f\"- Numero di output: {num_outputs}\")\n",
    "\n",
    "    target_names = ['olive_prod', 'min_oil_prod', 'max_oil_prod', 'avg_oil_prod', 'total_water_need']\n",
    "\n",
    "    assert len(target_names) == num_outputs, \\\n",
    "        f\"Il numero di target names ({len(target_names)}) non corrisponde al numero di output ({num_outputs})\"\n",
    "\n",
    "    # Crea il modello con il nuovo transformer\n",
    "    model = create_olive_oil_transformer(\n",
    "        temporal_shape=temporal_shape,\n",
    "        static_shape=static_shape,\n",
    "        num_outputs=num_outputs,\n",
    "        d_model=256,\n",
    "        num_heads=8,\n",
    "        ff_dim=512,\n",
    "        num_transformer_blocks=6,\n",
    "        dropout=0.1\n",
    "    )\n",
    "\n",
    "    model = compile_model(model)\n",
    "    callbacks = create_transformer_callbacks(target_names, val_data, val_targets)\n",
    "\n",
    "    return model, callbacks, target_names\n",
    "\n",
    "def train_transformer(train_data, train_targets, val_data, val_targets, epochs=200, batch_size=128, save_name='final_model'):\n",
    "    \"\"\"\n",
    "    Training ottimizzato per single-step transformer.\n",
    "    \"\"\"\n",
    "    # Dataset con augmentation\n",
    "    def augment(x, y):\n",
    "        # Ottieni il dtype dei dati originali\n",
    "        original_dtype = x['temporal'].dtype\n",
    "        # Genera il rumore con lo stesso dtype\n",
    "        noise = tf.random.normal(\n",
    "            tf.shape(x['temporal']), \n",
    "            mean=0.0, \n",
    "            stddev=0.01,\n",
    "            dtype=original_dtype\n",
    "        )\n",
    "        x['temporal'] += noise\n",
    "        return x, y\n",
    "\n",
    "    train_dataset = tf.data.Dataset.from_tensor_slices((train_data, train_targets))\\\n",
    "        .map(augment, num_parallel_calls=tf.data.AUTOTUNE)\\\n",
    "        .cache()\\\n",
    "        .shuffle(buffer_size=10000)\\\n",
    "        .batch(batch_size)\\\n",
    "        .prefetch(tf.data.AUTOTUNE)\n",
    "\n",
    "    val_dataset = tf.data.Dataset.from_tensor_slices((val_data, val_targets))\\\n",
    "        .cache()\\\n",
    "        .batch(batch_size)\\\n",
    "        .prefetch(tf.data.AUTOTUNE)\n",
    "\n",
    "    strategy = tf.distribute.MirroredStrategy() if len(tf.config.list_physical_devices('GPU')) > 1 else tf.distribute.get_strategy()\n",
    "\n",
    "    with strategy.scope():\n",
    "        model, callbacks, target_names = setup_transformer_training(\n",
    "            train_data, train_targets, val_data, val_targets\n",
    "        )\n",
    "\n",
    "    model.summary()\n",
    "\n",
    "    try:\n",
    "        keras.utils.plot_model(model, f\"{execute_name}_{save_name}.png\", show_shapes=True)\n",
    "    except Exception as e:\n",
    "        print(f\"Warning: Could not create model plot: {e}\")\n",
    "\n",
    "    # Training con gestione errori e memory saving\n",
    "    try:\n",
    "        with tf.device('/GPU:0'):  # Forza l'uso della GPU principale\n",
    "            history = model.fit(\n",
    "                train_dataset,\n",
    "                validation_data=val_dataset,\n",
    "                epochs=epochs,\n",
    "                callbacks=callbacks,\n",
    "                verbose=1,\n",
    "                workers=8,\n",
    "                use_multiprocessing=True\n",
    "            )\n",
    "    except tf.errors.ResourceExhaustedError:\n",
    "        print(\"Memoria GPU esaurita, riprovo con batch size più piccolo...\")\n",
    "        batch_size = batch_size // 2\n",
    "        train_dataset = train_dataset.unbatch().batch(batch_size)\n",
    "        val_dataset = val_dataset.unbatch().batch(batch_size)\n",
    "        history = model.fit(\n",
    "            train_dataset,\n",
    "            validation_data=val_dataset,\n",
    "            epochs=epochs,\n",
    "            callbacks=callbacks,\n",
    "            verbose=1\n",
    "        )\n",
    "\n",
    "    # Salvataggio modello\n",
    "    try:\n",
    "        save_path = f'{execute_name}_{save_name}.keras'\n",
    "        model.save(save_path, save_format='keras')\n",
    "\n",
    "        os.makedirs(f'{execute_name}/weights', exist_ok=True)\n",
    "        model.save_weights(f'{execute_name}/weights')\n",
    "        print(f\"\\nModello salvato in: {save_path}\")\n",
    "\n",
    "        # Salva anche la storia del training\n",
    "        with open(f'{execute_name}_training_history.json', 'w') as f:\n",
    "            json.dump(history.history, f)\n",
    "    except Exception as e:\n",
    "        print(f\"Warning: Could not save model: {e}\")\n",
    "\n",
    "    return model, history"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "35490e902e494c4a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Shape rilevate:\n",
      "- Temporal shape: (1, 3)\n",
      "- Static shape: (113,)\n",
      "- Numero di output: 5\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-12-19 23:43:47.552446: I tensorflow/tsl/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"OilTransformer\"\n",
      "__________________________________________________________________________________________________\n",
      " Layer (type)                Output Shape                 Param #   Connected to                  \n",
      "==================================================================================================\n",
      " temporal (InputLayer)       [(None, 1, 3)]               0         []                            \n",
      "                                                                                                  \n",
      " layer_normalization (Layer  (None, 1, 3)                 6         ['temporal[0][0]']            \n",
      " Normalization)                                                                                   \n",
      "                                                                                                  \n",
      " data_augmentation (DataAug  (None, 1, 3)                 0         ['layer_normalization[0][0]'] \n",
      " mentation)                                                                                       \n",
      "                                                                                                  \n",
      " dense (Dense)               (None, 1, 256)               1024      ['data_augmentation[0][0]']   \n",
      "                                                                                                  \n",
      " dropout (Dropout)           (None, 1, 256)               0         ['dense[0][0]']               \n",
      "                                                                                                  \n",
      " dense_1 (Dense)             (None, 1, 512)               131584    ['dropout[0][0]']             \n",
      "                                                                                                  \n",
      " positional_encoding (Posit  (None, 1, 512)               512       ['dense_1[0][0]']             \n",
      " ionalEncoding)                                                                                   \n",
      "                                                                                                  \n",
      " multi_head_attention (Mult  (None, 1, 512)               1050624   ['positional_encoding[0][0]', \n",
      " iHeadAttention)                                                     'positional_encoding[0][0]'] \n",
      "                                                                                                  \n",
      " dense_2 (Dense)             (None, 1, 512)               262656    ['positional_encoding[0][0]'] \n",
      "                                                                                                  \n",
      " dropout_1 (Dropout)         (None, 1, 512)               0         ['multi_head_attention[0][0]']\n",
      "                                                                                                  \n",
      " tf.math.multiply (TFOpLamb  (None, 1, 512)               0         ['dense_2[0][0]',             \n",
      " da)                                                                 'dropout_1[0][0]']           \n",
      "                                                                                                  \n",
      " tf.__operators__.add (TFOp  (None, 1, 512)               0         ['positional_encoding[0][0]', \n",
      " Lambda)                                                             'tf.math.multiply[0][0]']    \n",
      "                                                                                                  \n",
      " layer_normalization_1 (Lay  (None, 1, 512)               1024      ['tf.__operators__.add[0][0]']\n",
      " erNormalization)                                                                                 \n",
      "                                                                                                  \n",
      " dense_6 (Dense)             (None, 1, 512)               262656    ['layer_normalization_1[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " sequential (Sequential)     (None, 1, 512)               1312768   ['layer_normalization_1[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " tf.math.multiply_1 (TFOpLa  (None, 1, 512)               0         ['dense_6[0][0]',             \n",
      " mbda)                                                               'sequential[0][0]']          \n",
      "                                                                                                  \n",
      " tf.__operators__.add_1 (TF  (None, 1, 512)               0         ['layer_normalization_1[0][0]'\n",
      " OpLambda)                                                          , 'tf.math.multiply_1[0][0]'] \n",
      "                                                                                                  \n",
      " layer_normalization_2 (Lay  (None, 1, 512)               1024      ['tf.__operators__.add_1[0][0]\n",
      " erNormalization)                                                   ']                            \n",
      "                                                                                                  \n",
      " multi_head_attention_1 (Mu  (None, 1, 512)               1050624   ['layer_normalization_2[0][0]'\n",
      " ltiHeadAttention)                                                  , 'layer_normalization_2[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " dense_7 (Dense)             (None, 1, 512)               262656    ['layer_normalization_2[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " dropout_4 (Dropout)         (None, 1, 512)               0         ['multi_head_attention_1[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " tf.math.multiply_2 (TFOpLa  (None, 1, 512)               0         ['dense_7[0][0]',             \n",
      " mbda)                                                               'dropout_4[0][0]']           \n",
      "                                                                                                  \n",
      " tf.__operators__.add_2 (TF  (None, 1, 512)               0         ['layer_normalization_2[0][0]'\n",
      " OpLambda)                                                          , 'tf.math.multiply_2[0][0]'] \n",
      "                                                                                                  \n",
      " layer_normalization_3 (Lay  (None, 1, 512)               1024      ['tf.__operators__.add_2[0][0]\n",
      " erNormalization)                                                   ']                            \n",
      "                                                                                                  \n",
      " dense_11 (Dense)            (None, 1, 512)               262656    ['layer_normalization_3[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " sequential_1 (Sequential)   (None, 1, 512)               1312768   ['layer_normalization_3[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " tf.math.multiply_3 (TFOpLa  (None, 1, 512)               0         ['dense_11[0][0]',            \n",
      " mbda)                                                               'sequential_1[0][0]']        \n",
      "                                                                                                  \n",
      " tf.__operators__.add_3 (TF  (None, 1, 512)               0         ['layer_normalization_3[0][0]'\n",
      " OpLambda)                                                          , 'tf.math.multiply_3[0][0]'] \n",
      "                                                                                                  \n",
      " layer_normalization_4 (Lay  (None, 1, 512)               1024      ['tf.__operators__.add_3[0][0]\n",
      " erNormalization)                                                   ']                            \n",
      "                                                                                                  \n",
      " multi_head_attention_2 (Mu  (None, 1, 512)               1050624   ['layer_normalization_4[0][0]'\n",
      " ltiHeadAttention)                                                  , 'layer_normalization_4[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " dense_12 (Dense)            (None, 1, 512)               262656    ['layer_normalization_4[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " dropout_7 (Dropout)         (None, 1, 512)               0         ['multi_head_attention_2[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " tf.math.multiply_4 (TFOpLa  (None, 1, 512)               0         ['dense_12[0][0]',            \n",
      " mbda)                                                               'dropout_7[0][0]']           \n",
      "                                                                                                  \n",
      " tf.__operators__.add_4 (TF  (None, 1, 512)               0         ['layer_normalization_4[0][0]'\n",
      " OpLambda)                                                          , 'tf.math.multiply_4[0][0]'] \n",
      "                                                                                                  \n",
      " layer_normalization_5 (Lay  (None, 1, 512)               1024      ['tf.__operators__.add_4[0][0]\n",
      " erNormalization)                                                   ']                            \n",
      "                                                                                                  \n",
      " dense_16 (Dense)            (None, 1, 512)               262656    ['layer_normalization_5[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " sequential_2 (Sequential)   (None, 1, 512)               1312768   ['layer_normalization_5[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " tf.math.multiply_5 (TFOpLa  (None, 1, 512)               0         ['dense_16[0][0]',            \n",
      " mbda)                                                               'sequential_2[0][0]']        \n",
      "                                                                                                  \n",
      " tf.__operators__.add_5 (TF  (None, 1, 512)               0         ['layer_normalization_5[0][0]'\n",
      " OpLambda)                                                          , 'tf.math.multiply_5[0][0]'] \n",
      "                                                                                                  \n",
      " layer_normalization_6 (Lay  (None, 1, 512)               1024      ['tf.__operators__.add_5[0][0]\n",
      " erNormalization)                                                   ']                            \n",
      "                                                                                                  \n",
      " multi_head_attention_3 (Mu  (None, 1, 512)               1050624   ['layer_normalization_6[0][0]'\n",
      " ltiHeadAttention)                                                  , 'layer_normalization_6[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " dense_17 (Dense)            (None, 1, 512)               262656    ['layer_normalization_6[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " dropout_10 (Dropout)        (None, 1, 512)               0         ['multi_head_attention_3[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " tf.math.multiply_6 (TFOpLa  (None, 1, 512)               0         ['dense_17[0][0]',            \n",
      " mbda)                                                               'dropout_10[0][0]']          \n",
      "                                                                                                  \n",
      " tf.__operators__.add_6 (TF  (None, 1, 512)               0         ['layer_normalization_6[0][0]'\n",
      " OpLambda)                                                          , 'tf.math.multiply_6[0][0]'] \n",
      "                                                                                                  \n",
      " layer_normalization_7 (Lay  (None, 1, 512)               1024      ['tf.__operators__.add_6[0][0]\n",
      " erNormalization)                                                   ']                            \n",
      "                                                                                                  \n",
      " dense_21 (Dense)            (None, 1, 512)               262656    ['layer_normalization_7[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " sequential_3 (Sequential)   (None, 1, 512)               1312768   ['layer_normalization_7[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " tf.math.multiply_7 (TFOpLa  (None, 1, 512)               0         ['dense_21[0][0]',            \n",
      " mbda)                                                               'sequential_3[0][0]']        \n",
      "                                                                                                  \n",
      " tf.__operators__.add_7 (TF  (None, 1, 512)               0         ['layer_normalization_7[0][0]'\n",
      " OpLambda)                                                          , 'tf.math.multiply_7[0][0]'] \n",
      "                                                                                                  \n",
      " layer_normalization_8 (Lay  (None, 1, 512)               1024      ['tf.__operators__.add_7[0][0]\n",
      " erNormalization)                                                   ']                            \n",
      "                                                                                                  \n",
      " multi_head_attention_4 (Mu  (None, 1, 512)               1050624   ['layer_normalization_8[0][0]'\n",
      " ltiHeadAttention)                                                  , 'layer_normalization_8[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " dense_22 (Dense)            (None, 1, 512)               262656    ['layer_normalization_8[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " dropout_13 (Dropout)        (None, 1, 512)               0         ['multi_head_attention_4[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " tf.math.multiply_8 (TFOpLa  (None, 1, 512)               0         ['dense_22[0][0]',            \n",
      " mbda)                                                               'dropout_13[0][0]']          \n",
      "                                                                                                  \n",
      " tf.__operators__.add_8 (TF  (None, 1, 512)               0         ['layer_normalization_8[0][0]'\n",
      " OpLambda)                                                          , 'tf.math.multiply_8[0][0]'] \n",
      "                                                                                                  \n",
      " layer_normalization_9 (Lay  (None, 1, 512)               1024      ['tf.__operators__.add_8[0][0]\n",
      " erNormalization)                                                   ']                            \n",
      "                                                                                                  \n",
      " dense_26 (Dense)            (None, 1, 512)               262656    ['layer_normalization_9[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " sequential_4 (Sequential)   (None, 1, 512)               1312768   ['layer_normalization_9[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " tf.math.multiply_9 (TFOpLa  (None, 1, 512)               0         ['dense_26[0][0]',            \n",
      " mbda)                                                               'sequential_4[0][0]']        \n",
      "                                                                                                  \n",
      " tf.__operators__.add_9 (TF  (None, 1, 512)               0         ['layer_normalization_9[0][0]'\n",
      " OpLambda)                                                          , 'tf.math.multiply_9[0][0]'] \n",
      "                                                                                                  \n",
      " layer_normalization_10 (La  (None, 1, 512)               1024      ['tf.__operators__.add_9[0][0]\n",
      " yerNormalization)                                                  ']                            \n",
      "                                                                                                  \n",
      " multi_head_attention_5 (Mu  (None, 1, 512)               1050624   ['layer_normalization_10[0][0]\n",
      " ltiHeadAttention)                                                  ',                            \n",
      "                                                                     'layer_normalization_10[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " static (InputLayer)         [(None, 113)]                0         []                            \n",
      "                                                                                                  \n",
      " dense_27 (Dense)            (None, 1, 512)               262656    ['layer_normalization_10[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " dropout_16 (Dropout)        (None, 1, 512)               0         ['multi_head_attention_5[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " layer_normalization_13 (La  (None, 113)                  226       ['static[0][0]']              \n",
      " yerNormalization)                                                                                \n",
      "                                                                                                  \n",
      " tf.math.multiply_10 (TFOpL  (None, 1, 512)               0         ['dense_27[0][0]',            \n",
      " ambda)                                                              'dropout_16[0][0]']          \n",
      "                                                                                                  \n",
      " dense_32 (Dense)            (None, 512)                  58368     ['layer_normalization_13[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " tf.__operators__.add_10 (T  (None, 1, 512)               0         ['layer_normalization_10[0][0]\n",
      " FOpLambda)                                                         ',                            \n",
      "                                                                     'tf.math.multiply_10[0][0]'] \n",
      "                                                                                                  \n",
      " batch_normalization (Batch  (None, 512)                  2048      ['dense_32[0][0]']            \n",
      " Normalization)                                                                                   \n",
      "                                                                                                  \n",
      " layer_normalization_11 (La  (None, 1, 512)               1024      ['tf.__operators__.add_10[0][0\n",
      " yerNormalization)                                                  ]']                           \n",
      "                                                                                                  \n",
      " dropout_19 (Dropout)        (None, 512)                  0         ['batch_normalization[0][0]'] \n",
      "                                                                                                  \n",
      " dense_31 (Dense)            (None, 1, 512)               262656    ['layer_normalization_11[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " sequential_5 (Sequential)   (None, 1, 512)               1312768   ['layer_normalization_11[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " dense_33 (Dense)            (None, 256)                  131328    ['dropout_19[0][0]']          \n",
      "                                                                                                  \n",
      " tf.math.multiply_11 (TFOpL  (None, 1, 512)               0         ['dense_31[0][0]',            \n",
      " ambda)                                                              'sequential_5[0][0]']        \n",
      "                                                                                                  \n",
      " batch_normalization_1 (Bat  (None, 256)                  1024      ['dense_33[0][0]']            \n",
      " chNormalization)                                                                                 \n",
      "                                                                                                  \n",
      " tf.__operators__.add_11 (T  (None, 1, 512)               0         ['layer_normalization_11[0][0]\n",
      " FOpLambda)                                                         ',                            \n",
      "                                                                     'tf.math.multiply_11[0][0]'] \n",
      "                                                                                                  \n",
      " dropout_20 (Dropout)        (None, 256)                  0         ['batch_normalization_1[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " layer_normalization_12 (La  (None, 1, 512)               1024      ['tf.__operators__.add_11[0][0\n",
      " yerNormalization)                                                  ]']                           \n",
      "                                                                                                  \n",
      " dense_34 (Dense)            (None, 128)                  32896     ['dropout_20[0][0]']          \n",
      "                                                                                                  \n",
      " multi_head_attention_6 (Mu  (None, 1, 512)               525568    ['layer_normalization_12[0][0]\n",
      " ltiHeadAttention)                                                  ',                            \n",
      "                                                                     'layer_normalization_12[0][0]\n",
      "                                                                    ']                            \n",
      "                                                                                                  \n",
      " batch_normalization_2 (Bat  (None, 128)                  512       ['dense_34[0][0]']            \n",
      " chNormalization)                                                                                 \n",
      "                                                                                                  \n",
      " global_average_pooling1d (  (None, 512)                  0         ['multi_head_attention_6[0][0]\n",
      " GlobalAveragePooling1D)                                            ']                            \n",
      "                                                                                                  \n",
      " dropout_21 (Dropout)        (None, 128)                  0         ['batch_normalization_2[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " dense_35 (Dense)            (None, 256)                  131328    ['global_average_pooling1d[0][\n",
      "                                                                    0]']                          \n",
      "                                                                                                  \n",
      " dense_36 (Dense)            (None, 256)                  33024     ['dropout_21[0][0]']          \n",
      "                                                                                                  \n",
      " concatenate (Concatenate)   (None, 512)                  0         ['dense_35[0][0]',            \n",
      "                                                                     'dense_36[0][0]']            \n",
      "                                                                                                  \n",
      " dense_37 (Dense)            (None, 256)                  131328    ['concatenate[0][0]']         \n",
      "                                                                                                  \n",
      " batch_normalization_3 (Bat  (None, 256)                  1024      ['dense_37[0][0]']            \n",
      " chNormalization)                                                                                 \n",
      "                                                                                                  \n",
      " dense_38 (Dense)            (None, 256)                  65792     ['batch_normalization_3[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " dropout_22 (Dropout)        (None, 256)                  0         ['dense_38[0][0]']            \n",
      "                                                                                                  \n",
      " tf.__operators__.add_12 (T  (None, 256)                  0         ['dropout_22[0][0]',          \n",
      " FOpLambda)                                                          'dense_37[0][0]']            \n",
      "                                                                                                  \n",
      " batch_normalization_4 (Bat  (None, 256)                  1024      ['tf.__operators__.add_12[0][0\n",
      " chNormalization)                                                   ]']                           \n",
      "                                                                                                  \n",
      " dense_39 (Dense)            (None, 128)                  32896     ['batch_normalization_4[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " dropout_23 (Dropout)        (None, 128)                  0         ['dense_39[0][0]']            \n",
      "                                                                                                  \n",
      " batch_normalization_5 (Bat  (None, 128)                  512       ['dropout_23[0][0]']          \n",
      " chNormalization)                                                                                 \n",
      "                                                                                                  \n",
      " dense_40 (Dense)            (None, 64)                   8256      ['batch_normalization_5[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      " dropout_24 (Dropout)        (None, 64)                   0         ['dense_40[0][0]']            \n",
      "                                                                                                  \n",
      " batch_normalization_6 (Bat  (None, 64)                   256       ['dropout_24[0][0]']          \n",
      " chNormalization)                                                                                 \n",
      "                                                                                                  \n",
      " dense_41 (Dense)            (None, 5)                    325       ['batch_normalization_6[0][0]'\n",
      "                                                                    ]                             \n",
      "                                                                                                  \n",
      "==================================================================================================\n",
      "Total params: 18635373 (71.09 MB)\n",
      "Trainable params: 18631661 (71.07 MB)\n",
      "Non-trainable params: 3712 (14.50 KB)\n",
      "__________________________________________________________________________________________________\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-12-19 23:43:50.363178: I tensorflow/tsl/profiler/lib/profiler_session.cc:104] Profiler session initializing.\n",
      "2024-12-19 23:43:50.363220: I tensorflow/tsl/profiler/lib/profiler_session.cc:119] Profiler session started.\n",
      "2024-12-19 23:43:50.363276: I tensorflow/compiler/xla/backends/profiler/gpu/cupti_tracer.cc:1694] Profiler found 1 GPUs\n",
      "2024-12-19 23:43:50.410241: I tensorflow/tsl/profiler/lib/profiler_session.cc:131] Profiler session tear down.\n",
      "2024-12-19 23:43:50.410423: I tensorflow/compiler/xla/backends/profiler/gpu/cupti_tracer.cc:1828] CUPTI activity buffer flushed\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/200\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-12-19 23:44:15.723844: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7b5c587c2a20 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:\n",
      "2024-12-19 23:44:15.723900: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): NVIDIA L40S, Compute Capability 8.9\n",
      "2024-12-19 23:44:15.731034: I tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.cc:269] disabling MLIR crash reproducer, set env var `MLIR_CRASH_REPRODUCER_DIRECTORY` to enable.\n",
      "2024-12-19 23:44:15.824204: I tensorflow/compiler/xla/stream_executor/cuda/cuda_dnn.cc:442] Loaded cuDNN version 8905\n",
      "2024-12-19 23:44:16.017696: I ./tensorflow/compiler/jit/device_compiler.h:186] Compiled cluster using XLA!  This line is logged at most once for the lifetime of the process.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "81/81 [==============================] - 519s 6s/step - loss: 0.5779 - mae: 1.0754 - mape: 880.2349 - val_loss: 0.3937 - val_mae: 0.8479 - val_mape: 408.4369 - val_olive_prod_mae: 0.7764 - val_olive_prod_mape: 179.0094 - best_olive_prod_mae: 0.7764 - val_min_oil_prod_mae: 1.0417 - val_min_oil_prod_mape: 827.8750 - best_min_oil_prod_mae: 1.0417 - val_max_oil_prod_mae: 0.7703 - val_max_oil_prod_mape: 178.8319 - best_max_oil_prod_mae: 0.7703 - val_avg_oil_prod_mae: 0.8092 - val_avg_oil_prod_mape: 578.2767 - best_avg_oil_prod_mae: 0.8092 - val_total_water_need_mae: 0.8420 - val_total_water_need_mape: 278.1917 - best_total_water_need_mae: 0.8420 - lr: 4.0000e-05\n",
      "Epoch 2/200\n",
      "81/81 [==============================] - 46s 562ms/step - loss: 0.2425 - mae: 0.6015 - mape: 563.2821 - val_loss: 0.4574 - val_mae: 0.9300 - val_mape: 778.7053 - lr: 8.0500e-05\n",
      "Epoch 3/200\n",
      "81/81 [==============================] - 45s 545ms/step - loss: 0.1409 - mae: 0.4210 - mape: 431.1277 - val_loss: 0.2816 - val_mae: 0.6775 - val_mape: 529.1827 - lr: 1.2100e-04\n",
      "Epoch 4/200\n",
      "81/81 [==============================] - 45s 551ms/step - loss: 0.1043 - mae: 0.3407 - mape: 326.2097 - val_loss: 0.1583 - val_mae: 0.4714 - val_mape: 334.0154 - lr: 1.6150e-04\n",
      "Epoch 5/200\n",
      "81/81 [==============================] - 47s 570ms/step - loss: 0.0782 - mae: 0.2827 - mape: 232.1423 - val_loss: 0.0972 - val_mae: 0.3635 - val_mape: 290.3582 - lr: 2.0200e-04\n",
      "Epoch 6/200\n",
      "81/81 [==============================] - 430s 5s/step - loss: 0.0600 - mae: 0.2404 - mape: 192.1100 - val_loss: 0.0521 - val_mae: 0.2606 - val_mape: 219.4938 - val_olive_prod_mae: 0.2230 - val_olive_prod_mape: 268.5168 - best_olive_prod_mae: 0.2230 - val_min_oil_prod_mae: 0.2973 - val_min_oil_prod_mape: 134.6088 - best_min_oil_prod_mae: 0.2973 - val_max_oil_prod_mae: 0.2204 - val_max_oil_prod_mape: 174.5454 - best_max_oil_prod_mae: 0.2204 - val_avg_oil_prod_mae: 0.2480 - val_avg_oil_prod_mape: 278.0671 - best_avg_oil_prod_mae: 0.2480 - val_total_water_need_mae: 0.3143 - val_total_water_need_mape: 241.7285 - best_total_water_need_mae: 0.3143 - lr: 2.4250e-04\n",
      "Epoch 7/200\n",
      "13/81 [===>..........................] - ETA: 28s - loss: 0.0542 - mae: 0.2247 - mape: 202.4973"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-12-20 00:02:52.728150: I tensorflow/tsl/profiler/lib/profiler_session.cc:104] Profiler session initializing.\n",
      "2024-12-20 00:02:52.728206: I tensorflow/tsl/profiler/lib/profiler_session.cc:119] Profiler session started.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "33/81 [===========>..................] - ETA: 20s - loss: 0.0527 - mae: 0.2215 - mape: 175.1488"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-12-20 00:03:01.834386: I tensorflow/tsl/profiler/lib/profiler_session.cc:70] Profiler session collecting data.\n",
      "2024-12-20 00:03:01.926067: I tensorflow/compiler/xla/backends/profiler/gpu/cupti_tracer.cc:1828] CUPTI activity buffer flushed\n",
      "2024-12-20 00:03:07.275024: I tensorflow/compiler/xla/backends/profiler/gpu/cupti_collector.cc:541]  GpuTracer has collected 110853 callback api events and 111417 activity events. \n",
      "2024-12-20 00:04:14.089035: I tensorflow/tsl/profiler/lib/profiler_session.cc:131] Profiler session tear down.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "81/81 [==============================] - 118s 1s/step - loss: 0.0508 - mae: 0.2157 - mape: 185.7417 - val_loss: 0.0406 - val_mae: 0.2162 - val_mape: 198.2257 - lr: 2.8300e-04\n",
      "Epoch 8/200\n",
      "81/81 [==============================] - 45s 552ms/step - loss: 0.0439 - mae: 0.1973 - mape: 161.9557 - val_loss: 0.0259 - val_mae: 0.1641 - val_mape: 199.7436 - lr: 3.2350e-04\n",
      "Epoch 9/200\n",
      "81/81 [==============================] - 49s 583ms/step - loss: 0.0431 - mae: 0.1915 - mape: 164.8879 - val_loss: 0.0709 - val_mae: 0.3176 - val_mape: 337.8962 - lr: 3.6400e-04\n",
      "Epoch 10/200\n",
      "81/81 [==============================] - 43s 529ms/step - loss: 0.0423 - mae: 0.1887 - mape: 156.7106 - val_loss: 0.0464 - val_mae: 0.2383 - val_mape: 294.8042 - lr: 4.0450e-04\n",
      "Epoch 11/200\n",
      "81/81 [==============================] - 425s 5s/step - loss: 0.0412 - mae: 0.1862 - mape: 151.4311 - val_loss: 0.1553 - val_mae: 0.4763 - val_mape: 384.9722 - val_olive_prod_mae: 0.2800 - val_olive_prod_mape: 168.5654 - val_min_oil_prod_mae: 0.5849 - val_min_oil_prod_mape: 494.9827 - val_max_oil_prod_mae: 0.8025 - val_max_oil_prod_mape: 712.3788 - val_avg_oil_prod_mae: 0.2131 - val_avg_oil_prod_mape: 215.8353 - best_avg_oil_prod_mae: 0.2131 - val_total_water_need_mae: 0.5012 - val_total_water_need_mape: 333.0994 - lr: 4.4500e-04\n",
      "Epoch 12/200\n",
      "81/81 [==============================] - 48s 577ms/step - loss: 0.0334 - mae: 0.1657 - mape: 139.6879 - val_loss: 0.0329 - val_mae: 0.1911 - val_mape: 208.6394 - lr: 4.8550e-04\n",
      "Epoch 13/200\n",
      "81/81 [==============================] - 43s 526ms/step - loss: 0.0300 - mae: 0.1565 - mape: 130.8686 - val_loss: 0.0180 - val_mae: 0.1290 - val_mape: 152.9059 - lr: 3.5374e-04\n",
      "Epoch 14/200\n",
      "81/81 [==============================] - 43s 527ms/step - loss: 0.0302 - mae: 0.1576 - mape: 134.6192 - val_loss: 0.0309 - val_mae: 0.1843 - val_mape: 232.8076 - lr: 3.4444e-04\n",
      "Epoch 15/200\n",
      "81/81 [==============================] - 45s 544ms/step - loss: 0.0281 - mae: 0.1504 - mape: 126.4103 - val_loss: 0.0565 - val_mae: 0.2682 - val_mape: 290.2245 - lr: 3.3538e-04\n",
      "Epoch 16/200\n",
      "81/81 [==============================] - 414s 5s/step - loss: 0.0276 - mae: 0.1492 - mape: 126.1187 - val_loss: 0.0210 - val_mae: 0.1440 - val_mape: 214.6380 - val_olive_prod_mae: 0.1530 - val_olive_prod_mape: 196.5764 - best_olive_prod_mae: 0.1530 - val_min_oil_prod_mae: 0.1129 - val_min_oil_prod_mape: 94.3189 - best_min_oil_prod_mae: 0.1129 - val_max_oil_prod_mae: 0.1045 - val_max_oil_prod_mape: 90.8162 - best_max_oil_prod_mae: 0.1045 - val_avg_oil_prod_mae: 0.1553 - val_avg_oil_prod_mape: 514.4499 - best_avg_oil_prod_mae: 0.1553 - val_total_water_need_mae: 0.1945 - val_total_water_need_mape: 177.0285 - best_total_water_need_mae: 0.1945 - lr: 3.2657e-04\n",
      "Epoch 17/200\n",
      "81/81 [==============================] - 44s 536ms/step - loss: 0.0261 - mae: 0.1443 - mape: 121.8932 - val_loss: 0.0324 - val_mae: 0.1903 - val_mape: 286.4989 - lr: 3.1798e-04\n",
      "Epoch 18/200\n",
      "81/81 [==============================] - 44s 539ms/step - loss: 0.0250 - mae: 0.1420 - mape: 119.7674 - val_loss: 0.0193 - val_mae: 0.1254 - val_mape: 136.5804 - lr: 3.0962e-04\n",
      "Epoch 19/200\n",
      "81/81 [==============================] - 45s 545ms/step - loss: 0.0244 - mae: 0.1396 - mape: 123.8952 - val_loss: 0.0137 - val_mae: 0.0964 - val_mape: 107.5592 - lr: 3.0148e-04\n",
      "Epoch 20/200\n",
      "81/81 [==============================] - 45s 550ms/step - loss: 0.0241 - mae: 0.1380 - mape: 119.1140 - val_loss: 0.0136 - val_mae: 0.0996 - val_mape: 104.9675 - lr: 2.9355e-04\n",
      "Epoch 21/200\n",
      "81/81 [==============================] - 405s 5s/step - loss: 0.0232 - mae: 0.1360 - mape: 116.4450 - val_loss: 0.0137 - val_mae: 0.0968 - val_mape: 92.3893 - val_olive_prod_mae: 0.0957 - val_olive_prod_mape: 92.1067 - best_olive_prod_mae: 0.0957 - val_min_oil_prod_mae: 0.1077 - val_min_oil_prod_mape: 92.6856 - best_min_oil_prod_mae: 0.1077 - val_max_oil_prod_mae: 0.1119 - val_max_oil_prod_mape: 93.4440 - val_avg_oil_prod_mae: 0.1049 - val_avg_oil_prod_mape: 141.0929 - best_avg_oil_prod_mae: 0.1049 - val_total_water_need_mae: 0.0639 - val_total_water_need_mape: 42.6167 - best_total_water_need_mae: 0.0639 - lr: 2.8583e-04\n",
      "Epoch 22/200\n",
      "81/81 [==============================] - 43s 521ms/step - loss: 0.0230 - mae: 0.1351 - mape: 117.9255 - val_loss: 0.0173 - val_mae: 0.1206 - val_mape: 113.5945 - lr: 2.7832e-04\n",
      "Epoch 23/200\n",
      "81/81 [==============================] - 44s 529ms/step - loss: 0.0237 - mae: 0.1362 - mape: 119.0401 - val_loss: 0.0263 - val_mae: 0.1418 - val_mape: 103.9691 - lr: 2.7100e-04\n",
      "Epoch 24/200\n",
      "81/81 [==============================] - 44s 535ms/step - loss: 0.0228 - mae: 0.1345 - mape: 122.7791 - val_loss: 0.0140 - val_mae: 0.0997 - val_mape: 78.1515 - lr: 2.6388e-04\n",
      "Epoch 25/200\n",
      "81/81 [==============================] - 46s 566ms/step - loss: 0.0230 - mae: 0.1339 - mape: 115.1308 - val_loss: 0.0230 - val_mae: 0.1624 - val_mape: 188.7469 - lr: 2.5694e-04\n",
      "Epoch 26/200\n",
      "81/81 [==============================] - 416s 5s/step - loss: 0.0214 - mae: 0.1307 - mape: 108.7911 - val_loss: 0.0159 - val_mae: 0.1149 - val_mape: 104.5200 - val_olive_prod_mae: 0.1179 - val_olive_prod_mape: 102.0244 - val_min_oil_prod_mae: 0.1223 - val_min_oil_prod_mape: 86.6709 - val_max_oil_prod_mae: 0.1164 - val_max_oil_prod_mape: 86.5862 - val_avg_oil_prod_mae: 0.1132 - val_avg_oil_prod_mape: 159.2269 - val_total_water_need_mae: 0.1044 - val_total_water_need_mape: 88.0918 - lr: 2.5018e-04\n",
      "Epoch 27/200\n",
      "81/81 [==============================] - 43s 521ms/step - loss: 0.0221 - mae: 0.1313 - mape: 109.7560 - val_loss: 0.0155 - val_mae: 0.1120 - val_mape: 154.6095 - lr: 2.4360e-04\n",
      "Epoch 28/200\n",
      "81/81 [==============================] - 45s 554ms/step - loss: 0.0219 - mae: 0.1317 - mape: 121.4256 - val_loss: 0.0125 - val_mae: 0.0898 - val_mape: 87.1925 - lr: 2.3720e-04\n",
      "Epoch 29/200\n",
      "81/81 [==============================] - 43s 522ms/step - loss: 0.0211 - mae: 0.1291 - mape: 115.6524 - val_loss: 0.0124 - val_mae: 0.0922 - val_mape: 84.2523 - lr: 2.3096e-04\n",
      "Epoch 30/200\n",
      "81/81 [==============================] - 44s 531ms/step - loss: 0.0206 - mae: 0.1279 - mape: 110.3134 - val_loss: 0.0135 - val_mae: 0.0992 - val_mape: 131.3028 - lr: 2.2489e-04\n",
      "Epoch 31/200\n",
      "81/81 [==============================] - 408s 5s/step - loss: 0.0201 - mae: 0.1261 - mape: 114.8836 - val_loss: 0.0122 - val_mae: 0.0904 - val_mape: 83.3467 - val_olive_prod_mae: 0.0966 - val_olive_prod_mape: 90.2318 - val_min_oil_prod_mae: 0.0955 - val_min_oil_prod_mape: 100.6078 - best_min_oil_prod_mae: 0.0955 - val_max_oil_prod_mae: 0.0971 - val_max_oil_prod_mape: 80.8267 - best_max_oil_prod_mae: 0.0971 - val_avg_oil_prod_mae: 0.0919 - val_avg_oil_prod_mape: 99.4094 - best_avg_oil_prod_mae: 0.0919 - val_total_water_need_mae: 0.0706 - val_total_water_need_mape: 45.6571 - lr: 2.1898e-04\n",
      "Epoch 32/200\n",
      "81/81 [==============================] - 43s 531ms/step - loss: 0.0201 - mae: 0.1258 - mape: 112.7482 - val_loss: 0.0135 - val_mae: 0.0985 - val_mape: 113.5038 - lr: 2.1322e-04\n",
      "Epoch 33/200\n",
      "81/81 [==============================] - 45s 543ms/step - loss: 0.0197 - mae: 0.1250 - mape: 104.7758 - val_loss: 0.0133 - val_mae: 0.1006 - val_mape: 91.1548 - lr: 2.0761e-04\n",
      "Epoch 34/200\n",
      "81/81 [==============================] - 44s 541ms/step - loss: 0.0195 - mae: 0.1244 - mape: 109.6190 - val_loss: 0.0122 - val_mae: 0.0907 - val_mape: 80.4084 - lr: 2.0215e-04\n",
      "Epoch 35/200\n",
      "81/81 [==============================] - 44s 536ms/step - loss: 0.0193 - mae: 0.1237 - mape: 111.1468 - val_loss: 0.0121 - val_mae: 0.0875 - val_mape: 78.0447 - lr: 1.9684e-04\n",
      "Epoch 36/200\n",
      "81/81 [==============================] - 416s 5s/step - loss: 0.0196 - mae: 0.1248 - mape: 109.9066 - val_loss: 0.0199 - val_mae: 0.1307 - val_mape: 141.8087 - val_olive_prod_mae: 0.1195 - val_olive_prod_mape: 109.6746 - val_min_oil_prod_mae: 0.1206 - val_min_oil_prod_mape: 136.0026 - val_max_oil_prod_mae: 0.1150 - val_max_oil_prod_mape: 98.9782 - val_avg_oil_prod_mae: 0.1120 - val_avg_oil_prod_mape: 225.4990 - val_total_water_need_mae: 0.1862 - val_total_water_need_mape: 138.8892 - lr: 1.9166e-04\n",
      "Epoch 37/200\n",
      "81/81 [==============================] - 43s 524ms/step - loss: 0.0196 - mae: 0.1242 - mape: 107.2102 - val_loss: 0.0139 - val_mae: 0.1027 - val_mape: 125.0853 - lr: 1.8663e-04\n",
      "Epoch 38/200\n",
      "81/81 [==============================] - 44s 532ms/step - loss: 0.0195 - mae: 0.1247 - mape: 108.7505 - val_loss: 0.0171 - val_mae: 0.1160 - val_mape: 127.9954 - lr: 1.8172e-04\n",
      "Epoch 39/200\n",
      "81/81 [==============================] - 43s 530ms/step - loss: 0.0191 - mae: 0.1233 - mape: 114.1887 - val_loss: 0.0149 - val_mae: 0.1126 - val_mape: 115.3988 - lr: 1.7694e-04\n",
      "Epoch 40/200\n",
      "81/81 [==============================] - 44s 539ms/step - loss: 0.0187 - mae: 0.1224 - mape: 111.9256 - val_loss: 0.0130 - val_mae: 0.1018 - val_mape: 120.4004 - lr: 1.7229e-04\n",
      "Epoch 41/200\n",
      "81/81 [==============================] - 413s 5s/step - loss: 0.0183 - mae: 0.1212 - mape: 107.0688 - val_loss: 0.0111 - val_mae: 0.0833 - val_mape: 85.6888 - val_olive_prod_mae: 0.0903 - val_olive_prod_mape: 93.8519 - best_olive_prod_mae: 0.0903 - val_min_oil_prod_mae: 0.0895 - val_min_oil_prod_mape: 98.7712 - best_min_oil_prod_mae: 0.0895 - val_max_oil_prod_mae: 0.0896 - val_max_oil_prod_mape: 79.7747 - best_max_oil_prod_mae: 0.0896 - val_avg_oil_prod_mae: 0.0869 - val_avg_oil_prod_mape: 111.3278 - best_avg_oil_prod_mae: 0.0869 - val_total_water_need_mae: 0.0602 - val_total_water_need_mape: 44.7183 - best_total_water_need_mae: 0.0602 - lr: 1.6776e-04\n",
      "Epoch 42/200\n",
      "81/81 [==============================] - 43s 522ms/step - loss: 0.0182 - mae: 0.1211 - mape: 103.9119 - val_loss: 0.0115 - val_mae: 0.0915 - val_mape: 79.4720 - lr: 1.6335e-04\n",
      "Epoch 43/200\n",
      "81/81 [==============================] - 43s 520ms/step - loss: 0.0181 - mae: 0.1208 - mape: 110.8668 - val_loss: 0.0127 - val_mae: 0.0985 - val_mape: 107.8702 - lr: 1.5905e-04\n",
      "Epoch 44/200\n",
      "81/81 [==============================] - 44s 534ms/step - loss: 0.0181 - mae: 0.1206 - mape: 106.5163 - val_loss: 0.0120 - val_mae: 0.0901 - val_mape: 86.5637 - lr: 1.5487e-04\n",
      "Epoch 45/200\n",
      "81/81 [==============================] - 42s 512ms/step - loss: 0.0181 - mae: 0.1207 - mape: 109.4113 - val_loss: 0.0118 - val_mae: 0.0911 - val_mape: 85.9042 - lr: 1.5080e-04\n",
      "Epoch 46/200\n",
      "81/81 [==============================] - 418s 5s/step - loss: 0.0178 - mae: 0.1199 - mape: 120.5106 - val_loss: 0.0114 - val_mae: 0.0863 - val_mape: 82.2661 - val_olive_prod_mae: 0.0933 - val_olive_prod_mape: 87.2666 - val_min_oil_prod_mae: 0.0922 - val_min_oil_prod_mape: 97.8242 - val_max_oil_prod_mae: 0.0925 - val_max_oil_prod_mape: 81.9897 - val_avg_oil_prod_mae: 0.0892 - val_avg_oil_prod_mape: 108.5426 - val_total_water_need_mae: 0.0644 - val_total_water_need_mape: 35.7076 - lr: 1.4683e-04\n",
      "Epoch 47/200\n",
      "81/81 [==============================] - 43s 526ms/step - loss: 0.0176 - mae: 0.1193 - mape: 111.5625 - val_loss: 0.0119 - val_mae: 0.0918 - val_mape: 79.6498 - lr: 1.4297e-04\n",
      "Epoch 48/200\n",
      "81/81 [==============================] - 46s 555ms/step - loss: 0.0175 - mae: 0.1190 - mape: 110.9619 - val_loss: 0.0117 - val_mae: 0.0921 - val_mape: 78.5738 - lr: 1.3921e-04\n",
      "Epoch 49/200\n",
      "81/81 [==============================] - 44s 531ms/step - loss: 0.0177 - mae: 0.1193 - mape: 105.3367 - val_loss: 0.0126 - val_mae: 0.0990 - val_mape: 82.5022 - lr: 1.3555e-04\n",
      "Epoch 50/200\n",
      "81/81 [==============================] - 45s 552ms/step - loss: 0.0172 - mae: 0.1179 - mape: 103.1276 - val_loss: 0.0118 - val_mae: 0.0932 - val_mape: 91.8961 - lr: 1.3199e-04\n",
      "Epoch 51/200\n",
      "81/81 [==============================] - 407s 5s/step - loss: 0.0171 - mae: 0.1179 - mape: 109.7217 - val_loss: 0.0116 - val_mae: 0.0920 - val_mape: 99.3956 - val_olive_prod_mae: 0.0969 - val_olive_prod_mape: 92.6791 - val_min_oil_prod_mae: 0.0952 - val_min_oil_prod_mape: 104.2999 - val_max_oil_prod_mae: 0.0940 - val_max_oil_prod_mape: 84.1292 - val_avg_oil_prod_mae: 0.0930 - val_avg_oil_prod_mape: 158.9966 - val_total_water_need_mae: 0.0811 - val_total_water_need_mape: 56.8740 - lr: 1.2852e-04\n",
      "Epoch 52/200\n",
      "81/81 [==============================] - 43s 520ms/step - loss: 0.0169 - mae: 0.1171 - mape: 102.4648 - val_loss: 0.0117 - val_mae: 0.0977 - val_mape: 99.1071 - lr: 1.2514e-04\n",
      "Epoch 53/200\n",
      "81/81 [==============================] - 45s 545ms/step - loss: 0.0167 - mae: 0.1166 - mape: 103.6632 - val_loss: 0.0140 - val_mae: 0.1187 - val_mape: 127.0951 - lr: 1.2185e-04\n",
      "Epoch 54/200\n",
      "81/81 [==============================] - 45s 551ms/step - loss: 0.0167 - mae: 0.1169 - mape: 117.7828 - val_loss: 0.0106 - val_mae: 0.0828 - val_mape: 87.0786 - lr: 1.1865e-04\n",
      "Epoch 55/200\n",
      "81/81 [==============================] - 45s 541ms/step - loss: 0.0164 - mae: 0.1157 - mape: 103.2019 - val_loss: 0.0105 - val_mae: 0.0858 - val_mape: 91.8022 - lr: 1.1553e-04\n",
      "Epoch 56/200\n",
      "81/81 [==============================] - 414s 5s/step - loss: 0.0162 - mae: 0.1154 - mape: 106.0157 - val_loss: 0.0107 - val_mae: 0.0879 - val_mape: 76.6214 - val_olive_prod_mae: 0.0940 - val_olive_prod_mape: 89.4869 - val_min_oil_prod_mae: 0.0947 - val_min_oil_prod_mape: 100.1891 - val_max_oil_prod_mae: 0.0949 - val_max_oil_prod_mape: 81.9265 - val_avg_oil_prod_mae: 0.0927 - val_avg_oil_prod_mape: 81.1511 - val_total_water_need_mae: 0.0632 - val_total_water_need_mape: 30.3533 - lr: 1.1249e-04\n",
      "Epoch 57/200\n",
      "81/81 [==============================] - 44s 540ms/step - loss: 0.0161 - mae: 0.1154 - mape: 111.6323 - val_loss: 0.0122 - val_mae: 0.0993 - val_mape: 89.6327 - lr: 1.0953e-04\n",
      "Epoch 58/200\n",
      "81/81 [==============================] - 45s 547ms/step - loss: 0.0163 - mae: 0.1160 - mape: 103.7626 - val_loss: 0.0189 - val_mae: 0.1307 - val_mape: 154.6112 - lr: 1.0665e-04\n",
      "Epoch 59/200\n",
      "81/81 [==============================] - 45s 545ms/step - loss: 0.0163 - mae: 0.1160 - mape: 107.4402 - val_loss: 0.0132 - val_mae: 0.1094 - val_mape: 108.5976 - lr: 1.0385e-04\n",
      "Epoch 60/200\n",
      "81/81 [==============================] - 45s 549ms/step - loss: 0.0158 - mae: 0.1145 - mape: 102.4115 - val_loss: 0.0129 - val_mae: 0.1075 - val_mape: 113.4921 - lr: 1.0112e-04\n",
      "Epoch 61/200\n",
      "81/81 [==============================] - 413s 5s/step - loss: 0.0158 - mae: 0.1146 - mape: 112.1566 - val_loss: 0.0118 - val_mae: 0.0954 - val_mape: 87.6620 - val_olive_prod_mae: 0.0924 - val_olive_prod_mape: 87.6679 - val_min_oil_prod_mae: 0.0952 - val_min_oil_prod_mape: 89.1397 - val_max_oil_prod_mae: 0.0964 - val_max_oil_prod_mape: 80.2136 - val_avg_oil_prod_mae: 0.0914 - val_avg_oil_prod_mape: 81.9330 - val_total_water_need_mae: 0.1017 - val_total_water_need_mape: 99.3555 - lr: 9.8459e-05\n",
      "Epoch 62/200\n",
      "81/81 [==============================] - 45s 544ms/step - loss: 0.0157 - mae: 0.1143 - mape: 100.9561 - val_loss: 0.0125 - val_mae: 0.1035 - val_mape: 105.1631 - lr: 9.5870e-05\n",
      "Epoch 63/200\n",
      "81/81 [==============================] - 44s 541ms/step - loss: 0.0156 - mae: 0.1139 - mape: 99.1020 - val_loss: 0.0109 - val_mae: 0.0919 - val_mape: 86.3423 - lr: 9.3350e-05\n",
      "Epoch 64/200\n",
      "81/81 [==============================] - 45s 554ms/step - loss: 0.0156 - mae: 0.1140 - mape: 102.9145 - val_loss: 0.0150 - val_mae: 0.1133 - val_mape: 117.4506 - lr: 9.0895e-05\n",
      "Epoch 65/200\n",
      "81/81 [==============================] - 45s 549ms/step - loss: 0.0155 - mae: 0.1138 - mape: 99.9012 - val_loss: 0.0107 - val_mae: 0.0902 - val_mape: 78.9081 - lr: 8.8505e-05\n",
      "Epoch 66/200\n",
      "81/81 [==============================] - 426s 5s/step - loss: 0.0154 - mae: 0.1132 - mape: 101.1288 - val_loss: 0.0103 - val_mae: 0.0883 - val_mape: 84.9515 - val_olive_prod_mae: 0.0942 - val_olive_prod_mape: 89.3613 - val_min_oil_prod_mae: 0.0928 - val_min_oil_prod_mape: 90.1885 - val_max_oil_prod_mae: 0.0920 - val_max_oil_prod_mape: 80.9348 - val_avg_oil_prod_mae: 0.0877 - val_avg_oil_prod_mape: 101.2916 - val_total_water_need_mae: 0.0748 - val_total_water_need_mape: 62.9818 - lr: 8.6178e-05\n",
      "Epoch 67/200\n",
      "81/81 [==============================] - 44s 532ms/step - loss: 0.0154 - mae: 0.1134 - mape: 99.7389 - val_loss: 0.0103 - val_mae: 0.0847 - val_mape: 80.2572 - lr: 8.3913e-05\n",
      "Epoch 68/200\n",
      "81/81 [==============================] - 43s 524ms/step - loss: 0.0152 - mae: 0.1126 - mape: 105.7351 - val_loss: 0.0105 - val_mae: 0.0907 - val_mape: 92.2278 - lr: 8.1706e-05\n",
      "Epoch 69/200\n",
      "81/81 [==============================] - 45s 541ms/step - loss: 0.0152 - mae: 0.1127 - mape: 97.2689 - val_loss: 0.0106 - val_mae: 0.0892 - val_mape: 74.3894 - lr: 7.9558e-05\n",
      "Epoch 70/200\n",
      "81/81 [==============================] - 44s 534ms/step - loss: 0.0150 - mae: 0.1125 - mape: 97.9516 - val_loss: 0.0112 - val_mae: 0.0940 - val_mape: 81.9546 - lr: 7.7466e-05\n",
      "Epoch 71/200\n",
      "81/81 [==============================] - 404s 5s/step - loss: 0.0149 - mae: 0.1122 - mape: 101.4992 - val_loss: 0.0101 - val_mae: 0.0850 - val_mape: 81.0987 - val_olive_prod_mae: 0.0941 - val_olive_prod_mape: 91.1528 - val_min_oil_prod_mae: 0.0925 - val_min_oil_prod_mape: 91.4974 - val_max_oil_prod_mae: 0.0936 - val_max_oil_prod_mape: 79.5238 - val_avg_oil_prod_mae: 0.0884 - val_avg_oil_prod_mape: 102.5653 - val_total_water_need_mae: 0.0564 - val_total_water_need_mape: 40.7536 - best_total_water_need_mae: 0.0564 - lr: 7.5430e-05\n",
      "Epoch 72/200\n",
      "81/81 [==============================] - 43s 531ms/step - loss: 0.0149 - mae: 0.1121 - mape: 100.9465 - val_loss: 0.0110 - val_mae: 0.0896 - val_mape: 92.5869 - lr: 7.3446e-05\n",
      "Epoch 73/200\n",
      "81/81 [==============================] - 45s 555ms/step - loss: 0.0149 - mae: 0.1119 - mape: 103.2648 - val_loss: 0.0098 - val_mae: 0.0836 - val_mape: 76.6982 - lr: 7.1515e-05\n",
      "Epoch 74/200\n",
      "81/81 [==============================] - 43s 523ms/step - loss: 0.0147 - mae: 0.1117 - mape: 104.3210 - val_loss: 0.0100 - val_mae: 0.0875 - val_mape: 75.5992 - lr: 6.9635e-05\n",
      "Epoch 75/200\n",
      "81/81 [==============================] - 45s 546ms/step - loss: 0.0149 - mae: 0.1120 - mape: 107.9233 - val_loss: 0.0109 - val_mae: 0.0933 - val_mape: 76.4215 - lr: 6.7804e-05\n",
      "Epoch 76/200\n",
      "81/81 [==============================] - 420s 5s/step - loss: 0.0146 - mae: 0.1111 - mape: 100.7668 - val_loss: 0.0104 - val_mae: 0.0883 - val_mape: 80.8174 - val_olive_prod_mae: 0.0976 - val_olive_prod_mape: 92.8249 - val_min_oil_prod_mae: 0.0958 - val_min_oil_prod_mape: 95.7500 - val_max_oil_prod_mae: 0.0950 - val_max_oil_prod_mape: 79.5825 - val_avg_oil_prod_mae: 0.0928 - val_avg_oil_prod_mape: 106.9812 - val_total_water_need_mae: 0.0605 - val_total_water_need_mape: 28.9489 - lr: 6.6021e-05\n",
      "Epoch 77/200\n",
      "81/81 [==============================] - 44s 536ms/step - loss: 0.0145 - mae: 0.1112 - mape: 99.6902 - val_loss: 0.0102 - val_mae: 0.0891 - val_mape: 78.1710 - lr: 6.4285e-05\n",
      "Epoch 78/200\n",
      "81/81 [==============================] - 46s 559ms/step - loss: 0.0145 - mae: 0.1110 - mape: 97.5761 - val_loss: 0.0097 - val_mae: 0.0835 - val_mape: 72.4018 - lr: 6.2595e-05\n",
      "Epoch 79/200\n",
      "81/81 [==============================] - 45s 543ms/step - loss: 0.0144 - mae: 0.1109 - mape: 99.8900 - val_loss: 0.0095 - val_mae: 0.0828 - val_mape: 77.4501 - lr: 6.0949e-05\n",
      "Epoch 80/200\n",
      "81/81 [==============================] - 45s 549ms/step - loss: 0.0143 - mae: 0.1107 - mape: 101.5637 - val_loss: 0.0096 - val_mae: 0.0839 - val_mape: 75.1728 - lr: 5.9347e-05\n",
      "Epoch 81/200\n",
      "81/81 [==============================] - 415s 5s/step - loss: 0.0144 - mae: 0.1109 - mape: 101.2297 - val_loss: 0.0101 - val_mae: 0.0892 - val_mape: 82.6180 - val_olive_prod_mae: 0.0929 - val_olive_prod_mape: 90.3583 - val_min_oil_prod_mae: 0.0929 - val_min_oil_prod_mape: 98.0599 - val_max_oil_prod_mae: 0.0914 - val_max_oil_prod_mape: 80.4533 - val_avg_oil_prod_mae: 0.0911 - val_avg_oil_prod_mape: 94.1108 - val_total_water_need_mae: 0.0778 - val_total_water_need_mape: 50.1071 - lr: 5.7787e-05\n",
      "Epoch 82/200\n",
      "81/81 [==============================] - 44s 533ms/step - loss: 0.0142 - mae: 0.1104 - mape: 103.8522 - val_loss: 0.0099 - val_mae: 0.0843 - val_mape: 71.8070 - lr: 5.6267e-05\n",
      "Epoch 83/200\n",
      "81/81 [==============================] - 44s 537ms/step - loss: 0.0142 - mae: 0.1105 - mape: 99.8903 - val_loss: 0.0099 - val_mae: 0.0863 - val_mape: 75.7442 - lr: 5.4788e-05\n",
      "Epoch 84/200\n",
      "81/81 [==============================] - 44s 538ms/step - loss: 0.0142 - mae: 0.1103 - mape: 100.6964 - val_loss: 0.0097 - val_mae: 0.0853 - val_mape: 71.8215 - lr: 5.3347e-05\n",
      "Epoch 85/200\n",
      "81/81 [==============================] - 44s 535ms/step - loss: 0.0141 - mae: 0.1100 - mape: 101.9498 - val_loss: 0.0096 - val_mae: 0.0851 - val_mape: 73.2126 - lr: 5.1945e-05\n",
      "Epoch 86/200\n",
      "81/81 [==============================] - 424s 5s/step - loss: 0.0140 - mae: 0.1101 - mape: 99.0340 - val_loss: 0.0100 - val_mae: 0.0888 - val_mape: 71.7597 - val_olive_prod_mae: 0.0976 - val_olive_prod_mape: 89.1973 - val_min_oil_prod_mae: 0.0948 - val_min_oil_prod_mape: 92.7337 - val_max_oil_prod_mae: 0.0945 - val_max_oil_prod_mape: 79.1431 - val_avg_oil_prod_mae: 0.0921 - val_avg_oil_prod_mape: 68.7220 - val_total_water_need_mae: 0.0650 - val_total_water_need_mape: 29.0024 - lr: 5.0579e-05\n",
      "Epoch 87/200\n",
      "81/81 [==============================] - 44s 535ms/step - loss: 0.0139 - mae: 0.1094 - mape: 98.9774 - val_loss: 0.0095 - val_mae: 0.0838 - val_mape: 77.6027 - lr: 4.9249e-05\n",
      "Epoch 88/200\n",
      "81/81 [==============================] - 44s 537ms/step - loss: 0.0139 - mae: 0.1099 - mape: 103.9017 - val_loss: 0.0094 - val_mae: 0.0836 - val_mape: 79.2909 - lr: 4.7954e-05\n",
      "Epoch 89/200\n",
      "81/81 [==============================] - 43s 529ms/step - loss: 0.0138 - mae: 0.1095 - mape: 95.7289 - val_loss: 0.0091 - val_mae: 0.0812 - val_mape: 73.1377 - lr: 4.6693e-05\n",
      "Epoch 90/200\n",
      "81/81 [==============================] - 43s 524ms/step - loss: 0.0138 - mae: 0.1095 - mape: 105.6472 - val_loss: 0.0092 - val_mae: 0.0832 - val_mape: 77.7363 - lr: 4.5466e-05\n",
      "Epoch 91/200\n",
      "81/81 [==============================] - 419s 5s/step - loss: 0.0138 - mae: 0.1094 - mape: 102.3868 - val_loss: 0.0094 - val_mae: 0.0854 - val_mape: 78.2091 - val_olive_prod_mae: 0.0919 - val_olive_prod_mape: 90.3287 - val_min_oil_prod_mae: 0.0909 - val_min_oil_prod_mape: 97.2435 - val_max_oil_prod_mae: 0.0911 - val_max_oil_prod_mape: 80.7007 - val_avg_oil_prod_mae: 0.0883 - val_avg_oil_prod_mape: 91.3950 - val_total_water_need_mae: 0.0646 - val_total_water_need_mape: 31.3778 - lr: 4.4270e-05\n",
      "Epoch 92/200\n",
      "81/81 [==============================] - 42s 513ms/step - loss: 0.0138 - mae: 0.1095 - mape: 100.2383 - val_loss: 0.0095 - val_mae: 0.0859 - val_mape: 74.0313 - lr: 4.3106e-05\n",
      "Epoch 93/200\n",
      "81/81 [==============================] - 43s 524ms/step - loss: 0.0137 - mae: 0.1094 - mape: 98.0624 - val_loss: 0.0092 - val_mae: 0.0824 - val_mape: 75.3717 - lr: 4.1973e-05\n",
      "Epoch 94/200\n",
      "81/81 [==============================] - 42s 509ms/step - loss: 0.0137 - mae: 0.1092 - mape: 97.3056 - val_loss: 0.0094 - val_mae: 0.0847 - val_mape: 72.2782 - lr: 4.0869e-05\n",
      "Epoch 95/200\n",
      "81/81 [==============================] - 42s 516ms/step - loss: 0.0136 - mae: 0.1090 - mape: 99.6563 - val_loss: 0.0093 - val_mae: 0.0832 - val_mape: 71.3101 - lr: 3.9795e-05\n",
      "Epoch 96/200\n",
      "81/81 [==============================] - 416s 5s/step - loss: 0.0135 - mae: 0.1088 - mape: 98.3289 - val_loss: 0.0093 - val_mae: 0.0830 - val_mape: 73.6735 - val_olive_prod_mae: 0.0907 - val_olive_prod_mape: 88.2918 - val_min_oil_prod_mae: 0.0899 - val_min_oil_prod_mape: 92.6629 - val_max_oil_prod_mae: 0.0888 - val_max_oil_prod_mape: 81.5504 - best_max_oil_prod_mae: 0.0888 - val_avg_oil_prod_mae: 0.0862 - val_avg_oil_prod_mape: 79.1624 - best_avg_oil_prod_mae: 0.0862 - val_total_water_need_mae: 0.0594 - val_total_water_need_mape: 26.7003 - lr: 3.8749e-05\n",
      "Epoch 97/200\n",
      "81/81 [==============================] - 43s 527ms/step - loss: 0.0135 - mae: 0.1087 - mape: 93.9776 - val_loss: 0.0091 - val_mae: 0.0827 - val_mape: 74.7657 - lr: 3.7730e-05\n",
      "Epoch 98/200\n",
      "81/81 [==============================] - 43s 528ms/step - loss: 0.0134 - mae: 0.1088 - mape: 95.6354 - val_loss: 0.0091 - val_mae: 0.0811 - val_mape: 76.5250 - lr: 3.6738e-05\n",
      "Epoch 99/200\n",
      "81/81 [==============================] - 45s 541ms/step - loss: 0.0135 - mae: 0.1088 - mape: 105.4989 - val_loss: 0.0093 - val_mae: 0.0863 - val_mape: 75.0138 - lr: 3.5772e-05\n",
      "Epoch 100/200\n",
      "81/81 [==============================] - 44s 534ms/step - loss: 0.0134 - mae: 0.1085 - mape: 102.6167 - val_loss: 0.0091 - val_mae: 0.0833 - val_mape: 74.0674 - lr: 3.4831e-05\n",
      "Epoch 101/200\n",
      "81/81 [==============================] - 405s 5s/step - loss: 0.0134 - mae: 0.1088 - mape: 99.3198 - val_loss: 0.0094 - val_mae: 0.0860 - val_mape: 71.5030 - val_olive_prod_mae: 0.0935 - val_olive_prod_mape: 90.6842 - val_min_oil_prod_mae: 0.0939 - val_min_oil_prod_mape: 93.7380 - val_max_oil_prod_mae: 0.0917 - val_max_oil_prod_mape: 79.1902 - val_avg_oil_prod_mae: 0.0904 - val_avg_oil_prod_mape: 66.9787 - val_total_water_need_mae: 0.0603 - val_total_water_need_mape: 26.9237 - lr: 3.3916e-05\n",
      "Epoch 102/200\n",
      "81/81 [==============================] - 43s 526ms/step - loss: 0.0134 - mae: 0.1082 - mape: 96.7114 - val_loss: 0.0091 - val_mae: 0.0839 - val_mape: 73.3150 - lr: 3.3024e-05\n",
      "Epoch 103/200\n",
      "81/81 [==============================] - 44s 543ms/step - loss: 0.0132 - mae: 0.1078 - mape: 96.8080 - val_loss: 0.0090 - val_mae: 0.0836 - val_mape: 76.6545 - lr: 3.2156e-05\n",
      "Epoch 104/200\n",
      "81/81 [==============================] - ETA: 0s - loss: 0.0132 - mae: 0.1080 - mape: 103.5235\n",
      "Epoch 104: ReduceLROnPlateau reducing learning rate to 6.262018723646179e-06.\n",
      "81/81 [==============================] - 44s 541ms/step - loss: 0.0132 - mae: 0.1080 - mape: 103.5235 - val_loss: 0.0092 - val_mae: 0.0835 - val_mape: 74.9676 - lr: 3.1310e-05\n",
      "Epoch 105/200\n",
      "81/81 [==============================] - 45s 550ms/step - loss: 0.0132 - mae: 0.1080 - mape: 99.4297 - val_loss: 0.0088 - val_mae: 0.0815 - val_mape: 71.3449 - lr: 3.0487e-05\n",
      "Epoch 106/200\n",
      "81/81 [==============================] - 405s 5s/step - loss: 0.0133 - mae: 0.1075 - mape: 97.3356 - val_loss: 0.0088 - val_mae: 0.0813 - val_mape: 71.0418 - val_olive_prod_mae: 0.0902 - val_olive_prod_mape: 88.2805 - best_olive_prod_mae: 0.0902 - val_min_oil_prod_mae: 0.0891 - val_min_oil_prod_mape: 90.8285 - best_min_oil_prod_mae: 0.0891 - val_max_oil_prod_mae: 0.0890 - val_max_oil_prod_mape: 76.4075 - val_avg_oil_prod_mae: 0.0854 - val_avg_oil_prod_mape: 73.6663 - best_avg_oil_prod_mae: 0.0854 - val_total_water_need_mae: 0.0525 - val_total_water_need_mape: 26.0260 - best_total_water_need_mae: 0.0525 - lr: 2.9685e-05\n",
      "Epoch 107/200\n",
      "81/81 [==============================] - 46s 556ms/step - loss: 0.0131 - mae: 0.1077 - mape: 95.6784 - val_loss: 0.0086 - val_mae: 0.0803 - val_mape: 76.2398 - lr: 2.8905e-05\n",
      "Epoch 108/200\n",
      "81/81 [==============================] - 43s 520ms/step - loss: 0.0130 - mae: 0.1076 - mape: 97.3676 - val_loss: 0.0087 - val_mae: 0.0815 - val_mape: 72.6132 - lr: 2.8145e-05\n",
      "Epoch 109/200\n",
      "81/81 [==============================] - 44s 532ms/step - loss: 0.0130 - mae: 0.1074 - mape: 93.8073 - val_loss: 0.0088 - val_mae: 0.0831 - val_mape: 73.7144 - lr: 2.7405e-05\n",
      "Epoch 110/200\n",
      "81/81 [==============================] - 45s 547ms/step - loss: 0.0130 - mae: 0.1074 - mape: 98.0165 - val_loss: 0.0085 - val_mae: 0.0794 - val_mape: 74.5856 - lr: 2.6684e-05\n",
      "Epoch 111/200\n",
      "81/81 [==============================] - 421s 5s/step - loss: 0.0130 - mae: 0.1075 - mape: 98.1536 - val_loss: 0.0087 - val_mae: 0.0821 - val_mape: 72.5281 - val_olive_prod_mae: 0.0913 - val_olive_prod_mape: 89.8939 - val_min_oil_prod_mae: 0.0896 - val_min_oil_prod_mape: 93.7233 - val_max_oil_prod_mae: 0.0898 - val_max_oil_prod_mape: 76.0811 - val_avg_oil_prod_mae: 0.0865 - val_avg_oil_prod_mape: 75.4671 - val_total_water_need_mae: 0.0534 - val_total_water_need_mape: 27.4751 - lr: 2.5983e-05\n",
      "Epoch 112/200\n",
      "81/81 [==============================] - 45s 554ms/step - loss: 0.0130 - mae: 0.1073 - mape: 96.7342 - val_loss: 0.0087 - val_mae: 0.0815 - val_mape: 71.0408 - lr: 2.5300e-05\n",
      "Epoch 113/200\n",
      "81/81 [==============================] - 45s 550ms/step - loss: 0.0129 - mae: 0.1073 - mape: 93.0413 - val_loss: 0.0087 - val_mae: 0.0812 - val_mape: 70.8242 - lr: 2.4634e-05\n",
      "Epoch 114/200\n",
      "81/81 [==============================] - 44s 534ms/step - loss: 0.0129 - mae: 0.1073 - mape: 97.2687 - val_loss: 0.0089 - val_mae: 0.0836 - val_mape: 74.5174 - lr: 2.3987e-05\n",
      "Epoch 115/200\n",
      "81/81 [==============================] - 46s 563ms/step - loss: 0.0129 - mae: 0.1072 - mape: 97.5502 - val_loss: 0.0084 - val_mae: 0.0801 - val_mape: 70.5831 - lr: 2.3356e-05\n",
      "Epoch 116/200\n",
      "81/81 [==============================] - 410s 5s/step - loss: 0.0128 - mae: 0.1069 - mape: 99.3510 - val_loss: 0.0085 - val_mae: 0.0805 - val_mape: 70.4120 - val_olive_prod_mae: 0.0892 - val_olive_prod_mape: 89.7023 - best_olive_prod_mae: 0.0892 - val_min_oil_prod_mae: 0.0880 - val_min_oil_prod_mape: 91.7272 - best_min_oil_prod_mae: 0.0880 - val_max_oil_prod_mae: 0.0877 - val_max_oil_prod_mape: 75.6732 - best_max_oil_prod_mae: 0.0877 - val_avg_oil_prod_mae: 0.0848 - val_avg_oil_prod_mape: 69.0733 - best_avg_oil_prod_mae: 0.0848 - val_total_water_need_mae: 0.0528 - val_total_water_need_mape: 25.8832 - lr: 2.2742e-05\n",
      "Epoch 117/200\n",
      "81/81 [==============================] - 43s 518ms/step - loss: 0.0129 - mae: 0.1074 - mape: 101.2562 - val_loss: 0.0088 - val_mae: 0.0843 - val_mape: 70.6695 - lr: 2.2144e-05\n",
      "Epoch 118/200\n",
      "81/81 [==============================] - 45s 549ms/step - loss: 0.0128 - mae: 0.1069 - mape: 100.3844 - val_loss: 0.0087 - val_mae: 0.0824 - val_mape: 76.1144 - lr: 2.1562e-05\n",
      "Epoch 119/200\n",
      "81/81 [==============================] - 46s 557ms/step - loss: 0.0128 - mae: 0.1069 - mape: 99.9334 - val_loss: 0.0085 - val_mae: 0.0805 - val_mape: 73.0375 - lr: 2.0995e-05\n",
      "Epoch 120/200\n",
      "81/81 [==============================] - 45s 549ms/step - loss: 0.0128 - mae: 0.1070 - mape: 100.1810 - val_loss: 0.0085 - val_mae: 0.0815 - val_mape: 76.3325 - lr: 2.0443e-05\n",
      "Epoch 121/200\n",
      "81/81 [==============================] - 408s 5s/step - loss: 0.0128 - mae: 0.1069 - mape: 94.3632 - val_loss: 0.0086 - val_mae: 0.0817 - val_mape: 72.1149 - val_olive_prod_mae: 0.0906 - val_olive_prod_mape: 87.6058 - val_min_oil_prod_mae: 0.0886 - val_min_oil_prod_mape: 91.1811 - val_max_oil_prod_mae: 0.0890 - val_max_oil_prod_mape: 75.9044 - val_avg_oil_prod_mae: 0.0861 - val_avg_oil_prod_mape: 79.9283 - val_total_water_need_mae: 0.0544 - val_total_water_need_mape: 25.9553 - lr: 1.9905e-05\n",
      "Epoch 122/200\n",
      "81/81 [==============================] - 44s 539ms/step - loss: 0.0127 - mae: 0.1067 - mape: 95.9895 - val_loss: 0.0083 - val_mae: 0.0775 - val_mape: 74.3044 - lr: 1.9382e-05\n",
      "Epoch 123/200\n",
      "81/81 [==============================] - 45s 547ms/step - loss: 0.0127 - mae: 0.1068 - mape: 103.0387 - val_loss: 0.0084 - val_mae: 0.0787 - val_mape: 70.4848 - lr: 1.8872e-05\n",
      "Epoch 124/200\n",
      "81/81 [==============================] - 44s 534ms/step - loss: 0.0127 - mae: 0.1070 - mape: 101.5992 - val_loss: 0.0084 - val_mae: 0.0790 - val_mape: 76.9380 - lr: 1.8376e-05\n",
      "Epoch 125/200\n",
      "81/81 [==============================] - 43s 530ms/step - loss: 0.0127 - mae: 0.1066 - mape: 97.1413 - val_loss: 0.0084 - val_mae: 0.0793 - val_mape: 71.0964 - lr: 1.7893e-05\n",
      "Epoch 126/200\n",
      "81/81 [==============================] - 405s 5s/step - loss: 0.0127 - mae: 0.1067 - mape: 99.8651 - val_loss: 0.0083 - val_mae: 0.0798 - val_mape: 72.0929 - val_olive_prod_mae: 0.0891 - val_olive_prod_mape: 89.7311 - best_olive_prod_mae: 0.0891 - val_min_oil_prod_mae: 0.0881 - val_min_oil_prod_mape: 90.9031 - val_max_oil_prod_mae: 0.0879 - val_max_oil_prod_mape: 76.2289 - val_avg_oil_prod_mae: 0.0848 - val_avg_oil_prod_mape: 77.5775 - val_total_water_need_mae: 0.0491 - val_total_water_need_mape: 26.0246 - best_total_water_need_mae: 0.0491 - lr: 1.7423e-05\n",
      "Epoch 127/200\n",
      "81/81 [==============================] - 44s 535ms/step - loss: 0.0126 - mae: 0.1068 - mape: 95.1028 - val_loss: 0.0081 - val_mae: 0.0781 - val_mape: 71.2596 - lr: 1.6965e-05\n",
      "Epoch 128/200\n",
      "81/81 [==============================] - 45s 552ms/step - loss: 0.0127 - mae: 0.1067 - mape: 93.2160 - val_loss: 0.0084 - val_mae: 0.0812 - val_mape: 69.7919 - lr: 1.6518e-05\n",
      "Epoch 129/200\n",
      "81/81 [==============================] - 46s 564ms/step - loss: 0.0127 - mae: 0.1067 - mape: 95.8274 - val_loss: 0.0082 - val_mae: 0.0793 - val_mape: 71.5809 - lr: 1.6084e-05\n",
      "Epoch 130/200\n",
      "81/81 [==============================] - 43s 525ms/step - loss: 0.0125 - mae: 0.1064 - mape: 94.9175 - val_loss: 0.0084 - val_mae: 0.0789 - val_mape: 72.1971 - lr: 1.5661e-05\n",
      "Epoch 131/200\n",
      "81/81 [==============================] - 414s 5s/step - loss: 0.0126 - mae: 0.1064 - mape: 101.2890 - val_loss: 0.0083 - val_mae: 0.0800 - val_mape: 71.2394 - val_olive_prod_mae: 0.0891 - val_olive_prod_mape: 91.4833 - best_olive_prod_mae: 0.0891 - val_min_oil_prod_mae: 0.0879 - val_min_oil_prod_mape: 92.5499 - best_min_oil_prod_mae: 0.0879 - val_max_oil_prod_mae: 0.0879 - val_max_oil_prod_mape: 76.0341 - val_avg_oil_prod_mae: 0.0850 - val_avg_oil_prod_mape: 69.7731 - val_total_water_need_mae: 0.0500 - val_total_water_need_mape: 26.3569 - lr: 1.5250e-05\n",
      "Epoch 132/200\n",
      "81/81 [==============================] - 46s 557ms/step - loss: 0.0125 - mae: 0.1063 - mape: 97.2383 - val_loss: 0.0082 - val_mae: 0.0788 - val_mape: 70.9983 - lr: 1.4849e-05\n",
      "Epoch 133/200\n",
      "81/81 [==============================] - 42s 517ms/step - loss: 0.0125 - mae: 0.1065 - mape: 100.5532 - val_loss: 0.0083 - val_mae: 0.0797 - val_mape: 70.9532 - lr: 1.4458e-05\n",
      "Epoch 134/200\n",
      "81/81 [==============================] - 45s 549ms/step - loss: 0.0125 - mae: 0.1062 - mape: 91.1623 - val_loss: 0.0082 - val_mae: 0.0794 - val_mape: 70.6925 - lr: 1.4078e-05\n",
      "Epoch 135/200\n",
      "81/81 [==============================] - 46s 565ms/step - loss: 0.0125 - mae: 0.1062 - mape: 100.0002 - val_loss: 0.0083 - val_mae: 0.0803 - val_mape: 71.6639 - lr: 1.3708e-05\n",
      "Epoch 136/200\n",
      "81/81 [==============================] - 408s 5s/step - loss: 0.0125 - mae: 0.1062 - mape: 98.6318 - val_loss: 0.0083 - val_mae: 0.0795 - val_mape: 71.3979 - val_olive_prod_mae: 0.0890 - val_olive_prod_mape: 89.4010 - best_olive_prod_mae: 0.0890 - val_min_oil_prod_mae: 0.0877 - val_min_oil_prod_mape: 91.2028 - best_min_oil_prod_mae: 0.0877 - val_max_oil_prod_mae: 0.0877 - val_max_oil_prod_mape: 75.7092 - val_avg_oil_prod_mae: 0.0847 - val_avg_oil_prod_mape: 75.1019 - best_avg_oil_prod_mae: 0.0847 - val_total_water_need_mae: 0.0482 - val_total_water_need_mape: 25.5753 - best_total_water_need_mae: 0.0482 - lr: 1.3347e-05\n",
      "Epoch 137/200\n",
      "81/81 [==============================] - 46s 564ms/step - loss: 0.0125 - mae: 0.1065 - mape: 94.3227 - val_loss: 0.0081 - val_mae: 0.0783 - val_mape: 75.9415 - lr: 1.2997e-05\n",
      "Epoch 138/200\n",
      "81/81 [==============================] - 46s 554ms/step - loss: 0.0125 - mae: 0.1063 - mape: 97.7030 - val_loss: 0.0082 - val_mae: 0.0791 - val_mape: 72.1331 - lr: 1.2655e-05\n",
      "Epoch 139/200\n",
      "81/81 [==============================] - 43s 526ms/step - loss: 0.0125 - mae: 0.1061 - mape: 98.8603 - val_loss: 0.0083 - val_mae: 0.0795 - val_mape: 72.5747 - lr: 1.2322e-05\n",
      "Epoch 140/200\n",
      "81/81 [==============================] - 43s 522ms/step - loss: 0.0124 - mae: 0.1061 - mape: 96.8847 - val_loss: 0.0083 - val_mae: 0.0793 - val_mape: 69.8753 - lr: 1.1998e-05\n",
      "Epoch 141/200\n",
      "81/81 [==============================] - 398s 5s/step - loss: 0.0124 - mae: 0.1062 - mape: 95.8760 - val_loss: 0.0082 - val_mae: 0.0790 - val_mape: 71.8602 - val_olive_prod_mae: 0.0878 - val_olive_prod_mape: 91.0793 - best_olive_prod_mae: 0.0878 - val_min_oil_prod_mae: 0.0876 - val_min_oil_prod_mape: 92.5032 - best_min_oil_prod_mae: 0.0876 - val_max_oil_prod_mae: 0.0871 - val_max_oil_prod_mape: 76.3926 - best_max_oil_prod_mae: 0.0871 - val_avg_oil_prod_mae: 0.0844 - val_avg_oil_prod_mape: 73.0280 - best_avg_oil_prod_mae: 0.0844 - val_total_water_need_mae: 0.0480 - val_total_water_need_mape: 26.2976 - best_total_water_need_mae: 0.0480 - lr: 1.1683e-05\n",
      "Epoch 142/200\n",
      "81/81 [==============================] - ETA: 0s - loss: 0.0124 - mae: 0.1059 - mape: 93.7385\n",
      "Epoch 142: ReduceLROnPlateau reducing learning rate to 2.2750975404051134e-06.\n",
      "81/81 [==============================] - 43s 521ms/step - loss: 0.0124 - mae: 0.1059 - mape: 93.7385 - val_loss: 0.0081 - val_mae: 0.0781 - val_mape: 71.1219 - lr: 1.1375e-05\n",
      "Epoch 143/200\n",
      "81/81 [==============================] - 43s 524ms/step - loss: 0.0124 - mae: 0.1062 - mape: 96.3209 - val_loss: 0.0082 - val_mae: 0.0806 - val_mape: 71.3129 - lr: 1.1076e-05\n",
      "Epoch 144/200\n",
      "81/81 [==============================] - 43s 530ms/step - loss: 0.0124 - mae: 0.1062 - mape: 95.7396 - val_loss: 0.0082 - val_mae: 0.0809 - val_mape: 71.7618 - lr: 1.0785e-05\n",
      "Epoch 145/200\n",
      "81/81 [==============================] - 45s 547ms/step - loss: 0.0123 - mae: 0.1058 - mape: 101.4618 - val_loss: 0.0081 - val_mae: 0.0782 - val_mape: 70.8179 - lr: 1.0502e-05\n",
      "Epoch 146/200\n",
      "81/81 [==============================] - 385s 5s/step - loss: 0.0124 - mae: 0.1063 - mape: 97.9897 - val_loss: 0.0082 - val_mae: 0.0797 - val_mape: 70.4109 - val_olive_prod_mae: 0.0886 - val_olive_prod_mape: 89.7785 - val_min_oil_prod_mae: 0.0879 - val_min_oil_prod_mape: 92.4329 - val_max_oil_prod_mae: 0.0875 - val_max_oil_prod_mape: 76.0445 - val_avg_oil_prod_mae: 0.0847 - val_avg_oil_prod_mape: 67.6560 - val_total_water_need_mae: 0.0498 - val_total_water_need_mape: 26.1428 - lr: 1.0225e-05\n",
      "Epoch 147/200\n",
      "81/81 [==============================] - 45s 545ms/step - loss: 0.0123 - mae: 0.1060 - mape: 99.9797 - val_loss: 0.0081 - val_mae: 0.0788 - val_mape: 70.8160 - lr: 9.9566e-06\n",
      "Epoch 148/200\n",
      "81/81 [==============================] - 43s 527ms/step - loss: 0.0123 - mae: 0.1059 - mape: 97.9168 - val_loss: 0.0081 - val_mae: 0.0787 - val_mape: 70.3717 - lr: 9.6949e-06\n",
      "Epoch 149/200\n",
      "81/81 [==============================] - 43s 520ms/step - loss: 0.0123 - mae: 0.1061 - mape: 91.6191 - val_loss: 0.0081 - val_mae: 0.0788 - val_mape: 72.8542 - lr: 9.4400e-06\n",
      "Epoch 150/200\n",
      "81/81 [==============================] - 44s 537ms/step - loss: 0.0124 - mae: 0.1060 - mape: 95.8393 - val_loss: 0.0082 - val_mae: 0.0798 - val_mape: 72.8548 - lr: 9.1918e-06\n",
      "Epoch 151/200\n",
      "81/81 [==============================] - 400s 5s/step - loss: 0.0123 - mae: 0.1058 - mape: 101.8415 - val_loss: 0.0083 - val_mae: 0.0796 - val_mape: 72.3389 - val_olive_prod_mae: 0.0884 - val_olive_prod_mape: 88.7991 - val_min_oil_prod_mae: 0.0875 - val_min_oil_prod_mape: 91.5470 - best_min_oil_prod_mae: 0.0875 - val_max_oil_prod_mae: 0.0873 - val_max_oil_prod_mape: 76.2444 - val_avg_oil_prod_mae: 0.0844 - val_avg_oil_prod_mape: 79.9107 - best_avg_oil_prod_mae: 0.0844 - val_total_water_need_mae: 0.0503 - val_total_water_need_mape: 25.1932 - lr: 8.9501e-06\n",
      "Epoch 152/200\n",
      "81/81 [==============================] - 44s 531ms/step - loss: 0.0122 - mae: 0.1058 - mape: 96.1754 - val_loss: 0.0081 - val_mae: 0.0793 - val_mape: 71.8548 - lr: 8.7148e-06\n",
      "\n",
      "Modello salvato in: 2024-12-19_23-39_final_model.keras\n",
      "Warning: Could not save model: name 'json' is not defined\n"
     ]
    }
   ],
   "source": [
    "model, history = train_transformer(train_data, train_targets, val_data, val_targets, 200, 32768)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "3e2fb5a5341dac92",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "25500/25500 [==============================] - 378s 15ms/step\n",
      "\n",
      "Errori per target:\n",
      "--------------------------------------------------\n",
      "olive_prod:\n",
      "MAE assoluto: 1438.01\n",
      "Errore percentuale medio: 5.63%\n",
      "Precisione: 94.37%\n",
      "--------------------------------------------------\n",
      "min_oil_prod:\n",
      "MAE assoluto: 296.21\n",
      "Errore percentuale medio: 5.78%\n",
      "Precisione: 94.22%\n",
      "--------------------------------------------------\n",
      "max_oil_prod:\n",
      "MAE assoluto: 356.48\n",
      "Errore percentuale medio: 5.76%\n",
      "Precisione: 94.24%\n",
      "--------------------------------------------------\n",
      "avg_oil_prod:\n",
      "MAE assoluto: 313.20\n",
      "Errore percentuale medio: 5.53%\n",
      "Precisione: 94.47%\n",
      "--------------------------------------------------\n",
      "total_water_need:\n",
      "MAE assoluto: 511.21\n",
      "Errore percentuale medio: 3.23%\n",
      "Precisione: 96.77%\n",
      "--------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "percentage_errors, absolute_errors = calculate_real_error(model, val_data, val_targets, scaler_y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "4af58aa9bbc156f5",
   "metadata": {},
   "outputs": [],
   "source": [
    "def evaluate_model_performance(model, data, targets, set_name=\"\"):\n",
    "    \"\"\"\n",
    "    Valuta le performance del modello su un set di dati specifico.\n",
    "    \"\"\"\n",
    "    predictions = model.predict(data, verbose=0)\n",
    "\n",
    "    target_names = ['olive_prod', 'min_oil_prod', 'max_oil_prod', 'avg_oil_prod', 'total_water_need']\n",
    "    metrics = {}\n",
    "\n",
    "    for i, name in enumerate(target_names):\n",
    "        mae = np.mean(np.abs(targets[:, i] - predictions[:, i]))\n",
    "        mse = np.mean(np.square(targets[:, i] - predictions[:, i]))\n",
    "        rmse = np.sqrt(mse)\n",
    "        mape = np.mean(np.abs((targets[:, i] - predictions[:, i]) / (targets[:, i] + 1e-7))) * 100\n",
    "\n",
    "        metrics[f\"{name}_mae\"] = mae\n",
    "        metrics[f\"{name}_rmse\"] = rmse\n",
    "        metrics[f\"{name}_mape\"] = mape\n",
    "\n",
    "    if set_name:\n",
    "        print(f\"\\nPerformance sul set {set_name}:\")\n",
    "        for metric, value in metrics.items():\n",
    "            print(f\"{metric}: {value:.4f}\")\n",
    "\n",
    "    return metrics\n",
    "\n",
    "\n",
    "def retrain_model(base_model, train_data, train_targets,\n",
    "                  val_data, val_targets,\n",
    "                  test_data, test_targets,\n",
    "                  epochs=50, batch_size=128):\n",
    "    \"\"\"\n",
    "    Implementa il retraining del modello con i dati combinati.\n",
    "    \"\"\"\n",
    "    print(\"Valutazione performance iniziali del modello...\")\n",
    "    initial_metrics = {\n",
    "        'train': evaluate_model_performance(base_model, train_data, train_targets, \"training\"),\n",
    "        'val': evaluate_model_performance(base_model, val_data, val_targets, \"validazione\"),\n",
    "        'test': evaluate_model_performance(base_model, test_data, test_targets, \"test\")\n",
    "    }\n",
    "\n",
    "    # Combina i dati per il retraining\n",
    "    combined_data = {\n",
    "        'temporal': np.concatenate([train_data['temporal'], val_data['temporal'], test_data['temporal']]),\n",
    "        'static': np.concatenate([train_data['static'], val_data['static'], test_data['static']])\n",
    "    }\n",
    "    combined_targets = np.concatenate([train_targets, val_targets, test_targets])\n",
    "\n",
    "    # Crea una nuova suddivisione per la validazione\n",
    "    indices = np.arange(len(combined_targets))\n",
    "    np.random.shuffle(indices)\n",
    "\n",
    "    split_idx = int(len(indices) * 0.9)\n",
    "    train_idx, val_idx = indices[:split_idx], indices[split_idx:]\n",
    "\n",
    "    # Prepara i dati per il retraining\n",
    "    retrain_data = {k: v[train_idx] for k, v in combined_data.items()}\n",
    "    retrain_targets = combined_targets[train_idx]\n",
    "    retrain_val_data = {k: v[val_idx] for k, v in combined_data.items()}\n",
    "    retrain_val_targets = combined_targets[val_idx]\n",
    "\n",
    "    # Configura callbacks\n",
    "    callbacks = [\n",
    "        tf.keras.callbacks.EarlyStopping(\n",
    "            monitor='val_loss',\n",
    "            patience=10,\n",
    "            restore_best_weights=True,\n",
    "            min_delta=0.0001\n",
    "        ),\n",
    "        tf.keras.callbacks.ReduceLROnPlateau(\n",
    "            monitor='val_loss',\n",
    "            factor=0.2,\n",
    "            patience=5,\n",
    "            min_lr=1e-6,\n",
    "            verbose=1\n",
    "        ),\n",
    "        tf.keras.callbacks.ModelCheckpoint(\n",
    "            filepath=f'{execute_name}_retrained_best_oil_model.h5',\n",
    "            monitor='val_loss',\n",
    "            save_best_only=True,\n",
    "            mode='min',\n",
    "            save_weights_only=True\n",
    "        )\n",
    "    ]\n",
    "\n",
    "    # Imposta learning rate per il fine-tuning\n",
    "    optimizer = tf.keras.optimizers.AdamW(\n",
    "        learning_rate=tf.keras.optimizers.schedules.ExponentialDecay(\n",
    "            initial_learning_rate=1e-4,\n",
    "            decay_steps=1000,\n",
    "            decay_rate=0.9\n",
    "        ),\n",
    "        weight_decay=0.01\n",
    "    )\n",
    "\n",
    "    # Ricompila il modello con il nuovo optimizer\n",
    "    base_model.compile(\n",
    "        optimizer=optimizer,\n",
    "        loss=tf.keras.losses.Huber(),\n",
    "        metrics=['mae']\n",
    "    )\n",
    "\n",
    "    print(\"\\nAvvio retraining...\")\n",
    "    history = base_model.fit(\n",
    "        retrain_data,\n",
    "        retrain_targets,\n",
    "        validation_data=(retrain_val_data, retrain_val_targets),\n",
    "        epochs=epochs,\n",
    "        batch_size=batch_size,\n",
    "        callbacks=callbacks,\n",
    "        verbose=1\n",
    "    )\n",
    "\n",
    "    print(\"\\nValutazione performance finali...\")\n",
    "    final_metrics = {\n",
    "        'train': evaluate_model_performance(base_model, train_data, train_targets, \"training\"),\n",
    "        'val': evaluate_model_performance(base_model, val_data, val_targets, \"validazione\"),\n",
    "        'test': evaluate_model_performance(base_model, test_data, test_targets, \"test\")\n",
    "    }\n",
    "\n",
    "    # Salva il modello finale\n",
    "    save_path = f'{execute_name}_retrained_model.keras'\n",
    "    os.makedirs(f'{execute_name}_retrained/weights', exist_ok=True)\n",
    "    \n",
    "    base_model.save_weights(f'{execute_name}_retrained/weights')\n",
    "    base_model.save(save_path, save_format='keras')\n",
    "    print(f\"\\nModello riaddestrato salvato in: {save_path}\")\n",
    "\n",
    "    # Report miglioramenti\n",
    "    print(\"\\nMiglioramenti delle performance:\")\n",
    "    for dataset in ['train', 'val', 'test']:\n",
    "        print(f\"\\nSet {dataset}:\")\n",
    "        for metric in initial_metrics[dataset].keys():\n",
    "            initial = initial_metrics[dataset][metric]\n",
    "            final = final_metrics[dataset][metric]\n",
    "            improvement = ((initial - final) / initial) * 100\n",
    "            print(f\"{metric}: {improvement:.2f}% di miglioramento\")\n",
    "\n",
    "    return base_model, history, final_metrics\n",
    "\n",
    "\n",
    "def start_retraining(model_path, train_data, train_targets,\n",
    "                     val_data, val_targets,\n",
    "                     test_data, test_targets,\n",
    "                     epochs=50, batch_size=128):\n",
    "    \"\"\"\n",
    "    Avvia il processo di retraining in modo sicuro.\n",
    "    \"\"\"\n",
    "    try:\n",
    "        print(\"Caricamento del modello...\")\n",
    "        base_model = tf.keras.models.load_model(model_path, compile=False)\n",
    "        print(\"Modello caricato con successo!\")\n",
    "\n",
    "        return retrain_model(\n",
    "            base_model=base_model,\n",
    "            train_data=train_data,\n",
    "            train_targets=train_targets,\n",
    "            val_data=val_data,\n",
    "            val_targets=val_targets,\n",
    "            test_data=test_data,\n",
    "            test_targets=test_targets,\n",
    "            epochs=epochs,\n",
    "            batch_size=batch_size\n",
    "        )\n",
    "    except Exception as e:\n",
    "        print(f\"Errore durante il retraining: {str(e)}\")\n",
    "        raise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "588c7e49371f4a0c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Caricamento del modello...\n",
      "Modello caricato con successo!\n",
      "Valutazione performance iniziali del modello...\n",
      "\n",
      "Performance sul set training:\n",
      "olive_prod_mae: 0.0875\n",
      "olive_prod_rmse: 0.1181\n",
      "olive_prod_mape: 92.6990\n",
      "min_oil_prod_mae: 0.0867\n",
      "min_oil_prod_rmse: 0.1208\n",
      "min_oil_prod_mape: 81.7229\n",
      "max_oil_prod_mae: 0.0862\n",
      "max_oil_prod_rmse: 0.1200\n",
      "max_oil_prod_mape: 83.8850\n",
      "avg_oil_prod_mae: 0.0830\n",
      "avg_oil_prod_rmse: 0.1148\n",
      "avg_oil_prod_mape: 74.0966\n",
      "total_water_need_mae: 0.0467\n",
      "total_water_need_rmse: 0.0635\n",
      "total_water_need_mape: 37.3349\n",
      "\n",
      "Performance sul set validazione:\n",
      "olive_prod_mae: 0.0875\n",
      "olive_prod_rmse: 0.1181\n",
      "olive_prod_mape: 94.3014\n",
      "min_oil_prod_mae: 0.0868\n",
      "min_oil_prod_rmse: 0.1209\n",
      "min_oil_prod_mape: 91.2537\n",
      "max_oil_prod_mae: 0.0862\n",
      "max_oil_prod_rmse: 0.1199\n",
      "max_oil_prod_mape: 75.9864\n",
      "avg_oil_prod_mae: 0.0831\n",
      "avg_oil_prod_rmse: 0.1148\n",
      "avg_oil_prod_mape: 70.9473\n",
      "total_water_need_mae: 0.0467\n",
      "total_water_need_rmse: 0.0635\n",
      "total_water_need_mape: 25.8122\n",
      "\n",
      "Performance sul set test:\n",
      "olive_prod_mae: 0.0874\n",
      "olive_prod_rmse: 0.1181\n",
      "olive_prod_mape: 95.5103\n",
      "min_oil_prod_mae: 0.0866\n",
      "min_oil_prod_rmse: 0.1208\n",
      "min_oil_prod_mape: 228.7476\n",
      "max_oil_prod_mae: 0.0862\n",
      "max_oil_prod_rmse: 0.1201\n",
      "max_oil_prod_mape: 222.9631\n",
      "avg_oil_prod_mae: 0.0830\n",
      "avg_oil_prod_rmse: 0.1148\n",
      "avg_oil_prod_mape: 92.3280\n",
      "total_water_need_mae: 0.0467\n",
      "total_water_need_rmse: 0.0635\n",
      "total_water_need_mape: 43.6031\n",
      "\n",
      "Avvio retraining...\n",
      "Epoch 1/100\n",
      "225/225 [==============================] - 90s 220ms/step - loss: 0.0151 - mae: 0.1089 - val_loss: 0.0104 - val_mae: 0.0893 - lr: 9.7668e-05\n",
      "Epoch 2/100\n",
      "225/225 [==============================] - 46s 204ms/step - loss: 0.0147 - mae: 0.1077 - val_loss: 0.0104 - val_mae: 0.0918 - lr: 9.5379e-05\n",
      "Epoch 3/100\n",
      "225/225 [==============================] - 42s 185ms/step - loss: 0.0146 - mae: 0.1073 - val_loss: 0.0109 - val_mae: 0.0958 - lr: 9.3145e-05\n",
      "Epoch 4/100\n",
      "225/225 [==============================] - 46s 206ms/step - loss: 0.0143 - mae: 0.1070 - val_loss: 0.0094 - val_mae: 0.0827 - lr: 9.0963e-05\n",
      "Epoch 5/100\n",
      "225/225 [==============================] - 46s 204ms/step - loss: 0.0140 - mae: 0.1062 - val_loss: 0.0097 - val_mae: 0.0887 - lr: 8.8832e-05\n",
      "Epoch 6/100\n",
      "225/225 [==============================] - 47s 209ms/step - loss: 0.0146 - mae: 0.1089 - val_loss: 0.0100 - val_mae: 0.0885 - lr: 8.6751e-05\n",
      "Epoch 7/100\n",
      "225/225 [==============================] - 44s 196ms/step - loss: 0.0138 - mae: 0.1061 - val_loss: 0.0093 - val_mae: 0.0823 - lr: 8.4718e-05\n",
      "Epoch 8/100\n",
      "225/225 [==============================] - 48s 216ms/step - loss: 0.0136 - mae: 0.1057 - val_loss: 0.0094 - val_mae: 0.0845 - lr: 8.2734e-05\n",
      "Epoch 9/100\n",
      "225/225 [==============================] - 44s 194ms/step - loss: 0.0135 - mae: 0.1056 - val_loss: 0.0096 - val_mae: 0.0851 - lr: 8.0795e-05\n",
      "Epoch 10/100\n",
      "225/225 [==============================] - 43s 192ms/step - loss: 0.0134 - mae: 0.1048 - val_loss: 0.0094 - val_mae: 0.0835 - lr: 7.8903e-05\n",
      "Epoch 11/100\n",
      "225/225 [==============================] - 46s 204ms/step - loss: 0.0132 - mae: 0.1045 - val_loss: 0.0090 - val_mae: 0.0827 - lr: 7.7054e-05\n",
      "Epoch 12/100\n",
      "225/225 [==============================] - 46s 205ms/step - loss: 0.0130 - mae: 0.1042 - val_loss: 0.0090 - val_mae: 0.0809 - lr: 7.5249e-05\n",
      "Epoch 13/100\n",
      "225/225 [==============================] - 44s 194ms/step - loss: 0.0129 - mae: 0.1040 - val_loss: 0.0093 - val_mae: 0.0840 - lr: 7.3486e-05\n",
      "Epoch 14/100\n",
      "225/225 [==============================] - 46s 202ms/step - loss: 0.0128 - mae: 0.1037 - val_loss: 0.0089 - val_mae: 0.0801 - lr: 7.1764e-05\n",
      "Epoch 15/100\n",
      "225/225 [==============================] - 45s 201ms/step - loss: 0.0126 - mae: 0.1033 - val_loss: 0.0088 - val_mae: 0.0819 - lr: 7.0083e-05\n",
      "Epoch 16/100\n",
      "225/225 [==============================] - 45s 202ms/step - loss: 0.0125 - mae: 0.1030 - val_loss: 0.0088 - val_mae: 0.0833 - lr: 6.8441e-05\n",
      "Epoch 17/100\n",
      "225/225 [==============================] - 45s 199ms/step - loss: 0.0124 - mae: 0.1029 - val_loss: 0.0083 - val_mae: 0.0797 - lr: 6.6838e-05\n",
      "Epoch 18/100\n",
      "225/225 [==============================] - 43s 189ms/step - loss: 0.0123 - mae: 0.1027 - val_loss: 0.0089 - val_mae: 0.0835 - lr: 6.5272e-05\n",
      "Epoch 19/100\n",
      "225/225 [==============================] - 43s 192ms/step - loss: 0.0121 - mae: 0.1024 - val_loss: 0.0090 - val_mae: 0.0844 - lr: 6.3743e-05\n",
      "Epoch 20/100\n",
      "225/225 [==============================] - 44s 194ms/step - loss: 0.0121 - mae: 0.1025 - val_loss: 0.0089 - val_mae: 0.0839 - lr: 6.2250e-05\n",
      "Epoch 21/100\n",
      "225/225 [==============================] - 45s 201ms/step - loss: 0.0119 - mae: 0.1019 - val_loss: 0.0086 - val_mae: 0.0809 - lr: 6.0791e-05\n",
      "Epoch 22/100\n",
      "225/225 [==============================] - ETA: 0s - loss: 0.0118 - mae: 0.1017\n",
      "Epoch 22: ReduceLROnPlateau reducing learning rate to 1.1873427138198168e-05.\n",
      "225/225 [==============================] - 46s 205ms/step - loss: 0.0118 - mae: 0.1017 - val_loss: 0.0082 - val_mae: 0.0789 - lr: 5.9367e-05\n",
      "Epoch 23/100\n",
      "225/225 [==============================] - 46s 205ms/step - loss: 0.0117 - mae: 0.1014 - val_loss: 0.0081 - val_mae: 0.0794 - lr: 5.7976e-05\n",
      "Epoch 24/100\n",
      "225/225 [==============================] - 44s 197ms/step - loss: 0.0116 - mae: 0.1011 - val_loss: 0.0080 - val_mae: 0.0783 - lr: 5.6618e-05\n",
      "Epoch 25/100\n",
      "225/225 [==============================] - 46s 202ms/step - loss: 0.0115 - mae: 0.1009 - val_loss: 0.0080 - val_mae: 0.0773 - lr: 5.5292e-05\n",
      "Epoch 26/100\n",
      "225/225 [==============================] - 46s 206ms/step - loss: 0.0115 - mae: 0.1008 - val_loss: 0.0080 - val_mae: 0.0775 - lr: 5.3996e-05\n",
      "Epoch 27/100\n",
      "225/225 [==============================] - 45s 199ms/step - loss: 0.0114 - mae: 0.1005 - val_loss: 0.0077 - val_mae: 0.0763 - lr: 5.2731e-05\n",
      "Epoch 28/100\n",
      "225/225 [==============================] - 45s 201ms/step - loss: 0.0113 - mae: 0.1004 - val_loss: 0.0082 - val_mae: 0.0779 - lr: 5.1496e-05\n",
      "Epoch 29/100\n",
      "225/225 [==============================] - 47s 206ms/step - loss: 0.0112 - mae: 0.1002 - val_loss: 0.0077 - val_mae: 0.0758 - lr: 5.0290e-05\n",
      "Epoch 30/100\n",
      "225/225 [==============================] - 45s 201ms/step - loss: 0.0111 - mae: 0.1000 - val_loss: 0.0078 - val_mae: 0.0775 - lr: 4.9111e-05\n",
      "Epoch 31/100\n",
      "225/225 [==============================] - 45s 199ms/step - loss: 0.0111 - mae: 0.0998 - val_loss: 0.0077 - val_mae: 0.0769 - lr: 4.7961e-05\n",
      "Epoch 32/100\n",
      "225/225 [==============================] - ETA: 0s - loss: 0.0110 - mae: 0.0997\n",
      "Epoch 32: ReduceLROnPlateau reducing learning rate to 9.367457096232101e-06.\n",
      "225/225 [==============================] - 45s 200ms/step - loss: 0.0110 - mae: 0.0997 - val_loss: 0.0077 - val_mae: 0.0761 - lr: 4.6837e-05\n",
      "Epoch 33/100\n",
      "225/225 [==============================] - 44s 195ms/step - loss: 0.0109 - mae: 0.0994 - val_loss: 0.0076 - val_mae: 0.0760 - lr: 4.5740e-05\n",
      "Epoch 34/100\n",
      "225/225 [==============================] - 45s 202ms/step - loss: 0.0109 - mae: 0.0993 - val_loss: 0.0076 - val_mae: 0.0767 - lr: 4.4668e-05\n",
      "Epoch 35/100\n",
      "225/225 [==============================] - 45s 200ms/step - loss: 0.0108 - mae: 0.0992 - val_loss: 0.0077 - val_mae: 0.0781 - lr: 4.3622e-05\n",
      "Epoch 36/100\n",
      "225/225 [==============================] - 45s 199ms/step - loss: 0.0108 - mae: 0.0991 - val_loss: 0.0079 - val_mae: 0.0787 - lr: 4.2600e-05\n",
      "Epoch 37/100\n",
      "225/225 [==============================] - 45s 201ms/step - loss: 0.0107 - mae: 0.0989 - val_loss: 0.0074 - val_mae: 0.0758 - lr: 4.1602e-05\n",
      "Epoch 38/100\n",
      "225/225 [==============================] - 43s 192ms/step - loss: 0.0107 - mae: 0.0987 - val_loss: 0.0076 - val_mae: 0.0770 - lr: 4.0627e-05\n",
      "Epoch 39/100\n",
      "225/225 [==============================] - 43s 192ms/step - loss: 0.0106 - mae: 0.0986 - val_loss: 0.0074 - val_mae: 0.0770 - lr: 3.9676e-05\n",
      "Epoch 40/100\n",
      "225/225 [==============================] - 46s 204ms/step - loss: 0.0106 - mae: 0.0985 - val_loss: 0.0075 - val_mae: 0.0762 - lr: 3.8746e-05\n",
      "Epoch 41/100\n",
      "225/225 [==============================] - 46s 204ms/step - loss: 0.0105 - mae: 0.0983 - val_loss: 0.0072 - val_mae: 0.0759 - lr: 3.7838e-05\n",
      "Epoch 42/100\n",
      "225/225 [==============================] - 45s 200ms/step - loss: 0.0105 - mae: 0.0983 - val_loss: 0.0075 - val_mae: 0.0761 - lr: 3.6952e-05\n",
      "Epoch 43/100\n",
      "225/225 [==============================] - 43s 190ms/step - loss: 0.0104 - mae: 0.0982 - val_loss: 0.0072 - val_mae: 0.0748 - lr: 3.6086e-05\n",
      "Epoch 44/100\n",
      "225/225 [==============================] - 44s 195ms/step - loss: 0.0104 - mae: 0.0981 - val_loss: 0.0073 - val_mae: 0.0770 - lr: 3.5241e-05\n",
      "Epoch 45/100\n",
      "225/225 [==============================] - 42s 187ms/step - loss: 0.0104 - mae: 0.0982 - val_loss: 0.0074 - val_mae: 0.0769 - lr: 3.4415e-05\n",
      "Epoch 46/100\n",
      "225/225 [==============================] - ETA: 0s - loss: 0.0104 - mae: 0.0984\n",
      "Epoch 46: ReduceLROnPlateau reducing learning rate to 6.721798854414374e-06.\n",
      "225/225 [==============================] - 46s 204ms/step - loss: 0.0104 - mae: 0.0984 - val_loss: 0.0072 - val_mae: 0.0740 - lr: 3.3609e-05\n",
      "Epoch 47/100\n",
      "225/225 [==============================] - 45s 202ms/step - loss: 0.0103 - mae: 0.0978 - val_loss: 0.0072 - val_mae: 0.0745 - lr: 3.2822e-05\n",
      "Epoch 48/100\n",
      "225/225 [==============================] - 44s 197ms/step - loss: 0.0103 - mae: 0.0978 - val_loss: 0.0071 - val_mae: 0.0740 - lr: 3.2053e-05\n",
      "Epoch 49/100\n",
      "225/225 [==============================] - 47s 211ms/step - loss: 0.0103 - mae: 0.0977 - val_loss: 0.0070 - val_mae: 0.0746 - lr: 3.1302e-05\n",
      "Epoch 50/100\n",
      "225/225 [==============================] - 44s 196ms/step - loss: 0.0102 - mae: 0.0976 - val_loss: 0.0072 - val_mae: 0.0752 - lr: 3.0568e-05\n",
      "Epoch 51/100\n",
      "225/225 [==============================] - 43s 189ms/step - loss: 0.0102 - mae: 0.0975 - val_loss: 0.0070 - val_mae: 0.0742 - lr: 2.9852e-05\n",
      "Epoch 52/100\n",
      "225/225 [==============================] - 44s 197ms/step - loss: 0.0102 - mae: 0.0974 - val_loss: 0.0069 - val_mae: 0.0735 - lr: 2.9153e-05\n",
      "Epoch 53/100\n",
      "225/225 [==============================] - 46s 201ms/step - loss: 0.0102 - mae: 0.0974 - val_loss: 0.0070 - val_mae: 0.0738 - lr: 2.8470e-05\n",
      "Epoch 54/100\n",
      "225/225 [==============================] - 45s 198ms/step - loss: 0.0101 - mae: 0.0972 - val_loss: 0.0071 - val_mae: 0.0742 - lr: 2.7803e-05\n",
      "Epoch 55/100\n",
      "225/225 [==============================] - 45s 201ms/step - loss: 0.0101 - mae: 0.0972 - val_loss: 0.0070 - val_mae: 0.0744 - lr: 2.7152e-05\n",
      "Epoch 56/100\n",
      "225/225 [==============================] - 45s 202ms/step - loss: 0.0101 - mae: 0.0971 - val_loss: 0.0069 - val_mae: 0.0739 - lr: 2.6516e-05\n",
      "Epoch 57/100\n",
      "225/225 [==============================] - ETA: 0s - loss: 0.0100 - mae: 0.0970\n",
      "Epoch 57: ReduceLROnPlateau reducing learning rate to 5.178878927836195e-06.\n",
      "225/225 [==============================] - 50s 222ms/step - loss: 0.0100 - mae: 0.0970 - val_loss: 0.0068 - val_mae: 0.0738 - lr: 2.5894e-05\n",
      "Epoch 58/100\n",
      "225/225 [==============================] - 45s 198ms/step - loss: 0.0100 - mae: 0.0969 - val_loss: 0.0069 - val_mae: 0.0742 - lr: 2.5288e-05\n",
      "Epoch 59/100\n",
      "225/225 [==============================] - 47s 208ms/step - loss: 0.0100 - mae: 0.0969 - val_loss: 0.0070 - val_mae: 0.0744 - lr: 2.4695e-05\n",
      "Epoch 60/100\n",
      "225/225 [==============================] - 45s 199ms/step - loss: 0.0100 - mae: 0.0968 - val_loss: 0.0071 - val_mae: 0.0755 - lr: 2.4117e-05\n",
      "Epoch 61/100\n",
      "225/225 [==============================] - 43s 193ms/step - loss: 0.0100 - mae: 0.0968 - val_loss: 0.0069 - val_mae: 0.0738 - lr: 2.3552e-05\n",
      "Epoch 62/100\n",
      "225/225 [==============================] - ETA: 0s - loss: 0.0099 - mae: 0.0967\n",
      "Epoch 62: ReduceLROnPlateau reducing learning rate to 4.600007378030569e-06.\n",
      "225/225 [==============================] - 43s 192ms/step - loss: 0.0099 - mae: 0.0967 - val_loss: 0.0070 - val_mae: 0.0750 - lr: 2.3000e-05\n",
      "\n",
      "Valutazione performance finali...\n",
      "\n",
      "Performance sul set training:\n",
      "olive_prod_mae: 0.0839\n",
      "olive_prod_rmse: 0.1158\n",
      "olive_prod_mape: 90.9233\n",
      "min_oil_prod_mae: 0.0825\n",
      "min_oil_prod_rmse: 0.1166\n",
      "min_oil_prod_mape: 82.2691\n",
      "max_oil_prod_mae: 0.0821\n",
      "max_oil_prod_rmse: 0.1164\n",
      "max_oil_prod_mape: 82.9904\n",
      "avg_oil_prod_mae: 0.0798\n",
      "avg_oil_prod_rmse: 0.1124\n",
      "avg_oil_prod_mape: 74.0703\n",
      "total_water_need_mae: 0.0392\n",
      "total_water_need_rmse: 0.0563\n",
      "total_water_need_mape: 36.0925\n",
      "\n",
      "Performance sul set validazione:\n",
      "olive_prod_mae: 0.0839\n",
      "olive_prod_rmse: 0.1157\n",
      "olive_prod_mape: 95.2416\n",
      "min_oil_prod_mae: 0.0825\n",
      "min_oil_prod_rmse: 0.1166\n",
      "min_oil_prod_mape: 88.1669\n",
      "max_oil_prod_mae: 0.0820\n",
      "max_oil_prod_rmse: 0.1162\n",
      "max_oil_prod_mape: 75.9403\n",
      "avg_oil_prod_mae: 0.0798\n",
      "avg_oil_prod_rmse: 0.1123\n",
      "avg_oil_prod_mape: 69.5427\n",
      "total_water_need_mae: 0.0392\n",
      "total_water_need_rmse: 0.0562\n",
      "total_water_need_mape: 23.9373\n",
      "\n",
      "Performance sul set test:\n",
      "olive_prod_mae: 0.0839\n",
      "olive_prod_rmse: 0.1157\n",
      "olive_prod_mape: 96.0586\n",
      "min_oil_prod_mae: 0.0824\n",
      "min_oil_prod_rmse: 0.1165\n",
      "min_oil_prod_mape: 210.2095\n",
      "max_oil_prod_mae: 0.0821\n",
      "max_oil_prod_rmse: 0.1164\n",
      "max_oil_prod_mape: 223.1585\n",
      "avg_oil_prod_mae: 0.0798\n",
      "avg_oil_prod_rmse: 0.1123\n",
      "avg_oil_prod_mape: 95.1335\n",
      "total_water_need_mae: 0.0392\n",
      "total_water_need_rmse: 0.0563\n",
      "total_water_need_mape: 38.0699\n",
      "\n",
      "Modello riaddestrato salvato in: 2024-12-19_23-39_retrained_model.keras\n",
      "\n",
      "Miglioramenti delle performance:\n",
      "\n",
      "Set train:\n",
      "olive_prod_mae: 4.03% di miglioramento\n",
      "olive_prod_rmse: 1.98% di miglioramento\n",
      "olive_prod_mape: 1.92% di miglioramento\n",
      "min_oil_prod_mae: 4.90% di miglioramento\n",
      "min_oil_prod_rmse: 3.47% di miglioramento\n",
      "min_oil_prod_mape: -0.67% di miglioramento\n",
      "max_oil_prod_mae: 4.75% di miglioramento\n",
      "max_oil_prod_rmse: 3.00% di miglioramento\n",
      "max_oil_prod_mape: 1.07% di miglioramento\n",
      "avg_oil_prod_mae: 3.86% di miglioramento\n",
      "avg_oil_prod_rmse: 2.06% di miglioramento\n",
      "avg_oil_prod_mape: 0.04% di miglioramento\n",
      "total_water_need_mae: 16.11% di miglioramento\n",
      "total_water_need_rmse: 11.38% di miglioramento\n",
      "total_water_need_mape: 3.33% di miglioramento\n",
      "\n",
      "Set val:\n",
      "olive_prod_mae: 4.06% di miglioramento\n",
      "olive_prod_rmse: 2.06% di miglioramento\n",
      "olive_prod_mape: -1.00% di miglioramento\n",
      "min_oil_prod_mae: 4.96% di miglioramento\n",
      "min_oil_prod_rmse: 3.54% di miglioramento\n",
      "min_oil_prod_mape: 3.38% di miglioramento\n",
      "max_oil_prod_mae: 4.84% di miglioramento\n",
      "max_oil_prod_rmse: 3.11% di miglioramento\n",
      "max_oil_prod_mape: 0.06% di miglioramento\n",
      "avg_oil_prod_mae: 3.94% di miglioramento\n",
      "avg_oil_prod_rmse: 2.17% di miglioramento\n",
      "avg_oil_prod_mape: 1.98% di miglioramento\n",
      "total_water_need_mae: 16.07% di miglioramento\n",
      "total_water_need_rmse: 11.40% di miglioramento\n",
      "total_water_need_mape: 7.26% di miglioramento\n",
      "\n",
      "Set test:\n",
      "olive_prod_mae: 4.08% di miglioramento\n",
      "olive_prod_rmse: 2.05% di miglioramento\n",
      "olive_prod_mape: -0.57% di miglioramento\n",
      "min_oil_prod_mae: 4.94% di miglioramento\n",
      "min_oil_prod_rmse: 3.54% di miglioramento\n",
      "min_oil_prod_mape: 8.10% di miglioramento\n",
      "max_oil_prod_mae: 4.82% di miglioramento\n",
      "max_oil_prod_rmse: 3.09% di miglioramento\n",
      "max_oil_prod_mape: -0.09% di miglioramento\n",
      "avg_oil_prod_mae: 3.92% di miglioramento\n",
      "avg_oil_prod_rmse: 2.16% di miglioramento\n",
      "avg_oil_prod_mape: -3.04% di miglioramento\n",
      "total_water_need_mae: 16.15% di miglioramento\n",
      "total_water_need_rmse: 11.39% di miglioramento\n",
      "total_water_need_mape: 12.69% di miglioramento\n"
     ]
    }
   ],
   "source": [
    "model_path = f'{execute_name}_final_model.keras'\n",
    "\n",
    "retrained_model, retrain_history, final_metrics = start_retraining(\n",
    "    model_path=model_path,\n",
    "    train_data=train_data,\n",
    "    train_targets=train_targets,\n",
    "    val_data=val_data,\n",
    "    val_targets=val_targets,\n",
    "    test_data=test_data,\n",
    "    test_targets=test_targets,\n",
    "    epochs=100,\n",
    "    batch_size=16384\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "a95606bc-c4bc-418a-acdb-2e24c30dfa81",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "25500/25500 [==============================] - 393s 15ms/step\n",
      "\n",
      "Errori per target:\n",
      "--------------------------------------------------\n",
      "olive_prod:\n",
      "MAE assoluto: 1379.61\n",
      "Errore percentuale medio: 4.99%\n",
      "Precisione: 95.01%\n",
      "--------------------------------------------------\n",
      "min_oil_prod:\n",
      "MAE assoluto: 281.52\n",
      "Errore percentuale medio: 5.05%\n",
      "Precisione: 94.95%\n",
      "--------------------------------------------------\n",
      "max_oil_prod:\n",
      "MAE assoluto: 339.24\n",
      "Errore percentuale medio: 5.04%\n",
      "Precisione: 94.96%\n",
      "--------------------------------------------------\n",
      "avg_oil_prod:\n",
      "MAE assoluto: 300.87\n",
      "Errore percentuale medio: 4.88%\n",
      "Precisione: 95.12%\n",
      "--------------------------------------------------\n",
      "total_water_need:\n",
      "MAE assoluto: 429.07\n",
      "Errore percentuale medio: 2.51%\n",
      "Precisione: 97.49%\n",
      "--------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "percentage_errors, absolute_errors = calculate_real_error(retrained_model, val_data, val_targets, scaler_y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "e6f357cb-56a4-4f19-a4e8-77b73a28329d",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import matplotlib.pyplot as plt\n",
    "from typing import List, Dict, Tuple, Union\n",
    "\n",
    "def analyze_feature_importance(model: tf.keras.Model, \n",
    "                             test_data: dict, \n",
    "                             feature_names: List[str]) -> Dict[str, float]:\n",
    "    \"\"\"\n",
    "    Analizza l'importanza delle feature usando perturbazione.\n",
    "    \n",
    "    Args:\n",
    "        model: Modello TensorFlow addestrato\n",
    "        test_data: Dizionario con chiavi 'temporal' e 'static' contenenti i dati\n",
    "        feature_names: Lista dei nomi delle feature\n",
    "        \n",
    "    Returns:\n",
    "        dict: Dizionario con l'importanza relativa di ogni feature\n",
    "    \"\"\"\n",
    "    # Estrai i dati temporali e statici\n",
    "    temporal_data = test_data['temporal']\n",
    "    static_data = test_data['static']\n",
    "    \n",
    "    # Ottieni la predizione base\n",
    "    base_prediction = model.predict(test_data)\n",
    "    feature_importance = {}\n",
    "    \n",
    "    # Per ogni feature temporale\n",
    "    for i, feature in enumerate(feature_names):\n",
    "        if feature in ['temp_mean', 'precip_sum', 'solar_energy_sum']:\n",
    "            # Crea copia perturbata dei dati\n",
    "            perturbed_data = {\n",
    "                'temporal': temporal_data.copy(),\n",
    "                'static': static_data.copy()\n",
    "            }\n",
    "            \n",
    "            # Trova l'indice della feature temporale\n",
    "            temp_idx = ['temp_mean', 'precip_sum', 'solar_energy_sum'].index(feature)\n",
    "            \n",
    "            # Crea rumore per la feature temporale\n",
    "            feature_values = temporal_data[..., temp_idx]\n",
    "            noise = np.random.normal(0, np.std(feature_values) * 0.1, \n",
    "                                   size=feature_values.shape)\n",
    "            \n",
    "            # Applica il rumore alla feature temporale\n",
    "            perturbed_temporal = perturbed_data['temporal'].copy()\n",
    "            perturbed_temporal[..., temp_idx] = feature_values + noise\n",
    "            perturbed_data['temporal'] = perturbed_temporal\n",
    "            \n",
    "        else:  # Feature statiche\n",
    "            # Crea copia perturbata dei dati\n",
    "            perturbed_data = {\n",
    "                'temporal': temporal_data.copy(),\n",
    "                'static': static_data.copy()\n",
    "            }\n",
    "            \n",
    "            # Trova l'indice della feature statica\n",
    "            static_idx = ['ha'].index(feature)\n",
    "            \n",
    "            # Crea rumore per la feature statica\n",
    "            feature_values = static_data[..., static_idx]\n",
    "            noise = np.random.normal(0, np.std(feature_values) * 0.1, \n",
    "                                   size=feature_values.shape)\n",
    "            \n",
    "            # Applica il rumore alla feature statica\n",
    "            perturbed_static = perturbed_data['static'].copy()\n",
    "            perturbed_static[..., static_idx] = feature_values + noise\n",
    "            perturbed_data['static'] = perturbed_static\n",
    "        \n",
    "        # Calcola nuova predizione\n",
    "        perturbed_prediction = model.predict(perturbed_data)\n",
    "        \n",
    "        # Calcola impatto della perturbazione\n",
    "        impact = np.mean(np.abs(perturbed_prediction - base_prediction))\n",
    "        feature_importance[feature] = float(impact)\n",
    "    \n",
    "    # Normalizza le importanze\n",
    "    total_importance = sum(feature_importance.values())\n",
    "    feature_importance = {k: v/total_importance \n",
    "                         for k, v in feature_importance.items()}\n",
    "    \n",
    "    return feature_importance\n",
    "\n",
    "class ProbabilityFunctions:\n",
    "    @staticmethod\n",
    "    def calculate_statistics(data: Union[np.ndarray, tf.Tensor]) -> Dict[str, float]:\n",
    "        \"\"\"\n",
    "        Calcola statistiche di base usando TensorFlow.\n",
    "        \n",
    "        Args:\n",
    "            data: Tensor o array dei dati\n",
    "            \n",
    "        Returns:\n",
    "            dict: Dizionario con le statistiche\n",
    "        \"\"\"\n",
    "        if not isinstance(data, tf.Tensor):\n",
    "            data = tf.convert_to_tensor(data, dtype=tf.float32)\n",
    "            \n",
    "        mean = tf.reduce_mean(data)\n",
    "        # Calcola varianza manualmente\n",
    "        squared_deviations = tf.square(data - mean)\n",
    "        variance = tf.reduce_mean(squared_deviations)\n",
    "        std = tf.sqrt(variance)\n",
    "        \n",
    "        # Ordina il tensor per il calcolo della mediana\n",
    "        sorted_data = tf.sort(data)\n",
    "        size = tf.size(data)\n",
    "        mid_index = size // 2\n",
    "        median = sorted_data[mid_index]\n",
    "        \n",
    "        return {\n",
    "            'mean': mean.numpy(),\n",
    "            'variance': variance.numpy(),\n",
    "            'std': std.numpy(),\n",
    "            'min': tf.reduce_min(data).numpy(),\n",
    "            'max': tf.reduce_max(data).numpy(),\n",
    "            'median': median.numpy()\n",
    "        }\n",
    "\n",
    "    @staticmethod\n",
    "    def calculate_pmf(data: np.ndarray, bins: int = 50) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:\n",
    "        \"\"\"\n",
    "        Calcola la Probability Mass Function (PMF) dei dati.\n",
    "        \n",
    "        Args:\n",
    "            data: Array di dati\n",
    "            bins: Numero di bin per l'istogramma\n",
    "            \n",
    "        Returns:\n",
    "            tuple: (bin_centers, pmf, bin_edges)\n",
    "        \"\"\"\n",
    "        # Calcola l'istogramma\n",
    "        hist, bin_edges = np.histogram(data, bins=bins, density=True)\n",
    "        \n",
    "        # Calcola i centri dei bin\n",
    "        bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2\n",
    "        \n",
    "        # Normalizza per ottenere la PMF\n",
    "        pmf = hist / np.sum(hist)\n",
    "        \n",
    "        return bin_centers, pmf, bin_edges\n",
    "\n",
    "    @staticmethod\n",
    "    def calculate_cmf(pmf: np.ndarray) -> np.ndarray:\n",
    "        \"\"\"\n",
    "        Calcola la Cumulative Mass Function (CMF) dalla PMF.\n",
    "        \n",
    "        Args:\n",
    "            pmf: Probability Mass Function\n",
    "            \n",
    "        Returns:\n",
    "            array: Cumulative Mass Function\n",
    "        \"\"\"\n",
    "        return np.cumsum(pmf)\n",
    "\n",
    "    def plot_distributions(self, data: np.ndarray, \n",
    "                         bins: int = 50, \n",
    "                         title: str = \"Distribuzione\") -> Tuple[np.ndarray, np.ndarray, np.ndarray]:\n",
    "        \"\"\"\n",
    "        Calcola e visualizza PMF e CMF delle distribuzioni.\n",
    "        \n",
    "        Args:\n",
    "            data: Array di dati da analizzare\n",
    "            bins: Numero di bin per l'istogramma\n",
    "            title: Titolo del grafico\n",
    "            \n",
    "        Returns:\n",
    "            tuple: (bin_centers, pmf, cmf)\n",
    "        \"\"\"\n",
    "        # Calcola PMF e CMF\n",
    "        bin_centers, pmf, bin_edges = self.calculate_pmf(data, bins)\n",
    "        cmf = self.calculate_cmf(pmf)\n",
    "        \n",
    "        # Crea il plot\n",
    "        fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))\n",
    "        \n",
    "        # Plot PMF\n",
    "        width = np.diff(bin_edges)\n",
    "        ax1.bar(bin_centers, pmf, width=width, alpha=0.5, label='PMF')\n",
    "        ax1.set_title('Probability Mass Function')\n",
    "        ax1.set_ylabel('Probability')\n",
    "        ax1.grid(True, alpha=0.3)\n",
    "        ax1.legend()\n",
    "        \n",
    "        # Plot CMF\n",
    "        ax2.plot(bin_centers, cmf, 'r-', label='CMF')\n",
    "        ax2.set_title('Cumulative Mass Function')\n",
    "        ax2.set_xlabel('Value')\n",
    "        ax2.set_ylabel('Cumulative Probability')\n",
    "        ax2.grid(True, alpha=0.3)\n",
    "        ax2.legend()\n",
    "        \n",
    "        # Imposta il titolo generale\n",
    "        fig.suptitle(title, y=1.02)\n",
    "        plt.tight_layout()\n",
    "        plt.show()\n",
    "        \n",
    "        return bin_centers, pmf, cmf\n",
    "\n",
    "def analyze_model_predictions(model: tf.keras.Model, \n",
    "                            test_data: np.ndarray,\n",
    "                            test_targets: np.ndarray,\n",
    "                            scaler_y) -> None:\n",
    "    \"\"\"\n",
    "    Analizza le distribuzioni di probabilità delle predizioni del modello.\n",
    "    \n",
    "    Args:\n",
    "        model: Modello TensorFlow addestrato\n",
    "        test_data: Dati di test\n",
    "        test_targets: Target di test\n",
    "        scaler_y: Scaler usato per denormalizzare i target\n",
    "    \"\"\"\n",
    "    # Ottieni le predizioni\n",
    "    predictions = model.predict(test_data)\n",
    "    \n",
    "    # Denormalizza predizioni e target\n",
    "    predictions_real = scaler_y.inverse_transform(predictions)\n",
    "    targets_real = scaler_y.inverse_transform(test_targets)\n",
    "    \n",
    "    # Inizializza la classe per l'analisi delle probabilità\n",
    "    prob = ProbabilityFunctions()\n",
    "    \n",
    "    # Analizza ogni target\n",
    "    target_names = ['olive_prod', 'min_oil_prod', 'max_oil_prod', \n",
    "                   'avg_oil_prod', 'total_water_need']\n",
    "    \n",
    "    for i, target in enumerate(target_names):\n",
    "        print(f\"\\nAnalisi per {target}\")\n",
    "        print(\"-\" * 50)\n",
    "        \n",
    "        # Calcola errori\n",
    "        errors = predictions_real[:, i] - targets_real[:, i]\n",
    "        \n",
    "        # Calcola statistiche degli errori\n",
    "        error_stats = prob.calculate_statistics(errors)\n",
    "        print(\"\\nStatistiche degli Errori:\")\n",
    "        for key, value in error_stats.items():\n",
    "            print(f\"{key}: {value:.3f}\")\n",
    "        \n",
    "        # Visualizza le distribuzioni degli errori\n",
    "        bin_centers, pmf, cmf = prob.plot_distributions(\n",
    "            errors, \n",
    "            bins=50,\n",
    "            title=f\"Distribuzione degli Errori - {target}\"\n",
    "        )\n",
    "        \n",
    "        # Calcola intervalli di confidenza\n",
    "        confidence_levels = [0.68, 0.95, 0.99]  # 1σ, 2σ, 3σ\n",
    "        for level in confidence_levels:\n",
    "            lower_idx = np.searchsorted(cmf, (1 - level) / 2)\n",
    "            upper_idx = np.searchsorted(cmf, (1 + level) / 2)\n",
    "            \n",
    "            print(f\"\\nIntervallo di Confidenza {level*100}%:\")\n",
    "            print(f\"Range: [{bin_centers[lower_idx]:.2f}, {bin_centers[upper_idx]:.2f}]\")\n",
    "\n",
    "def run_comprehensive_analysis(retrained_model, test_data, test_targets, scaler_y):\n",
    "    \"\"\"\n",
    "    Esegue un'analisi completa del modello includendo errori,\n",
    "    importanza delle feature e distribuzioni.\n",
    "    \"\"\"\n",
    "    print(\"=== ANALISI COMPLETA DEL MODELLO ===\")\n",
    "    \n",
    "    # 1. Analisi degli errori\n",
    "    print(\"\\n1. ANALISI DEGLI ERRORI\")\n",
    "    print(\"-\" * 50)\n",
    "    analyze_model_predictions(retrained_model, test_data, test_targets, scaler_y)\n",
    "    \n",
    "    # 2. Analisi dell'importanza delle feature\n",
    "    print(\"\\n2. IMPORTANZA DELLE FEATURE\")\n",
    "    print(\"-\" * 50)\n",
    "    \n",
    "    # Definisci i nomi delle feature\n",
    "    temporal_features = ['temp_mean', 'precip_sum', 'solar_energy_sum']\n",
    "    static_features = ['ha']\n",
    "    \n",
    "    all_features = temporal_features + static_features\n",
    "    importance = analyze_feature_importance(retrained_model, test_data, all_features)\n",
    "    \n",
    "    print(\"\\nImportanza relativa delle feature:\")\n",
    "    for feature, imp in sorted(importance.items(), key=lambda x: x[1], reverse=True):\n",
    "        print(f\"{feature}: {imp:.4f}\")\n",
    "        \n",
    "    # 3. Analisi distribuzionale\n",
    "    print(\"\\n3. ANALISI DISTRIBUZIONALE\")\n",
    "    print(\"-\" * 50)\n",
    "    \n",
    "    prob = ProbabilityFunctions()\n",
    "    predictions = retrained_model.predict(test_data)\n",
    "    predictions_real = scaler_y.inverse_transform(predictions)\n",
    "    targets_real = scaler_y.inverse_transform(test_targets)\n",
    "    \n",
    "    target_names = ['olive_prod', 'min_oil_prod', 'max_oil_prod', \n",
    "                    'avg_oil_prod', 'total_water_need']\n",
    "    \n",
    "    for i, target in enumerate(target_names):\n",
    "        print(f\"\\nAnalisi distribuzionale per {target}\")\n",
    "        \n",
    "        # Statistiche\n",
    "        stats_pred = prob.calculate_statistics(predictions_real[:, i])\n",
    "        stats_true = prob.calculate_statistics(targets_real[:, i])\n",
    "        \n",
    "        print(\"\\nStatistiche Predizioni:\")\n",
    "        for key, value in stats_pred.items():\n",
    "            print(f\"{key}: {value:.3f}\")\n",
    "            \n",
    "        print(\"\\nStatistiche Target Reali:\")\n",
    "        for key, value in stats_true.items():\n",
    "            print(f\"{key}: {value:.3f}\")\n",
    "        \n",
    "        # Visualizza distribuzioni\n",
    "        prob.plot_distributions(predictions_real[:, i], bins=50,\n",
    "                              title=f\"Distribuzione Predizioni - {target}\")\n",
    "        prob.plot_distributions(targets_real[:, i], bins=50,\n",
    "                              title=f\"Distribuzione Target Reali - {target}\")\n",
    "\n",
    "def analyze_model_predictions(model, test_data, test_targets, scaler_y):\n",
    "    \"\"\"\n",
    "    Analizza le distribuzioni di probabilità delle predizioni del modello.\n",
    "    \n",
    "    Args:\n",
    "        model: Modello TensorFlow addestrato\n",
    "        test_data: Dati di test\n",
    "        test_targets: Target di test\n",
    "        scaler_y: Scaler usato per denormalizzare i target\n",
    "    \"\"\"\n",
    "    # Ottieni le predizioni\n",
    "    predictions = model.predict(test_data)\n",
    "    \n",
    "    # Denormalizza predizioni e target\n",
    "    predictions_real = scaler_y.inverse_transform(predictions)\n",
    "    targets_real = scaler_y.inverse_transform(test_targets)\n",
    "    \n",
    "    # Inizializza la classe per l'analisi delle probabilità\n",
    "    prob = ProbabilityFunctions()\n",
    "    \n",
    "    # Analizza ogni target\n",
    "    target_names = ['olive_prod', 'min_oil_prod', 'max_oil_prod', \n",
    "                   'avg_oil_prod', 'total_water_need']\n",
    "    \n",
    "    for i, target in enumerate(target_names):\n",
    "        print(f\"\\nAnalisi per {target}\")\n",
    "        print(\"-\" * 50)\n",
    "        \n",
    "        # Calcola errori\n",
    "        errors = predictions_real[:, i] - targets_real[:, i]\n",
    "        \n",
    "        # Calcola statistiche degli errori\n",
    "        error_stats = prob.calculate_statistics(errors)\n",
    "        print(\"\\nStatistiche degli Errori:\")\n",
    "        for key, value in error_stats.items():\n",
    "            print(f\"{key}: {value:.3f}\")\n",
    "        \n",
    "        # Visualizza le distribuzioni degli errori\n",
    "        bin_centers, pmf, cmf = prob.plot_distributions(\n",
    "            errors, \n",
    "            bins=50,\n",
    "            title=f\"Distribuzione degli Errori - {target}\"\n",
    "        )\n",
    "        \n",
    "        # Calcola intervalli di confidenza\n",
    "        confidence_levels = [0.80,0.85, 0.90, 0.95, 0.99]  # 1σ, 2σ, 3σ\n",
    "        for level in confidence_levels:\n",
    "            lower_idx = np.searchsorted(cmf, (1 - level) / 2)\n",
    "            upper_idx = np.searchsorted(cmf, (1 + level) / 2)\n",
    "            \n",
    "            print(f\"\\nIntervallo di Confidenza {level*100}%:\")\n",
    "            print(f\"Range: [{bin_centers[lower_idx]:.2f}, {bin_centers[upper_idx]:.2f}]\")\n",
    "\n",
    "class ProbabilityFunctions:\n",
    "    @staticmethod\n",
    "    def calculate_statistics(data):\n",
    "        \"\"\"\n",
    "        Calcola statistiche di base usando TensorFlow.\n",
    "        \n",
    "        Args:\n",
    "            data: Tensor dei dati\n",
    "            \n",
    "        Returns:\n",
    "            dict: Dizionario con le statistiche\n",
    "        \"\"\"\n",
    "        if not isinstance(data, tf.Tensor):\n",
    "            data = tf.convert_to_tensor(data, dtype=tf.float32)\n",
    "            \n",
    "        mean = tf.reduce_mean(data)\n",
    "        # Calculate variance manually\n",
    "        squared_deviations = tf.square(data - mean)\n",
    "        variance = tf.reduce_mean(squared_deviations)\n",
    "        std = tf.sqrt(variance)\n",
    "        \n",
    "        # Sort the tensor for median calculation\n",
    "        sorted_data = tf.sort(data)\n",
    "        size = tf.size(data)\n",
    "        mid_index = size // 2\n",
    "        median = sorted_data[mid_index]\n",
    "        \n",
    "        return {\n",
    "            'mean': mean.numpy(),\n",
    "            'variance': variance.numpy(),\n",
    "            'std': std.numpy(),\n",
    "            'min': tf.reduce_min(data).numpy(),\n",
    "            'max': tf.reduce_max(data).numpy(),\n",
    "            'median': median.numpy()\n",
    "        }\n",
    "\n",
    "    @staticmethod\n",
    "    def calculate_pmf(data, bins=50):\n",
    "        \"\"\"\n",
    "        Calcola la Probability Mass Function (PMF) dei dati.\n",
    "        \n",
    "        Args:\n",
    "            data: Array di dati\n",
    "            bins: Numero di bin per l'istogramma\n",
    "            \n",
    "        Returns:\n",
    "            tuple: (bin_centers, pmf, bin_edges)\n",
    "        \"\"\"\n",
    "        # Calcola l'istogramma\n",
    "        hist, bin_edges = np.histogram(data, bins=bins, density=True)\n",
    "        \n",
    "        # Calcola i centri dei bin\n",
    "        bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2\n",
    "        \n",
    "        # Normalizza per ottenere la PMF\n",
    "        pmf = hist / np.sum(hist)\n",
    "        \n",
    "        return bin_centers, pmf, bin_edges\n",
    "\n",
    "    @staticmethod\n",
    "    def calculate_cmf(pmf):\n",
    "        \"\"\"\n",
    "        Calcola la Cumulative Mass Function (CMF) dalla PMF.\n",
    "        \n",
    "        Args:\n",
    "            pmf: Probability Mass Function\n",
    "            \n",
    "        Returns:\n",
    "            array: Cumulative Mass Function\n",
    "        \"\"\"\n",
    "        return np.cumsum(pmf)\n",
    "\n",
    "    def plot_distributions(self, data, bins=50, title=\"Distribuzione\"):\n",
    "        \"\"\"\n",
    "        Calcola e visualizza PMF e CMF delle distribuzioni.\n",
    "        \n",
    "        Args:\n",
    "            data: Array di dati da analizzare\n",
    "            bins: Numero di bin per l'istogramma\n",
    "            title: Titolo del grafico\n",
    "            \n",
    "        Returns:\n",
    "            tuple: (bin_centers, pmf, cmf)\n",
    "        \"\"\"\n",
    "        # Calcola PMF e CMF\n",
    "        bin_centers, pmf, bin_edges = self.calculate_pmf(data, bins)\n",
    "        cmf = self.calculate_cmf(pmf)\n",
    "        \n",
    "        # Crea il plot\n",
    "        fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))\n",
    "        \n",
    "        # Plot PMF\n",
    "        width = np.diff(bin_edges)\n",
    "        ax1.bar(bin_centers, pmf, width=width, alpha=0.5, label='PMF')\n",
    "        ax1.set_title('Probability Mass Function')\n",
    "        ax1.set_ylabel('Probability')\n",
    "        ax1.grid(True, alpha=0.3)\n",
    "        ax1.legend()\n",
    "        \n",
    "        # Plot CMF\n",
    "        ax2.plot(bin_centers, cmf, 'r-', label='CMF')\n",
    "        ax2.set_title('Cumulative Mass Function')\n",
    "        ax2.set_xlabel('Value')\n",
    "        ax2.set_ylabel('Cumulative Probability')\n",
    "        ax2.grid(True, alpha=0.3)\n",
    "        ax2.legend()\n",
    "        \n",
    "        # Set overall title\n",
    "        fig.suptitle(title, y=1.02)\n",
    "        plt.tight_layout()\n",
    "        plt.show()\n",
    "        \n",
    "        return bin_centers, pmf, cmf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "b98f2a45-ba6f-4519-acaa-0138b4ee7812",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=== ANALISI COMPLETA DEL MODELLO ===\n",
      "\n",
      "1. ANALISI DEGLI ERRORI\n",
      "--------------------------------------------------\n",
      "19125/19125 [==============================] - 297s 16ms/step\n",
      "\n",
      "Analisi per olive_prod\n",
      "--------------------------------------------------\n",
      "\n",
      "Statistiche degli Errori:\n",
      "mean: -153.802\n",
      "variance: 3593289.250\n",
      "std: 1895.597\n",
      "min: -16577.840\n",
      "max: 13799.312\n",
      "median: 42.076\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 67932 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Intervallo di Confidenza 80.0%:\n",
      "Range: [-2300.58, 1952.22]\n",
      "\n",
      "Intervallo di Confidenza 85.0%:\n",
      "Range: [-2908.12, 1952.22]\n",
      "\n",
      "Intervallo di Confidenza 90.0%:\n",
      "Range: [-3515.66, 2559.77]\n",
      "\n",
      "Intervallo di Confidenza 95.0%:\n",
      "Range: [-4730.75, 3167.31]\n",
      "\n",
      "Intervallo di Confidenza 99.0%:\n",
      "Range: [-6553.38, 4989.94]\n",
      "\n",
      "Analisi per min_oil_prod\n",
      "--------------------------------------------------\n",
      "\n",
      "Statistiche degli Errori:\n",
      "mean: -35.659\n",
      "variance: 156634.391\n",
      "std: 395.771\n",
      "min: -3838.121\n",
      "max: 3470.118\n",
      "median: 2.335\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 62992 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Intervallo di Confidenza 80.0%:\n",
      "Range: [-549.41, 327.58]\n",
      "\n",
      "Intervallo di Confidenza 85.0%:\n",
      "Range: [-549.41, 473.74]\n",
      "\n",
      "Intervallo di Confidenza 90.0%:\n",
      "Range: [-695.58, 619.91]\n",
      "\n",
      "Intervallo di Confidenza 95.0%:\n",
      "Range: [-987.91, 766.07]\n",
      "\n",
      "Intervallo di Confidenza 99.0%:\n",
      "Range: [-1426.40, 1058.40]\n",
      "\n",
      "Analisi per max_oil_prod\n",
      "--------------------------------------------------\n",
      "\n",
      "Statistiche degli Errori:\n",
      "mean: -35.914\n",
      "variance: 230541.562\n",
      "std: 480.147\n",
      "min: -5331.337\n",
      "max: 4020.382\n",
      "median: 11.369\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 60268 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Intervallo di Confidenza 80.0%:\n",
      "Range: [-561.96, 560.25]\n",
      "\n",
      "Intervallo di Confidenza 85.0%:\n",
      "Range: [-748.99, 560.25]\n",
      "\n",
      "Intervallo di Confidenza 90.0%:\n",
      "Range: [-936.03, 747.28]\n",
      "\n",
      "Intervallo di Confidenza 95.0%:\n",
      "Range: [-1123.06, 934.31]\n",
      "\n",
      "Intervallo di Confidenza 99.0%:\n",
      "Range: [-1871.20, 1308.38]\n",
      "\n",
      "Analisi per avg_oil_prod\n",
      "--------------------------------------------------\n",
      "\n",
      "Statistiche degli Errori:\n",
      "mean: -35.829\n",
      "variance: 178113.297\n",
      "std: 422.035\n",
      "min: -4341.829\n",
      "max: 3468.752\n",
      "median: 5.723\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 70224 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Intervallo di Confidenza 80.0%:\n",
      "Range: [-514.64, 422.63]\n",
      "\n",
      "Intervallo di Confidenza 85.0%:\n",
      "Range: [-670.86, 422.63]\n",
      "\n",
      "Intervallo di Confidenza 90.0%:\n",
      "Range: [-827.07, 578.84]\n",
      "\n",
      "Intervallo di Confidenza 95.0%:\n",
      "Range: [-983.28, 735.05]\n",
      "\n",
      "Intervallo di Confidenza 99.0%:\n",
      "Range: [-1608.13, 1047.47]\n",
      "\n",
      "Analisi per total_water_need\n",
      "--------------------------------------------------\n",
      "\n",
      "Statistiche degli Errori:\n",
      "mean: -25.087\n",
      "variance: 379237.156\n",
      "std: 615.822\n",
      "min: -5668.621\n",
      "max: 5323.238\n",
      "median: 45.572\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 69272 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Intervallo di Confidenza 80.0%:\n",
      "Range: [-722.28, 596.74]\n",
      "\n",
      "Intervallo di Confidenza 85.0%:\n",
      "Range: [-942.12, 596.74]\n",
      "\n",
      "Intervallo di Confidenza 90.0%:\n",
      "Range: [-1161.96, 816.58]\n",
      "\n",
      "Intervallo di Confidenza 95.0%:\n",
      "Range: [-1381.80, 1036.41]\n",
      "\n",
      "Intervallo di Confidenza 99.0%:\n",
      "Range: [-2480.98, 2135.60]\n",
      "\n",
      "2. IMPORTANZA DELLE FEATURE\n",
      "--------------------------------------------------\n",
      "19125/19125 [==============================] - 287s 15ms/step\n",
      "19125/19125 [==============================] - 292s 15ms/step\n",
      "19125/19125 [==============================] - 290s 15ms/step\n",
      "19125/19125 [==============================] - 295s 15ms/step\n",
      "19125/19125 [==============================] - 297s 16ms/step\n",
      "\n",
      "Importanza relativa delle feature:\n",
      "ha: 0.8669\n",
      "precip_sum: 0.0575\n",
      "solar_energy_sum: 0.0420\n",
      "temp_mean: 0.0336\n",
      "\n",
      "3. ANALISI DISTRIBUZIONALE\n",
      "--------------------------------------------------\n",
      "19125/19125 [==============================] - 300s 16ms/step\n",
      "\n",
      "Analisi distribuzionale per olive_prod\n",
      "\n",
      "Statistiche Predizioni:\n",
      "mean: 29677.232\n",
      "variance: 255279328.000\n",
      "std: 15977.463\n",
      "min: 3532.861\n",
      "max: 87733.969\n",
      "median: 27822.436\n",
      "\n",
      "Statistiche Target Reali:\n",
      "mean: 29831.037\n",
      "variance: 270305376.000\n",
      "std: 16440.967\n",
      "min: 2156.451\n",
      "max: 98292.078\n",
      "median: 27885.184\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 71956 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 66048 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Analisi distribuzionale per min_oil_prod\n",
      "\n",
      "Statistiche Predizioni:\n",
      "mean: 5875.726\n",
      "variance: 11020948.000\n",
      "std: 3319.781\n",
      "min: 624.859\n",
      "max: 19463.191\n",
      "median: 5412.554\n",
      "\n",
      "Statistiche Target Reali:\n",
      "mean: 5911.384\n",
      "variance: 11648010.000\n",
      "std: 3412.918\n",
      "min: 385.506\n",
      "max: 22119.781\n",
      "median: 5416.575\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 67800 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 66140 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Analisi distribuzionale per max_oil_prod\n",
      "\n",
      "Statistiche Predizioni:\n",
      "mean: 7108.558\n",
      "variance: 16190243.000\n",
      "std: 4023.710\n",
      "min: 693.562\n",
      "max: 24302.926\n",
      "median: 6544.735\n",
      "\n",
      "Statistiche Target Reali:\n",
      "mean: 7144.473\n",
      "variance: 17129654.000\n",
      "std: 4138.798\n",
      "min: 467.800\n",
      "max: 28135.092\n",
      "median: 6546.016\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 65308 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 66956 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Analisi distribuzionale per avg_oil_prod\n",
      "\n",
      "Statistiche Predizioni:\n",
      "mean: 6492.088\n",
      "variance: 13472738.000\n",
      "std: 3670.523\n",
      "min: 659.898\n",
      "max: 21879.734\n",
      "median: 5980.175\n",
      "\n",
      "Statistiche Target Reali:\n",
      "mean: 6527.917\n",
      "variance: 14225926.000\n",
      "std: 3771.727\n",
      "min: 426.118\n",
      "max: 24928.848\n",
      "median: 5983.750\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 64908 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 67696 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Analisi distribuzionale per total_water_need\n",
      "\n",
      "Statistiche Predizioni:\n",
      "mean: 22511.547\n",
      "variance: 114444504.000\n",
      "std: 10697.874\n",
      "min: 4104.441\n",
      "max: 50439.238\n",
      "median: 22263.105\n",
      "\n",
      "Statistiche Target Reali:\n",
      "mean: 22536.635\n",
      "variance: 120029880.000\n",
      "std: 10955.814\n",
      "min: 3238.847\n",
      "max: 53757.914\n",
      "median: 22304.934\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 71000 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 69540 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "run_comprehensive_analysis(retrained_model, test_data, test_targets, scaler_y)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.0rc1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
