{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ad9863f8",
   "metadata": {},
   "source": [
    "# Esame Laboratorio di Programmazione II\n",
    "\n",
    "Scrivete chiaramente sul notebook il vostro nome e matricola e salvate il file con il nome della vostra matricola.\n",
    "\n",
    "Per ogni funzione o metodo che richiede un campionamento rispetto ad una distribuzione, settate il seed a 0: `np.random.seed(0)`.\n",
    "\n",
    "Stampate il risultato delle domande e consegnate il compito eseguito: ogni cella deve avere il corrispondente output. Ad esempio, NON scrivete solo:\n",
    "\n",
    "```python\n",
    "lista = np.array([1, 2, 3])\n",
    "```\n",
    "\n",
    "ma:\n",
    "\n",
    "```python\n",
    "lista = np.array([1, 2, 3])\n",
    "print('lista =', lista)\n",
    "```\n",
    "\n",
    "NB: se l'output è una matrice molto grande, non dovete stamparla integralmente.\n",
    "\n",
    "Sarà valutata anche la presentazione: ad esempio, un plot senza titolo o senza etichette sugli assi sarà considerato incompleto.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c821388",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Qui potete mettere gli import delle librerie \n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "057f3daf",
   "metadata": {},
   "source": [
    "## Esercizio 1\n",
    "\n",
    "Una squadra di esploratori spaziali ha registrato i seguenti livelli di ossigeno residuo dopo una missione:\n",
    "\n",
    "`68, 74, 91, 55, 83, 79, 62, 88, 96, 71, 64, 85`\n",
    "\n",
    "1. Crea un array NumPy `ossigeno` con questi valori e calcola la **media**.\n",
    "2. Tutti i valori **strettamente minori di 72** devono essere aumentati di 10 punti. Aggiorna l’array in-place e stampa il nuovo array.\n",
    "3. Calcola quanti valori, dopo la correzione, sono **compresi tra 80 e 92 inclusi**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "090f39a8",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "1a8ebee3",
   "metadata": {},
   "source": [
    "## Esercizio 2\n",
    "\n",
    "Una ruota numerata truccata può restituire i valori da **1 a 8**.\n",
    "\n",
    "La ruota è costruita in modo che il valore **8** abbia probabilità **tripla** rispetto a ciascuno degli altri valori.\n",
    "\n",
    "In particolare:\n",
    "\n",
    "- la probabilità di ottenere ciascun numero da **1 a 7** è **1/10**\n",
    "- la probabilità di ottenere **8** è **3/10**\n",
    "\n",
    "1. Scrivi una funzione `gira_ruota(N)` che simula `N` giri della ruota e restituisce un array NumPy contenente i risultati.\n",
    "2. Per valori di `N = 100, 200, 300, ..., 1000`, esegui una simulazione e calcola la **frequenza relativa** del valore **8** e del valore **2**.\n",
    "3. Rappresenta graficamente le frequenze relative dell’8 e del 2 in funzione di `N` e confrontale con i valori teorici."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fec7960b",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "886730e1",
   "metadata": {},
   "source": [
    "## Esercizio 3\n",
    "\n",
    "Si consideri la seguente matrice `T` di dimensione **5 × 4**, che rappresenta valori di temperatura registrati in **5 laboratori** diversi, in **4 momenti della giornata**:\n",
    "\n",
    "|     | M1 | M2 | M3 | M4 |\n",
    "|-----|----|----|----|----|\n",
    "| L1  | 21 | 23 | 22 | 24 |\n",
    "| L2  | 19 | 22 | 21 | 23 |\n",
    "| L3  | 20 | 24 | 23 | 25 |\n",
    "| L4  | 18 | 21 | 20 | 22 |\n",
    "| L5  | 22 | 25 | 24 | 26 |\n",
    "\n",
    "1. Crea la matrice `T` come array NumPy e calcola:\n",
    "   - la media di ciascuna riga\n",
    "   - la media di ciascuna colonna\n",
    "2. Crea una nuova matrice `S` ottenuta sottraendo a ogni elemento di `T`\n",
    "   la media della **sua colonna**.\n",
    "3. Individua la posizione (riga, colonna) del valore minimo di `S`\n",
    "   e stampala."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ceb2583c",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "d058867c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  mission_id drone_model     area  flight_time_min  distance_km  battery_used  \\\n",
      "0      D2000     FalconX  Foresta               33        13.47         19.46   \n",
      "1      D2001     FalconX  Foresta              109        37.22         48.81   \n",
      "2      D2002   AeroScout    Citta              109        34.81         58.55   \n",
      "3      D2003     FalconX  Foresta               40        10.73         19.83   \n",
      "4      D2004   AeroScout    Costa              120        49.49         66.50   \n",
      "\n",
      "   signal_loss  completed  \n",
      "0          4.0          0  \n",
      "1          1.0          1  \n",
      "2          3.0          0  \n",
      "3          3.0          0  \n",
      "4          2.0          1  \n"
     ]
    }
   ],
   "source": [
    "# =========================\n",
    "# (Setup) creazione dataset\n",
    "# =========================\n",
    "### Creazione del dataset `drone_missions.csv` (da eseguire una sola volta)\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "def make_drone_missions_csv(filename=\"drone_missions.csv\", n=100, seed=2):\n",
    "    rng = np.random.default_rng(seed)\n",
    "\n",
    "    mission_id = [f\"D{2000+i}\" for i in range(n)]\n",
    "\n",
    "    drone_model = rng.choice(\n",
    "        [\"FalconX\", \"SkyBee\", \"AeroScout\", \"MiniRover\"],\n",
    "        size=n,\n",
    "        p=[0.30, 0.30, 0.25, 0.15]\n",
    "    )\n",
    "\n",
    "    area = rng.choice(\n",
    "        [\"Porto\", \"Foresta\", \"Citta\", \"Costa\"],\n",
    "        size=n,\n",
    "        p=[0.25, 0.30, 0.25, 0.20]\n",
    "    )\n",
    "\n",
    "    # durata del volo\n",
    "    flight_time_min = rng.integers(15, 121, size=n)\n",
    "\n",
    "    # efficienza media diversa per modello: km percorsi al minuto\n",
    "    speed_by_model = {\n",
    "        \"FalconX\": 0.42,\n",
    "        \"SkyBee\": 0.34,\n",
    "        \"AeroScout\": 0.38,\n",
    "        \"MiniRover\": 0.27\n",
    "    }\n",
    "\n",
    "    # penalità/bonus per area\n",
    "    area_factor = {\n",
    "        \"Porto\": 1.00,\n",
    "        \"Foresta\": 0.85,\n",
    "        \"Citta\": 0.90,\n",
    "        \"Costa\": 1.10\n",
    "    }\n",
    "\n",
    "    distance_km = []\n",
    "\n",
    "    for model, ar, t in zip(drone_model, area, flight_time_min):\n",
    "        base_distance = t * speed_by_model[model] * area_factor[ar]\n",
    "        noise = rng.normal(0, 2.0)\n",
    "        distance_km.append(max(1, base_distance + noise))\n",
    "\n",
    "    distance_km = np.array(distance_km).round(2)\n",
    "\n",
    "    # consumo batteria: cresce con il tempo, ma dipende dal modello\n",
    "    battery_factor = {\n",
    "        \"FalconX\": 0.45,\n",
    "        \"SkyBee\": 0.55,\n",
    "        \"AeroScout\": 0.50,\n",
    "        \"MiniRover\": 0.60\n",
    "    }\n",
    "\n",
    "    battery_used = []\n",
    "\n",
    "    for model, t in zip(drone_model, flight_time_min):\n",
    "        base_battery = t * battery_factor[model]\n",
    "        noise = rng.normal(0, 4.0)\n",
    "        battery_used.append(max(5, base_battery + noise))\n",
    "\n",
    "    battery_used = np.array(battery_used).round(2)\n",
    "\n",
    "    # perdita di segnale più alta in alcune aree\n",
    "    signal_loss = []\n",
    "\n",
    "    for ar in area:\n",
    "        if ar == \"Foresta\":\n",
    "            loss = rng.poisson(2.2)\n",
    "        elif ar == \"Citta\":\n",
    "            loss = rng.poisson(1.6)\n",
    "        elif ar == \"Porto\":\n",
    "            loss = rng.poisson(1.0)\n",
    "        else:\n",
    "            loss = rng.poisson(0.8)\n",
    "\n",
    "        signal_loss.append(min(loss, 6))\n",
    "\n",
    "    signal_loss = np.array(signal_loss)\n",
    "\n",
    "    # missione completata: più probabile se signal_loss è basso\n",
    "    completed = (signal_loss <= 2).astype(int)\n",
    "\n",
    "    df = pd.DataFrame({\n",
    "        \"mission_id\": mission_id,\n",
    "        \"drone_model\": drone_model,\n",
    "        \"area\": area,\n",
    "        \"flight_time_min\": flight_time_min,\n",
    "        \"distance_km\": distance_km,\n",
    "        \"battery_used\": battery_used,\n",
    "        \"signal_loss\": signal_loss,\n",
    "        \"completed\": completed\n",
    "    })\n",
    "\n",
    "    # valori mancanti mirati\n",
    "    miss1 = rng.choice(df.index, size=max(1, n//20), replace=False)\n",
    "    miss2 = rng.choice(df.index.difference(miss1), size=max(1, n//20), replace=False)\n",
    "\n",
    "    df.loc[miss1, \"battery_used\"] = np.nan\n",
    "    df.loc[miss2, \"signal_loss\"] = np.nan\n",
    "\n",
    "    df.to_csv(filename, index=False)\n",
    "    return df\n",
    "\n",
    "df = make_drone_missions_csv(\"drone_missions.csv\", n=100, seed=2)\n",
    "print(df.head())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94af6714",
   "metadata": {},
   "source": [
    "## Esercizio 4\n",
    "\n",
    "Si consideri il file CSV `drone_missions.csv`, che contiene informazioni su alcune missioni effettuate da droni.\n",
    "\n",
    "Il dataset contiene le seguenti colonne:\n",
    "\n",
    "`mission_id`, `drone_model`, `area`, `flight_time_min`, `distance_km`, `battery_used`, `signal_loss`, `completed`\n",
    "\n",
    "dove `completed` vale 1 se la missione è stata completata, 0 altrimenti.\n",
    "\n",
    "Svolgere le seguenti richieste:\n",
    "\n",
    "1. Caricare il dataset in un DataFrame pandas, verificare la presenza di **valori mancanti per colonna** ed eliminare le righe che ne contengono.\n",
    "\n",
    "2. Creare una nuova colonna `efficiency_index` definita come:\n",
    "\n",
    "   $$\n",
    "   \\texttt{efficiency\\_index} = \\frac{\\texttt{distance\\_km}}{\\texttt{battery\\_used}}\n",
    "   $$\n",
    "\n",
    "3. Filtrare le missioni che hanno:\n",
    "   - `flight_time_min` > 60\n",
    "   - `signal_loss` <= 1\n",
    "\n",
    "4. Creare un **grafico a barre** con le **10 missioni con `efficiency_index` più alto**\n",
    "   usando `mission_id` come etichetta.\n",
    "\n",
    "5. Creare uno **scatter plot** con:\n",
    "   - asse x = `flight_time_min`\n",
    "   - asse y = `distance_km`\n",
    "   - colore dei punti = `efficiency_index`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "44a51157",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "a865eddb",
   "metadata": {},
   "source": [
    "## Esercizio 5\n",
    "\n",
    "Si utilizzi di nuovo il dataset `drone_missions.csv`. **Prima di svolgere questo esercizio, ricaricare il dataset originale.**\n",
    "\n",
    "Svolgere le seguenti richieste:\n",
    "\n",
    "1. Determinare il numero di righe e di colonne del dataset ed eliminare la colonna `mission_id`.\n",
    "2. Individuare il `drone_model` più frequente nel dataset.\n",
    "3. Calcolare la media di `distance_km` per ciascun `drone_model` e ordinare i risultati dal valore medio più alto al più basso.\n",
    "4. Rappresentare la distribuzione di `distance_km` per ciascun `drone_model` mediante un boxplot.\n",
    "5. Rappresentare la distribuzione di `battery_used` per ciascun `drone_model` mediante un **violin plot**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2d359775",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "732bb164",
   "metadata": {},
   "source": [
    "## Esercizio 6\n",
    "\n",
    "Genera due array:\n",
    "\n",
    "`x = np.linspace(0, 6, 100)`  \n",
    "`y = -1.8 * x + 4.5 + np.random.normal(0, 0.7, 100)`\n",
    "\n",
    "1. Stimare i parametri `a` e `b` della retta del tipo:\n",
    "\n",
    "   $$\n",
    "   y = a \\cdot x + b\n",
    "   $$\n",
    "\n",
    "2. Plotta i punti originali e la retta ottenuta.\n",
    "\n",
    "3. Calcola **MAE** (*Mean Absolute Error*) e **RMSE** (*Root Mean Squared Error*) tra i valori reali `y` e quelli stimati dal modello, dove:\n",
    "\n",
    "   $$\n",
    "   \\text{MAE} = \\frac{1}{n}\\sum_{i=1}^{n} \\lvert y_i - \\hat{y}_i \\rvert\n",
    "   $$\n",
    "\n",
    "   $$   \n",
    "   \\text{RMSE} = \\sqrt{\\frac{1}{n}\\sum_{i=1}^{n} (y_i - \\hat{y}_i)^2}\n",
    "   $$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "563e358b",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "labPython",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
