{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_2-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "f3c335f9940cfd76528b3ef918b9b342", "translation_date": "2025-08-29T23:17:34+00:00", "source_file": "2-Regression/2-Data/solution/R/lesson_2-R.ipynb", "language_code": "it" } }, "cells": [ { "cell_type": "markdown", "source": [ "# Costruire un modello di regressione: preparare e visualizzare i dati\n", "\n", "## **Regressione Lineare per le Zucche - Lezione 2**\n", "#### Introduzione\n", "\n", "Ora che hai a disposizione gli strumenti necessari per iniziare a costruire modelli di machine learning con Tidymodels e il Tidyverse, sei pronto per iniziare a porre domande ai tuoi dati. Quando lavori con i dati e applichi soluzioni di ML, è molto importante sapere come formulare la domanda giusta per sbloccare correttamente il potenziale del tuo dataset.\n", "\n", "In questa lezione, imparerai:\n", "\n", "- Come preparare i tuoi dati per la costruzione di modelli.\n", "\n", "- Come utilizzare `ggplot2` per la visualizzazione dei dati.\n", "\n", "La domanda a cui hai bisogno di rispondere determinerà il tipo di algoritmi di ML che utilizzerai. E la qualità della risposta che otterrai dipenderà fortemente dalla natura dei tuoi dati.\n", "\n", "Vediamo questo concetto attraverso un esercizio pratico.\n", "\n", "
\n",
" \n",
"
\n",
"\n",
"> Un ripasso: L'operatore pipe (`%>%`) esegue operazioni in sequenza logica passando un oggetto avanti in una funzione o espressione. Puoi pensare all'operatore pipe come se dicesse \"e poi\" nel tuo codice.\n"
],
"metadata": {
"id": "REWcIv9yX29v"
}
},
{
"cell_type": "markdown",
"source": [
"## 2. Controllare i dati mancanti\n",
"\n",
"Uno dei problemi più comuni che i data scientist devono affrontare è la presenza di dati incompleti o mancanti. R rappresenta i valori mancanti, o sconosciuti, con un valore sentinella speciale: `NA` (Not Available).\n",
"\n",
"Quindi, come possiamo sapere se il data frame contiene valori mancanti? \n",
"
\n",
"- Un modo semplice sarebbe utilizzare la funzione base di R `anyNA`, che restituisce gli oggetti logici `TRUE` o `FALSE`.\n"
],
"metadata": {
"id": "Zxfb3AM5YbUe"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" anyNA()"
],
"outputs": [],
"metadata": {
"id": "G--DQutAYltj"
}
},
{
"cell_type": "markdown",
"source": [
"Ottimo, sembra che manchino alcuni dati! Questo è un buon punto di partenza.\n",
"\n",
"- Un altro modo sarebbe utilizzare la funzione `is.na()` che indica quali elementi individuali delle colonne sono mancanti con un valore logico `TRUE`.\n"
],
"metadata": {
"id": "mU-7-SB6YokF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "W-DxDOR4YxSW"
}
},
{
"cell_type": "markdown",
"source": [
"Ok, lavoro fatto, ma con un data frame così grande, sarebbe inefficiente e praticamente impossibile esaminare tutte le righe e le colonne singolarmente😴.\n",
"\n",
"- Un modo più intuitivo sarebbe calcolare la somma dei valori mancanti per ogni colonna:\n"
],
"metadata": {
"id": "xUWxipKYY0o7"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" colSums()"
],
"outputs": [],
"metadata": {
"id": "ZRBWV6P9ZArL"
}
},