{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "lesson_12-R.ipynb", "provenance": [], "collapsed_sections": [] }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "fab50046ca413a38939d579f8432274f", "translation_date": "2025-08-29T23:52:45+00:00", "source_file": "4-Classification/3-Classifiers-2/solution/R/lesson_12-R.ipynb", "language_code": "it" } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "jsFutf_ygqSx" }, "source": [] }, { "cell_type": "markdown", "metadata": { "id": "HD54bEefgtNO" }, "source": [ "## Classificatori di cucina 2\n", "\n", "In questa seconda lezione sulla classificazione, esploreremo `ulteriori modi` per classificare i dati categorici. Impareremo anche le implicazioni della scelta di un classificatore rispetto a un altro.\n", "\n", "### [**Quiz pre-lezione**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/23/)\n", "\n", "### **Prerequisiti**\n", "\n", "Presumiamo che tu abbia completato le lezioni precedenti, poiché riprenderemo alcuni concetti già appresi.\n", "\n", "Per questa lezione, avremo bisogno dei seguenti pacchetti:\n", "\n", "- `tidyverse`: Il [tidyverse](https://www.tidyverse.org/) è una [collezione di pacchetti R](https://www.tidyverse.org/packages) progettata per rendere la scienza dei dati più veloce, semplice e divertente!\n", "\n", "- `tidymodels`: Il framework [tidymodels](https://www.tidymodels.org/) è una [collezione di pacchetti](https://www.tidymodels.org/packages/) per la modellazione e il machine learning.\n", "\n", "- `themis`: Il pacchetto [themis](https://themis.tidymodels.org/) fornisce passaggi extra per le ricette utili a gestire dati sbilanciati.\n", "\n", "Puoi installarli con il seguente comando:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"kernlab\", \"themis\", \"ranger\", \"xgboost\", \"kknn\"))`\n", "\n", "In alternativa, lo script qui sotto verifica se hai i pacchetti necessari per completare questo modulo e li installa per te nel caso in cui manchino.\n" ] }, { "cell_type": "code", "metadata": { "id": "vZ57IuUxgyQt" }, "source": [ "suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n", "\n", "pacman::p_load(tidyverse, tidymodels, themis, kernlab, ranger, xgboost, kknn)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "z22M-pj4g07x" }, "source": [ "## **1. Una mappa di classificazione**\n", "\n", "Nella nostra [lezione precedente](https://github.com/microsoft/ML-For-Beginners/tree/main/4-Classification/2-Classifiers-1), abbiamo cercato di rispondere alla domanda: come scegliere tra diversi modelli? In gran parte, dipende dalle caratteristiche dei dati e dal tipo di problema che vogliamo risolvere (ad esempio classificazione o regressione?).\n", "\n", "In precedenza, abbiamo imparato le varie opzioni disponibili per classificare i dati utilizzando il cheat sheet di Microsoft. Il framework di Machine Learning di Python, Scikit-learn, offre un cheat sheet simile ma più dettagliato che può aiutare ulteriormente a restringere la scelta dei tuoi stimatori (un altro termine per classificatori):\n", "\n", "

\n", " \n", "

\n" ] }, { "cell_type": "markdown", "metadata": { "id": "u1i3xRIVg7vG" }, "source": [ "> Suggerimento: [visita questa mappa online](https://scikit-learn.org/stable/tutorial/machine_learning_map/) e segui il percorso per leggere la documentazione.\n", ">\n", "> Il [sito di riferimento di Tidymodels](https://www.tidymodels.org/find/parsnip/#models) fornisce anche un'ottima documentazione sui diversi tipi di modelli.\n", "\n", "### **Il piano** 🗺️\n", "\n", "Questa mappa è molto utile una volta che hai una chiara comprensione dei tuoi dati, poiché puoi \"percorrere\" i suoi sentieri per arrivare a una decisione:\n", "\n", "- Abbiamo \\>50 campioni\n", "\n", "- Vogliamo prevedere una categoria\n", "\n", "- Abbiamo dati etichettati\n", "\n", "- Abbiamo meno di 100K campioni\n", "\n", "- ✨ Possiamo scegliere un Linear SVC\n", "\n", "- Se questo non funziona, dato che abbiamo dati numerici\n", "\n", " - Possiamo provare un ✨ KNeighbors Classifier\n", "\n", " - Se anche questo non funziona, provare ✨ SVC e ✨ Ensemble Classifiers\n", "\n", "Questo è un percorso molto utile da seguire. Ora, entriamo subito nel vivo utilizzando il framework di modellazione [tidymodels](https://www.tidymodels.org/): una collezione coerente e flessibile di pacchetti R sviluppata per promuovere buone pratiche statistiche 😊.\n", "\n", "## 2. Dividere i dati e gestire un dataset sbilanciato.\n", "\n", "Dalle lezioni precedenti, abbiamo appreso che c'era un insieme di ingredienti comuni tra le nostre cucine. Inoltre, c'era una distribuzione piuttosto diseguale nel numero di cucine.\n", "\n", "Affronteremo questi aspetti:\n", "\n", "- Eliminando gli ingredienti più comuni che creano confusione tra cucine distinte, utilizzando `dplyr::select()`.\n", "\n", "- Utilizzando una `recipe` che pre-elabora i dati per prepararli alla modellazione applicando un algoritmo di `over-sampling`.\n", "\n", "Abbiamo già visto quanto sopra nella lezione precedente, quindi dovrebbe essere una passeggiata 🥳!\n" ] }, { "cell_type": "code", "metadata": { "id": "6tj_rN00hClA" }, "source": [ "# Load the core Tidyverse and Tidymodels packages\n", "library(tidyverse)\n", "library(tidymodels)\n", "\n", "# Load the original cuisines data\n", "df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/4-Classification/data/cuisines.csv\")\n", "\n", "# Drop id column, rice, garlic and ginger from our original data set\n", "df_select <- df %>% \n", " select(-c(1, rice, garlic, ginger)) %>%\n", " # Encode cuisine column as categorical\n", " mutate(cuisine = factor(cuisine))\n", "\n", "\n", "# Create data split specification\n", "set.seed(2056)\n", "cuisines_split <- initial_split(data = df_select,\n", " strata = cuisine,\n", " prop = 0.7)\n", "\n", "# Extract the data in each split\n", "cuisines_train <- training(cuisines_split)\n", "cuisines_test <- testing(cuisines_split)\n", "\n", "# Display distribution of cuisines in the training set\n", "cuisines_train %>% \n", " count(cuisine) %>% \n", " arrange(desc(n))" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "zFin5yw3hHb1" }, "source": [ "### Gestire dati sbilanciati\n", "\n", "I dati sbilanciati spesso hanno effetti negativi sulle prestazioni del modello. Molti modelli funzionano meglio quando il numero di osservazioni è uguale e, di conseguenza, tendono a incontrare difficoltà con dati non bilanciati.\n", "\n", "Ci sono principalmente due modi per gestire set di dati sbilanciati:\n", "\n", "- aggiungere osservazioni alla classe minoritaria: `Over-sampling`, ad esempio utilizzando un algoritmo SMOTE che genera sinteticamente nuovi esempi della classe minoritaria basandosi sui vicini più prossimi di questi casi.\n", "\n", "- rimuovere osservazioni dalla classe maggioritaria: `Under-sampling`\n", "\n", "Nella nostra lezione precedente, abbiamo dimostrato come gestire set di dati sbilanciati utilizzando una `recipe`. Una recipe può essere considerata come un piano che descrive quali passaggi devono essere applicati a un set di dati per prepararlo all'analisi. Nel nostro caso, vogliamo ottenere una distribuzione equa nel numero delle nostre cucine per il nostro `training set`. Passiamo subito all'azione.\n" ] }, { "cell_type": "code", "metadata": { "id": "cRzTnHolhLWd" }, "source": [ "# Load themis package for dealing with imbalanced data\n", "library(themis)\n", "\n", "# Create a recipe for preprocessing training data\n", "cuisines_recipe <- recipe(cuisine ~ ., data = cuisines_train) %>%\n", " step_smote(cuisine) \n", "\n", "# Print recipe\n", "cuisines_recipe" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "KxOQ2ORhhO81" }, "source": [ "Ora siamo pronti per addestrare i modelli 👩‍💻👨‍💻!\n", "\n", "## 3. Oltre i modelli di regressione multinomiale\n", "\n", "Nella lezione precedente, abbiamo esaminato i modelli di regressione multinomiale. Esploriamo ora alcuni modelli più flessibili per la classificazione.\n", "\n", "### Support Vector Machines\n", "\n", "Nel contesto della classificazione, i `Support Vector Machines` sono una tecnica di machine learning che cerca di trovare un *iperpiano* che separi \"al meglio\" le classi. Vediamo un esempio semplice:\n", "\n", "

\n", " \n", "

https://commons.wikimedia.org/w/index.php?curid=22877598
\n" ] }, { "cell_type": "markdown", "metadata": { "id": "C4Wsd0vZhXYu" }, "source": [ "H1~ non separa le classi. H2~ lo fa, ma solo con un piccolo margine. H3~ le separa con il margine massimo.\n", "\n", "#### Classificatore Lineare a Vettori di Supporto\n", "\n", "Il clustering a Vettori di Supporto (SVC) è un membro della famiglia delle macchine a vettori di supporto (SVM) nelle tecniche di apprendimento automatico. Nell'SVC, l'iperpiano viene scelto per separare correttamente `la maggior parte` delle osservazioni di addestramento, ma `potrebbe classificare erroneamente` alcune osservazioni. Consentendo ad alcuni punti di trovarsi sul lato sbagliato, l'SVM diventa più robusto agli outlier e quindi migliora la generalizzazione su nuovi dati. Il parametro che regola questa violazione è chiamato `cost` e ha un valore predefinito di 1 (vedi `help(\"svm_poly\")`).\n", "\n", "Creiamo un SVC lineare impostando `degree = 1` in un modello SVM polinomiale.\n" ] }, { "cell_type": "code", "metadata": { "id": "vJpp6nuChlBz" }, "source": [ "# Make a linear SVC specification\n", "svc_linear_spec <- svm_poly(degree = 1) %>% \n", " set_engine(\"kernlab\") %>% \n", " set_mode(\"classification\")\n", "\n", "# Bundle specification and recipe into a worklow\n", "svc_linear_wf <- workflow() %>% \n", " add_recipe(cuisines_recipe) %>% \n", " add_model(svc_linear_spec)\n", "\n", "# Print out workflow\n", "svc_linear_wf" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "rDs8cWNkhoqu" }, "source": [ "Ora che abbiamo catturato i passaggi di pre-elaborazione e la specifica del modello in un *workflow*, possiamo procedere con l'addestramento del linear SVC e valutare i risultati nel frattempo. Per quanto riguarda le metriche di performance, creiamo un set di metriche che valuterà: `accuracy`, `sensitivity`, `Positive Predicted Value` e `F Measure`.\n", "\n", "> `augment()` aggiungerà colonna/e per le predizioni ai dati forniti.\n" ] }, { "cell_type": "code", "metadata": { "id": "81wiqcwuhrnq" }, "source": [ "# Train a linear SVC model\n", "svc_linear_fit <- svc_linear_wf %>% \n", " fit(data = cuisines_train)\n", "\n", "# Create a metric set\n", "eval_metrics <- metric_set(ppv, sens, accuracy, f_meas)\n", "\n", "\n", "# Make predictions and Evaluate model performance\n", "svc_linear_fit %>% \n", " augment(new_data = cuisines_test) %>% \n", " eval_metrics(truth = cuisine, estimate = .pred_class)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "0UFQvHf-huo3" }, "source": [ "#### Support Vector Machine\n", "\n", "La support vector machine (SVM) è un'estensione del support vector classifier per gestire un confine non lineare tra le classi. In sostanza, le SVM utilizzano il *kernel trick* per ampliare lo spazio delle caratteristiche e adattarsi alle relazioni non lineari tra le classi. Una funzione kernel popolare e estremamente flessibile utilizzata dalle SVM è la *funzione di base radiale.* Vediamo come si comporterà sui nostri dati.\n" ] }, { "cell_type": "code", "metadata": { "id": "-KX4S8mzhzmp" }, "source": [ "set.seed(2056)\n", "\n", "# Make an RBF SVM specification\n", "svm_rbf_spec <- svm_rbf() %>% \n", " set_engine(\"kernlab\") %>% \n", " set_mode(\"classification\")\n", "\n", "# Bundle specification and recipe into a worklow\n", "svm_rbf_wf <- workflow() %>% \n", " add_recipe(cuisines_recipe) %>% \n", " add_model(svm_rbf_spec)\n", "\n", "\n", "# Train an RBF model\n", "svm_rbf_fit <- svm_rbf_wf %>% \n", " fit(data = cuisines_train)\n", "\n", "\n", "# Make predictions and Evaluate model performance\n", "svm_rbf_fit %>% \n", " augment(new_data = cuisines_test) %>% \n", " eval_metrics(truth = cuisine, estimate = .pred_class)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "QBFSa7WSh4HQ" }, "source": [ "Molto meglio 🤩!\n", "\n", "> ✅ Si prega di consultare:\n", ">\n", "> - [*Support Vector Machines*](https://bradleyboehmke.github.io/HOML/svm.html), Hands-on Machine Learning with R\n", ">\n", "> - [*Support Vector Machines*](https://www.statlearning.com/), An Introduction to Statistical Learning with Applications in R\n", ">\n", "> per ulteriori approfondimenti.\n", "\n", "### Classificatori Nearest Neighbor\n", "\n", "Il metodo *K*-nearest neighbor (KNN) è un algoritmo in cui ogni osservazione viene predetta in base alla sua *somiglianza* con altre osservazioni.\n", "\n", "Applichiamolo ai nostri dati.\n" ] }, { "cell_type": "code", "metadata": { "id": "k4BxxBcdh9Ka" }, "source": [ "# Make a KNN specification\n", "knn_spec <- nearest_neighbor() %>% \n", " set_engine(\"kknn\") %>% \n", " set_mode(\"classification\")\n", "\n", "# Bundle recipe and model specification into a workflow\n", "knn_wf <- workflow() %>% \n", " add_recipe(cuisines_recipe) %>% \n", " add_model(knn_spec)\n", "\n", "# Train a boosted tree model\n", "knn_wf_fit <- knn_wf %>% \n", " fit(data = cuisines_train)\n", "\n", "\n", "# Make predictions and Evaluate model performance\n", "knn_wf_fit %>% \n", " augment(new_data = cuisines_test) %>% \n", " eval_metrics(truth = cuisine, estimate = .pred_class)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "HaegQseriAcj" }, "source": [ "Sembra che questo modello non stia funzionando molto bene. Probabilmente modificare i parametri del modello (vedi `help(\"nearest_neighbor\")`) migliorerà le prestazioni del modello. Assicurati di provarlo.\n", "\n", "> ✅ Consulta:\n", ">\n", "> - [Hands-on Machine Learning with R](https://bradleyboehmke.github.io/HOML/)\n", ">\n", "> - [An Introduction to Statistical Learning with Applications in R](https://www.statlearning.com/)\n", ">\n", "> per saperne di più sui classificatori *K*-Nearest Neighbors.\n", "\n", "### Classificatori ensemble\n", "\n", "Gli algoritmi ensemble funzionano combinando più stimatori di base per produrre un modello ottimale attraverso:\n", "\n", "`bagging`: applicando una *funzione di media* a una collezione di modelli di base\n", "\n", "`boosting`: costruendo una sequenza di modelli che si basano l'uno sull'altro per migliorare le prestazioni predittive.\n", "\n", "Iniziamo provando un modello Random Forest, che costruisce una vasta collezione di alberi decisionali e poi applica una funzione di media per ottenere un modello complessivo migliore.\n" ] }, { "cell_type": "code", "metadata": { "id": "49DPoVs6iK1M" }, "source": [ "# Make a random forest specification\n", "rf_spec <- rand_forest() %>% \n", " set_engine(\"ranger\") %>% \n", " set_mode(\"classification\")\n", "\n", "# Bundle recipe and model specification into a workflow\n", "rf_wf <- workflow() %>% \n", " add_recipe(cuisines_recipe) %>% \n", " add_model(rf_spec)\n", "\n", "# Train a random forest model\n", "rf_wf_fit <- rf_wf %>% \n", " fit(data = cuisines_train)\n", "\n", "\n", "# Make predictions and Evaluate model performance\n", "rf_wf_fit %>% \n", " augment(new_data = cuisines_test) %>% \n", " eval_metrics(truth = cuisine, estimate = .pred_class)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "RGVYwC_aiUWc" }, "source": [ "Ottimo lavoro 👏!\n", "\n", "Proviamo anche a sperimentare con un modello Boosted Tree.\n", "\n", "Boosted Tree definisce un metodo ensemble che crea una serie di alberi decisionali sequenziali, dove ogni albero dipende dai risultati degli alberi precedenti nel tentativo di ridurre progressivamente l'errore. Si concentra sui pesi degli elementi classificati in modo errato e regola l'adattamento per il classificatore successivo al fine di correggere.\n", "\n", "Ci sono diversi modi per adattare questo modello (vedi `help(\"boost_tree\")`). In questo esempio, adatteremo i Boosted Tree tramite il motore `xgboost`.\n" ] }, { "cell_type": "code", "metadata": { "id": "Py1YWo-micWs" }, "source": [ "# Make a boosted tree specification\n", "boost_spec <- boost_tree(trees = 200) %>% \n", " set_engine(\"xgboost\") %>% \n", " set_mode(\"classification\")\n", "\n", "# Bundle recipe and model specification into a workflow\n", "boost_wf <- workflow() %>% \n", " add_recipe(cuisines_recipe) %>% \n", " add_model(boost_spec)\n", "\n", "# Train a boosted tree model\n", "boost_wf_fit <- boost_wf %>% \n", " fit(data = cuisines_train)\n", "\n", "\n", "# Make predictions and Evaluate model performance\n", "boost_wf_fit %>% \n", " augment(new_data = cuisines_test) %>% \n", " eval_metrics(truth = cuisine, estimate = .pred_class)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "zNQnbuejigZM" }, "source": [ "> ✅ Si prega di consultare:\n", ">\n", "> - [Machine Learning for Social Scientists](https://cimentadaj.github.io/ml_socsci/tree-based-methods.html#random-forests)\n", ">\n", "> - [Hands-on Machine Learning with R](https://bradleyboehmke.github.io/HOML/)\n", ">\n", "> - [An Introduction to Statistical Learning with Applications in R](https://www.statlearning.com/)\n", ">\n", "> - - Esplora il modello AdaBoost, che rappresenta una buona alternativa a xgboost.\n", ">\n", "> per saperne di più sui classificatori Ensemble.\n", "\n", "## 4. Extra - confronto tra modelli multipli\n", "\n", "Abbiamo adattato un bel numero di modelli in questo laboratorio 🙌. Può diventare noioso o complicato creare molti workflow da diversi set di preprocessori e/o specifiche di modelli e poi calcolare le metriche di performance una per una.\n", "\n", "Vediamo se possiamo affrontare questo problema creando una funzione che adatta una lista di workflow al set di addestramento e poi restituisce le metriche di performance basate sul set di test. Utilizzeremo `map()` e `map_dfr()` dal pacchetto [purrr](https://purrr.tidyverse.org/) per applicare funzioni a ciascun elemento della lista.\n", "\n", "> Le funzioni [`map()`](https://purrr.tidyverse.org/reference/map.html) ti permettono di sostituire molti cicli for con codice che è sia più conciso che più facile da leggere. Il miglior posto per imparare le funzioni [`map()`](https://purrr.tidyverse.org/reference/map.html) è il [capitolo sull'iterazione](http://r4ds.had.co.nz/iteration.html) in R for data science.\n" ] }, { "cell_type": "code", "metadata": { "id": "Qzb7LyZnimd2" }, "source": [ "set.seed(2056)\n", "\n", "# Create a metric set\n", "eval_metrics <- metric_set(ppv, sens, accuracy, f_meas)\n", "\n", "# Define a function that returns performance metrics\n", "compare_models <- function(workflow_list, train_set, test_set){\n", " \n", " suppressWarnings(\n", " # Fit each model to the train_set\n", " map(workflow_list, fit, data = train_set) %>% \n", " # Make predictions on the test set\n", " map_dfr(augment, new_data = test_set, .id = \"model\") %>%\n", " # Select desired columns\n", " select(model, cuisine, .pred_class) %>% \n", " # Evaluate model performance\n", " group_by(model) %>% \n", " eval_metrics(truth = cuisine, estimate = .pred_class) %>% \n", " ungroup()\n", " )\n", " \n", "} # End of function" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "Fwa712sNisDA" }, "source": [] }, { "cell_type": "code", "metadata": { "id": "3i4VJOi2iu-a" }, "source": [ "# Make a list of workflows\n", "workflow_list <- list(\n", " \"svc\" = svc_linear_wf,\n", " \"svm\" = svm_rbf_wf,\n", " \"knn\" = knn_wf,\n", " \"random_forest\" = rf_wf,\n", " \"xgboost\" = boost_wf)\n", "\n", "# Call the function\n", "set.seed(2056)\n", "perf_metrics <- compare_models(workflow_list = workflow_list, train_set = cuisines_train, test_set = cuisines_test)\n", "\n", "# Print out performance metrics\n", "perf_metrics %>% \n", " group_by(.metric) %>% \n", " arrange(desc(.estimate)) %>% \n", " slice_head(n=7)\n", "\n", "# Compare accuracy\n", "perf_metrics %>% \n", " filter(.metric == \"accuracy\") %>% \n", " arrange(desc(.estimate))\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "KuWK_lEli4nW" }, "source": [ "Il pacchetto [**workflowset**](https://workflowsets.tidymodels.org/) permette agli utenti di creare e adattare facilmente un gran numero di modelli, ma è principalmente progettato per lavorare con tecniche di campionamento come la `validazione incrociata`, un approccio che dobbiamo ancora trattare.\n", "\n", "## **🚀Sfida**\n", "\n", "Ognuna di queste tecniche ha un gran numero di parametri che puoi modificare, ad esempio `cost` negli SVM, `neighbors` in KNN, `mtry` (Predittori Selezionati Casualmente) in Random Forest.\n", "\n", "Ricerca i parametri predefiniti di ciascuno e pensa a cosa significherebbe modificare questi parametri per la qualità del modello.\n", "\n", "Per saperne di più su un particolare modello e i suoi parametri, usa: `help(\"model\")`, ad esempio `help(\"rand_forest\")`.\n", "\n", "> In pratica, di solito *stimiamo* i *valori migliori* per questi parametri allenando molti modelli su un `set di dati simulato` e misurando quanto bene si comportano tutti questi modelli. Questo processo si chiama **ottimizzazione**.\n", "\n", "### [**Quiz post-lezione**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/24/)\n", "\n", "### **Revisione e Studio Autonomo**\n", "\n", "C'è molto gergo in queste lezioni, quindi prenditi un momento per rivedere [questa lista](https://docs.microsoft.com/dotnet/machine-learning/resources/glossary?WT.mc_id=academic-77952-leestott) di terminologia utile!\n", "\n", "#### GRAZIE A:\n", "\n", "[`Allison Horst`](https://twitter.com/allison_horst/) per aver creato le incredibili illustrazioni che rendono R più accogliente e coinvolgente. Trova altre illustrazioni nella sua [galleria](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n", "\n", "[Cassie Breviu](https://www.twitter.com/cassieview) e [Jen Looper](https://www.twitter.com/jenlooper) per aver creato la versione originale in Python di questo modulo ♥️\n", "\n", "Buono studio,\n", "\n", "[Eric](https://twitter.com/ericntay), Gold Microsoft Learn Student Ambassador.\n", "\n", "

\n", " \n", "

Illustrazione di @allison_horst
\n" ] }, { "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" ] } ] }