
{
"cell_type": "markdown",
"source": [
"Molto meglio! Mancano alcuni dati, ma forse non sarà un problema per il compito da svolgere. Vediamo cosa porterà avanti un'ulteriore analisi.\n",
"\n",
"> Oltre ai fantastici set di pacchetti e funzioni, R ha una documentazione molto valida. Ad esempio, usa `help(colSums)` o `?colSums` per scoprire di più sulla funzione.\n"
],
"metadata": {
"id": "9gv-crB6ZD1Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 3. Dplyr: Una grammatica per la manipolazione dei dati\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "i5o33MQBZWWw"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::select()\n",
"\n",
"`select()` è una funzione del pacchetto `dplyr` che ti aiuta a scegliere le colonne da mantenere o escludere.\n",
"\n",
"Per rendere il tuo data frame più facile da gestire, elimina alcune delle sue colonne utilizzando `select()`, mantenendo solo le colonne di cui hai bisogno.\n",
"\n",
"Ad esempio, in questo esercizio, la nostra analisi riguarderà le colonne `Package`, `Low Price`, `High Price` e `Date`. Selezioniamo queste colonne.\n"
],
"metadata": {
"id": "x3VGMAGBZiUr"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Select desired columns\n",
"pumpkins <- pumpkins %>% \n",
" select(Package, `Low Price`, `High Price`, Date)\n",
"\n",
"\n",
"# Print data set\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "F_FgxQnVZnM0"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::mutate()\n",
"\n",
"`mutate()` è una funzione del pacchetto `dplyr` che ti aiuta a creare o modificare colonne, mantenendo intatte le colonne esistenti.\n",
"\n",
"La struttura generale di `mutate` è:\n",
"\n",
"`data %>% mutate(new_column_name = what_it_contains)`\n",
"\n",
"Proviamo a utilizzare `mutate` con la colonna `Date` eseguendo le seguenti operazioni:\n",
"\n",
"1. Convertire le date (attualmente di tipo carattere) in un formato mese (si tratta di date statunitensi, quindi il formato è `MM/DD/YYYY`).\n",
"\n",
"2. Estrarre il mese dalle date in una nuova colonna.\n",
"\n",
"In R, il pacchetto [lubridate](https://lubridate.tidyverse.org/) semplifica il lavoro con i dati di tipo Date-time. Quindi, utilizziamo `dplyr::mutate()`, `lubridate::mdy()`, `lubridate::month()` e vediamo come raggiungere gli obiettivi sopra indicati. Possiamo eliminare la colonna `Date` poiché non ci servirà più nelle operazioni successive.\n"
],
"metadata": {
"id": "2KKo0Ed9Z1VB"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Load lubridate\n",
"library(lubridate)\n",
"\n",
"pumpkins <- pumpkins %>% \n",
" # Convert the Date column to a date object\n",
" mutate(Date = mdy(Date)) %>% \n",
" # Extract month from Date\n",
" mutate(Month = month(Date)) %>% \n",
" # Drop Date column\n",
" select(-Date)\n",
"\n",
"# View the first few rows\n",
"pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "5joszIVSZ6xe"
}
},
{
"cell_type": "markdown",
"source": [
"Evviva! 🤩\n",
"\n",
"Ora, creiamo una nuova colonna `Price`, che rappresenta il prezzo medio di una zucca. Adesso, calcoliamo la media delle colonne `Low Price` e `High Price` per riempire la nuova colonna Price.\n",
"
\n"
],
"metadata": {
"id": "nIgLjNMCZ-6Y"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new column Price\n",
"pumpkins <- pumpkins %>% \n",
" mutate(Price = (`Low Price` + `High Price`)/2)\n",
"\n",
"# View the first few rows of the data\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "Zo0BsqqtaJw2"
}
},
{
"cell_type": "markdown",
"source": [
"Sììì! 💪\n",
"\n",
"\"Ma aspetta!\", dirai dopo aver dato un'occhiata all'intero set di dati con `View(pumpkins)`, \"C'è qualcosa di strano qui!\" 🤔\n",
"\n",
"Se guardi la colonna `Package`, le zucche vengono vendute in molte configurazioni diverse. Alcune sono vendute in misure di `1 1/9 bushel`, altre in misure di `1/2 bushel`, alcune per zucca, altre per libbra, e altre ancora in grandi scatole di larghezze variabili.\n",
"\n",
"Verifichiamolo:\n"
],
"metadata": {
"id": "p77WZr-9aQAR"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Verify the distinct observations in Package column\n",
"pumpkins %>% \n",
" distinct(Package)"
],
"outputs": [],
"metadata": {
"id": "XISGfh0IaUy6"
}
},
{
"cell_type": "markdown",
"source": [
"Fantastico!👏\n",
"\n",
"Le zucche sembrano essere molto difficili da pesare in modo coerente, quindi filtriamole selezionando solo le zucche con la stringa *bushel* nella colonna `Package` e inseriamole in un nuovo data frame `new_pumpkins`.\n"
],
"metadata": {
"id": "7sMjiVujaZxY"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::filter() e stringr::str_detect()\n",
"\n",
"[`dplyr::filter()`](https://dplyr.tidyverse.org/reference/filter.html): crea un sottoinsieme dei dati contenente solo le **righe** che soddisfano le tue condizioni, in questo caso, zucche con la stringa *bushel* nella colonna `Package`.\n",
"\n",
"[stringr::str_detect()](https://stringr.tidyverse.org/reference/str_detect.html): rileva la presenza o l'assenza di un pattern in una stringa.\n",
"\n",
"Il pacchetto [`stringr`](https://github.com/tidyverse/stringr) fornisce funzioni semplici per operazioni comuni sulle stringhe.\n"
],
"metadata": {
"id": "L8Qfcs92ageF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Retain only pumpkins with \"bushel\"\n",
"new_pumpkins <- pumpkins %>% \n",
" filter(str_detect(Package, \"bushel\"))\n",
"\n",
"# Get the dimensions of the new data\n",
"dim(new_pumpkins)\n",
"\n",
"# View a few rows of the new data\n",
"new_pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "hy_SGYREampd"
}
},
{
"cell_type": "markdown",
"source": [
"Puoi vedere che abbiamo ristretto a circa 415 righe di dati contenenti zucche al moggio.🤩 \n",
"
\n"
],
"metadata": {
"id": "VrDwF031avlR"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::case_when()\n",
"\n",
"**Ma aspetta! C'è ancora una cosa da fare**\n",
"\n",
"Hai notato che la quantità di bushel varia per riga? Devi normalizzare i prezzi in modo da mostrare il prezzo per bushel, non per 1 1/9 o 1/2 bushel. È il momento di fare un po' di calcoli per standardizzarlo.\n",
"\n",
"Utilizzeremo la funzione [`case_when()`](https://dplyr.tidyverse.org/reference/case_when.html) per *modificare* la colonna Price in base a determinate condizioni. `case_when` ti permette di vettorializzare più istruzioni `if_else()`.\n"
],
"metadata": {
"id": "mLpw2jH4a0tx"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Convert the price if the Package contains fractional bushel values\n",
"new_pumpkins <- new_pumpkins %>% \n",
" mutate(Price = case_when(\n",
" str_detect(Package, \"1 1/9\") ~ Price/(1 + 1/9),\n",
" str_detect(Package, \"1/2\") ~ Price/(1/2),\n",
" TRUE ~ Price))\n",
"\n",
"# View the first few rows of the data\n",
"new_pumpkins %>% \n",
" slice_head(n = 30)"
],
"outputs": [],
"metadata": {
"id": "P68kLVQmbM6I"
}
},
{
"cell_type": "markdown",
"source": [
"Ora possiamo analizzare il prezzo per unità basandoci sulla loro misura in staia. Tutto questo studio sulle staia di zucche, tuttavia, dimostra quanto sia `importante` `comprendere la natura dei propri dati`!\n",
"\n",
"> ✅ Secondo [The Spruce Eats](https://www.thespruceeats.com/how-much-is-a-bushel-1389308), il peso di una staia dipende dal tipo di prodotto, poiché si tratta di una misura di volume. \"Una staia di pomodori, ad esempio, dovrebbe pesare 56 libbre... Le foglie e le verdure occupano più spazio con meno peso, quindi una staia di spinaci pesa solo 20 libbre.\" È tutto piuttosto complicato! Non preoccupiamoci di fare una conversione da staia a libbre, e invece calcoliamo il prezzo per staia. Tutto questo studio sulle staia di zucche, tuttavia, dimostra quanto sia importante comprendere la natura dei propri dati!\n",
">\n",
"> ✅ Hai notato che le zucche vendute a mezza staia sono molto costose? Riesci a capire il perché? Suggerimento: le zucche piccole sono molto più care di quelle grandi, probabilmente perché ce ne sono molte di più per staia, dato lo spazio inutilizzato occupato da una grande zucca vuota per torte.\n"
],
"metadata": {
"id": "pS2GNPagbSdb"
}
},
{
"cell_type": "markdown",
"source": [
"Ora, per puro spirito d'avventura 💁♀️, spostiamo anche la colonna Mese nella prima posizione, cioè `prima` della colonna `Pacchetto`.\n",
"\n",
"Si utilizza `dplyr::relocate()` per modificare la posizione delle colonne.\n"
],
"metadata": {
"id": "qql1SowfbdnP"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new data frame new_pumpkins\n",
"new_pumpkins <- new_pumpkins %>% \n",
" relocate(Month, .before = Package)\n",
"\n",
"new_pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "JJ1x6kw8bixF"
}
},
{
"cell_type": "markdown",
"source": [
"Ottimo lavoro!👌 Ora hai un dataset pulito e ordinato su cui puoi costruire il tuo nuovo modello di regressione!\n",
"
\n"
],
"metadata": {
"id": "y8TJ0Za_bn5Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 4. Visualizzazione dei dati con ggplot2\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "Ml7SDCLQcPvE"
}
},
{
"cell_type": "markdown",
"source": [
"### **Come lo rendiamo utile?**\n",
"\n",
"Per visualizzare dati utili nei grafici, di solito è necessario raggruppare i dati in qualche modo. Ad esempio, nel nostro caso, calcolare il prezzo medio delle zucche per ogni mese fornirebbe maggiori informazioni sui modelli sottostanti nei nostri dati. Questo ci porta a un'altra panoramica di **dplyr**:\n",
"\n",
"#### `dplyr::group_by() %>% summarize()`\n",
"\n",
"L'aggregazione raggruppata in R può essere facilmente calcolata utilizzando\n",
"\n",
"`dplyr::group_by() %>% summarize()`\n",
"\n",
"- `dplyr::group_by()` cambia l'unità di analisi dal dataset completo ai singoli gruppi, come per mese.\n",
"\n",
"- `dplyr::summarize()` crea un nuovo data frame con una colonna per ogni variabile di raggruppamento e una colonna per ciascuna delle statistiche di riepilogo che hai specificato.\n",
"\n",
"Ad esempio, possiamo utilizzare `dplyr::group_by() %>% summarize()` per raggruppare le zucche in base alla colonna **Month** e poi calcolare il **prezzo medio** per ogni mese.\n"
],
"metadata": {
"id": "jMakvJZIcVkh"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Find the average price of pumpkins per month\r\n",
"new_pumpkins %>%\r\n",
" group_by(Month) %>% \r\n",
" summarise(mean_price = mean(Price))"
],
"outputs": [],
"metadata": {
"id": "6kVSUa2Bcilf"
}
},
{
"cell_type": "markdown",
"source": [
"Succinto!✨\n",
"\n",
"Le caratteristiche categoriche, come i mesi, sono meglio rappresentate utilizzando un grafico a barre 📊. I livelli responsabili per i grafici a barre sono `geom_bar()` e `geom_col()`. Consulta `?geom_bar` per saperne di più.\n",
"\n",
"Prepariamone uno!\n"
],
"metadata": {
"id": "Kds48GUBcj3W"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Find the average price of pumpkins per month then plot a bar chart\r\n",
"new_pumpkins %>%\r\n",
" group_by(Month) %>% \r\n",
" summarise(mean_price = mean(Price)) %>% \r\n",
" ggplot(aes(x = Month, y = mean_price)) +\r\n",
" geom_col(fill = \"midnightblue\", alpha = 0.7) +\r\n",
" ylab(\"Pumpkin Price\")"
],
"outputs": [],
"metadata": {
"id": "VNbU1S3BcrxO"
}
},
{
"cell_type": "markdown",
"source": [
"🤩🤩 Questa è una visualizzazione dei dati più utile! Sembra indicare che il prezzo più alto delle zucche si verifica a settembre e ottobre. Rispecchia le tue aspettative? Perché sì o perché no?\n",
"\n",
"Congratulazioni per aver completato la seconda lezione 👏! Hai preparato i tuoi dati per la costruzione del modello, poi hai scoperto ulteriori approfondimenti utilizzando le visualizzazioni!\n"
],
"metadata": {
"id": "zDm0VOzzcuzR"
}
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Disclaimer**: \nQuesto documento è stato tradotto utilizzando il servizio di traduzione automatica [Co-op Translator](https://github.com/Azure/co-op-translator). Sebbene ci impegniamo per garantire l'accuratezza, si prega di notare che le traduzioni automatiche possono contenere errori o imprecisioni. Il documento originale nella sua lingua nativa dovrebbe essere considerato la fonte autorevole. Per informazioni critiche, si raccomanda una traduzione professionale effettuata da un traduttore umano. Non siamo responsabili per eventuali incomprensioni o interpretazioni errate derivanti dall'uso di questa traduzione.\n"
]
}
]
}