{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Δημιουργία μοντέλου λογιστικής παλινδρόμησης - Μάθημα 4\n", "\n", "![Γραφικό πληροφοριών: Λογιστική vs. Γραμμική παλινδρόμηση](../../../../../../2-Regression/4-Logistic/images/linear-vs-logistic.png)\n", "\n", "#### **[Προ-μάθημα κουίζ](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n", "\n", "#### Εισαγωγή\n", "\n", "Στο τελευταίο μάθημα για την Παλινδρόμηση, μία από τις βασικές *κλασικές* τεχνικές Μηχανικής Μάθησης, θα εξετάσουμε τη Λογιστική Παλινδρόμηση. Αυτή η τεχνική χρησιμοποιείται για την ανακάλυψη μοτίβων ώστε να προβλέψουμε δυαδικές κατηγορίες. Είναι αυτό το γλυκό σοκολάτα ή όχι; Είναι αυτή η ασθένεια μεταδοτική ή όχι; Θα επιλέξει αυτός ο πελάτης το προϊόν ή όχι;\n", "\n", "Σε αυτό το μάθημα, θα μάθετε:\n", "\n", "- Τεχνικές για λογιστική παλινδρόμηση\n", "\n", "✅ Εμβαθύνετε την κατανόησή σας για την εργασία με αυτόν τον τύπο παλινδρόμησης σε αυτό το [Learn module](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)\n", "\n", "## Προαπαιτούμενα\n", "\n", "Έχοντας δουλέψει με τα δεδομένα κολοκύθας, είμαστε πλέον αρκετά εξοικειωμένοι ώστε να συνειδητοποιήσουμε ότι υπάρχει μία δυαδική κατηγορία με την οποία μπορούμε να δουλέψουμε: `Color`.\n", "\n", "Ας δημιουργήσουμε ένα μοντέλο λογιστικής παλινδρόμησης για να προβλέψουμε, δεδομένων κάποιων μεταβλητών, *ποιο χρώμα είναι πιθανό να έχει μια δεδομένη κολοκύθα* (πορτοκαλί 🎃 ή λευκό 👻).\n", "\n", "> Γιατί μιλάμε για δυαδική ταξινόμηση σε ένα μάθημα που αφορά την παλινδρόμηση; Μόνο για γλωσσική ευκολία, καθώς η λογιστική παλινδρόμηση είναι [στην πραγματικότητα μια μέθοδος ταξινόμησης](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), αν και βασίζεται σε γραμμικές αρχές. Μάθετε για άλλους τρόπους ταξινόμησης δεδομένων στην επόμενη ομάδα μαθημάτων.\n", "\n", "Για αυτό το μάθημα, θα χρειαστούμε τα παρακάτω πακέτα:\n", "\n", "- `tidyverse`: Το [tidyverse](https://www.tidyverse.org/) είναι μια [συλλογή πακέτων R](https://www.tidyverse.org/packages) σχεδιασμένη για να κάνει την επιστήμη δεδομένων πιο γρήγορη, εύκολη και διασκεδαστική!\n", "\n", "- `tidymodels`: Το [tidymodels](https://www.tidymodels.org/) είναι ένα [πλαίσιο συλλογής πακέτων](https://www.tidymodels.org/packages/) για μοντελοποίηση και μηχανική μάθηση.\n", "\n", "- `janitor`: Το [πακέτο janitor](https://github.com/sfirke/janitor) παρέχει απλά εργαλεία για την εξέταση και τον καθαρισμό \"βρώμικων\" δεδομένων.\n", "\n", "- `ggbeeswarm`: Το [πακέτο ggbeeswarm](https://github.com/eclarke/ggbeeswarm) παρέχει μεθόδους για τη δημιουργία γραφημάτων τύπου beeswarm χρησιμοποιώντας το ggplot2.\n", "\n", "Μπορείτε να τα εγκαταστήσετε ως εξής:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n", "\n", "Εναλλακτικά, το παρακάτω script ελέγχει αν έχετε τα απαραίτητα πακέτα για την ολοκλήρωση αυτού του μαθήματος και τα εγκαθιστά για εσάς σε περίπτωση που λείπουν.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n", "\n", "pacman::p_load(tidyverse, tidymodels, janitor, ggbeeswarm)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **Ορισμός της ερώτησης**\n", "\n", "Για τους σκοπούς μας, θα εκφράσουμε την ερώτηση ως δυαδική: 'Λευκό' ή 'Μη Λευκό'. Υπάρχει επίσης μια κατηγορία 'ριγέ' στο σύνολο δεδομένων μας, αλλά υπάρχουν λίγες περιπτώσεις αυτής, οπότε δεν θα τη χρησιμοποιήσουμε. Εξάλλου, εξαφανίζεται όταν αφαιρούμε τις τιμές null από το σύνολο δεδομένων.\n", "\n", "> 🎃 Διασκεδαστικό γεγονός: Μερικές φορές αποκαλούμε τα λευκά κολοκύθια 'κολοκύθια-φαντάσματα'. Δεν είναι πολύ εύκολο να τα σκαλίσουμε, γι' αυτό δεν είναι τόσο δημοφιλή όσο τα πορτοκαλί, αλλά έχουν ενδιαφέρον εμφάνιση! Έτσι, θα μπορούσαμε επίσης να διατυπώσουμε την ερώτησή μας ως: 'Φάντασμα' ή 'Μη Φάντασμα'. 👻\n", "\n", "## **Σχετικά με την λογιστική παλινδρόμηση**\n", "\n", "Η λογιστική παλινδρόμηση διαφέρει από τη γραμμική παλινδρόμηση, την οποία μάθατε προηγουμένως, σε μερικά σημαντικά σημεία.\n", "\n", "#### **Δυαδική ταξινόμηση**\n", "\n", "Η λογιστική παλινδρόμηση δεν προσφέρει τις ίδιες δυνατότητες με τη γραμμική παλινδρόμηση. Η πρώτη προσφέρει πρόβλεψη για μια `δυαδική κατηγορία` (\"πορτοκαλί ή μη πορτοκαλί\"), ενώ η δεύτερη είναι ικανή να προβλέπει `συνεχείς τιμές`, για παράδειγμα, δεδομένης της προέλευσης μιας κολοκύθας και του χρόνου συγκομιδής, *πόσο θα αυξηθεί η τιμή της*.\n", "\n", "![Infographic από την Dasani Madipalli](../../../../../../2-Regression/4-Logistic/images/pumpkin-classifier.png)\n", "\n", "### Άλλες ταξινομήσεις\n", "\n", "Υπάρχουν άλλοι τύποι λογιστικής παλινδρόμησης, συμπεριλαμβανομένων των πολυωνυμικών και των διατακτικών:\n", "\n", "- **Πολυωνυμική**, που περιλαμβάνει περισσότερες από μία κατηγορίες - \"Πορτοκαλί, Λευκό και Ριγέ\".\n", "\n", "- **Διατακτική**, που περιλαμβάνει διατεταγμένες κατηγορίες, χρήσιμη αν θέλαμε να ταξινομήσουμε τα αποτελέσματά μας λογικά, όπως οι κολοκύθες μας που ταξινομούνται με βάση έναν πεπερασμένο αριθμό μεγεθών (mini, sm, med, lg, xl, xxl).\n", "\n", "![Πολυωνυμική vs διατακτική παλινδρόμηση](../../../../../../2-Regression/4-Logistic/images/multinomial-vs-ordinal.png)\n", "\n", "#### **Οι μεταβλητές ΔΕΝ χρειάζεται να συσχετίζονται**\n", "\n", "Θυμάστε πώς η γραμμική παλινδρόμηση λειτουργούσε καλύτερα με πιο συσχετισμένες μεταβλητές; Η λογιστική παλινδρόμηση είναι το αντίθετο - οι μεταβλητές δεν χρειάζεται να ευθυγραμμίζονται. Αυτό λειτουργεί για αυτά τα δεδομένα που έχουν σχετικά αδύναμες συσχετίσεις.\n", "\n", "#### **Χρειάζεστε πολλά καθαρά δεδομένα**\n", "\n", "Η λογιστική παλινδρόμηση θα δώσει πιο ακριβή αποτελέσματα αν χρησιμοποιήσετε περισσότερα δεδομένα. Το μικρό μας σύνολο δεδομένων δεν είναι ιδανικό για αυτήν την εργασία, οπότε λάβετε το υπόψη σας.\n", "\n", "✅ Σκεφτείτε τους τύπους δεδομένων που θα ήταν κατάλληλοι για λογιστική παλινδρόμηση.\n", "\n", "## Άσκηση - καθαρίστε τα δεδομένα\n", "\n", "Πρώτα, καθαρίστε λίγο τα δεδομένα, αφαιρώντας τις τιμές null και επιλέγοντας μόνο ορισμένες στήλες:\n", "\n", "1. Προσθέστε τον ακόλουθο κώδικα:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Load the core tidyverse packages\n", "library(tidyverse)\n", "\n", "# Import the data and clean column names\n", "pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\") %>% \n", " clean_names()\n", "\n", "# Select desired columns\n", "pumpkins_select <- pumpkins %>% \n", " select(c(city_name, package, variety, origin, item_size, color)) \n", "\n", "# Drop rows containing missing values and encode color as factor (category)\n", "pumpkins_select <- pumpkins_select %>% \n", " drop_na() %>% \n", " mutate(color = factor(color))\n", "\n", "# View the first few rows\n", "pumpkins_select %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Μπορείτε πάντα να ρίξετε μια ματιά στο νέο σας dataframe, χρησιμοποιώντας τη συνάρτηση [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html) όπως φαίνεται παρακάτω:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "pumpkins_select %>% \n", " glimpse()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ας επιβεβαιώσουμε ότι θα ασχοληθούμε με ένα πρόβλημα δυαδικής ταξινόμησης:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Subset distinct observations in outcome column\n", "pumpkins_select %>% \n", " distinct(color)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Οπτικοποίηση - κατηγορικό διάγραμμα\n", "Μέχρι τώρα έχετε φορτώσει ξανά τα δεδομένα για τις κολοκύθες και τα έχετε καθαρίσει ώστε να διατηρήσετε ένα σύνολο δεδομένων που περιλαμβάνει μερικές μεταβλητές, όπως το Χρώμα. Ας οπτικοποιήσουμε το dataframe στο notebook χρησιμοποιώντας τη βιβλιοθήκη ggplot.\n", "\n", "Η βιβλιοθήκη ggplot προσφέρει μερικούς έξυπνους τρόπους για να οπτικοποιήσετε τα δεδομένα σας. Για παράδειγμα, μπορείτε να συγκρίνετε τις κατανομές των δεδομένων για κάθε Ποικιλία και Χρώμα σε ένα κατηγορικό διάγραμμα.\n", "\n", "1. Δημιουργήστε ένα τέτοιο διάγραμμα χρησιμοποιώντας τη συνάρτηση geombar, με τα δεδομένα για τις κολοκύθες, και καθορίζοντας έναν χρωματικό χάρτη για κάθε κατηγορία κολοκύθας (πορτοκαλί ή λευκή):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# Specify colors for each value of the hue variable\n", "palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n", "\n", "# Create the bar plot\n", "ggplot(pumpkins_select, aes(y = variety, fill = color)) +\n", " geom_bar(position = \"dodge\") +\n", " scale_fill_manual(values = palette) +\n", " labs(y = \"Variety\", fill = \"Color\") +\n", " theme_minimal()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Παρατηρώντας τα δεδομένα, μπορείτε να δείτε πώς τα δεδομένα Χρώματος σχετίζονται με την Ποικιλία.\n", "\n", "✅ Με βάση αυτό το κατηγοριακό διάγραμμα, ποιες ενδιαφέρουσες εξερευνήσεις μπορείτε να φανταστείτε;\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Προεπεξεργασία δεδομένων: κωδικοποίηση χαρακτηριστικών\n", "\n", "Το σύνολο δεδομένων μας για τις κολοκύθες περιέχει τιμές κειμένου για όλες τις στήλες του. Η εργασία με κατηγορικά δεδομένα είναι διαισθητική για τους ανθρώπους, αλλά όχι για τις μηχανές. Οι αλγόριθμοι μηχανικής μάθησης λειτουργούν καλύτερα με αριθμούς. Γι' αυτό η κωδικοποίηση είναι ένα πολύ σημαντικό βήμα στη φάση της προεπεξεργασίας δεδομένων, καθώς μας επιτρέπει να μετατρέψουμε τα κατηγορικά δεδομένα σε αριθμητικά, χωρίς να χάσουμε καμία πληροφορία. Η σωστή κωδικοποίηση οδηγεί στη δημιουργία ενός καλού μοντέλου.\n", "\n", "Για την κωδικοποίηση χαρακτηριστικών υπάρχουν δύο κύριοι τύποι κωδικοποιητών:\n", "\n", "1. Ordinal encoder: είναι κατάλληλος για τακτικές μεταβλητές, οι οποίες είναι κατηγορικές μεταβλητές όπου τα δεδομένα τους ακολουθούν μια λογική σειρά, όπως η στήλη `item_size` στο σύνολο δεδομένων μας. Δημιουργεί έναν χάρτη έτσι ώστε κάθε κατηγορία να εκπροσωπείται από έναν αριθμό, ο οποίος είναι η σειρά της κατηγορίας στη στήλη.\n", "\n", "2. Categorical encoder: είναι κατάλληλος για ονομαστικές μεταβλητές, οι οποίες είναι κατηγορικές μεταβλητές όπου τα δεδομένα τους δεν ακολουθούν μια λογική σειρά, όπως όλα τα χαρακτηριστικά εκτός από το `item_size` στο σύνολο δεδομένων μας. Είναι μια κωδικοποίηση one-hot, που σημαίνει ότι κάθε κατηγορία εκπροσωπείται από μια δυαδική στήλη: η κωδικοποιημένη μεταβλητή είναι ίση με 1 αν η κολοκύθα ανήκει σε αυτήν την ποικιλία και 0 διαφορετικά.\n", "\n", "Το Tidymodels παρέχει ένα ακόμη χρήσιμο πακέτο: [recipes](https://recipes.tidymodels.org/) - ένα πακέτο για την προεπεξεργασία δεδομένων. Θα ορίσουμε μια `recipe` που καθορίζει ότι όλες οι στήλες προβλεπτών πρέπει να κωδικοποιηθούν σε ένα σύνολο ακέραιων αριθμών, θα την `prep` για να εκτιμήσουμε τις απαιτούμενες ποσότητες και στατιστικά που χρειάζονται για οποιαδήποτε λειτουργία και τέλος θα την `bake` για να εφαρμόσουμε τους υπολογισμούς σε νέα δεδομένα.\n", "\n", "> Συνήθως, το recipes χρησιμοποιείται ως προεπεξεργαστής για τη μοντελοποίηση, όπου καθορίζει ποια βήματα πρέπει να εφαρμοστούν σε ένα σύνολο δεδομένων για να είναι έτοιμο για μοντελοποίηση. Σε αυτήν την περίπτωση είναι **πολύ προτεινόμενο** να χρησιμοποιήσετε ένα `workflow()` αντί να εκτιμάτε χειροκίνητα μια συνταγή χρησιμοποιώντας prep και bake. Θα δούμε όλα αυτά σε λίγο.\n", ">\n", "> Ωστόσο, προς το παρόν, χρησιμοποιούμε recipes + prep + bake για να καθορίσουμε ποια βήματα πρέπει να εφαρμοστούν σε ένα σύνολο δεδομένων για να είναι έτοιμο για ανάλυση δεδομένων και στη συνέχεια να εξάγουμε τα προεπεξεργασμένα δεδομένα με τα βήματα που έχουν εφαρμοστεί.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Preprocess and extract data to allow some data analysis\n", "baked_pumpkins <- recipe(color ~ ., data = pumpkins_select) %>%\n", " # Define ordering for item_size column\n", " step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n", " # Convert factors to numbers using the order defined above (Ordinal encoding)\n", " step_integer(item_size, zero_based = F) %>%\n", " # Encode all other predictors using one hot encoding\n", " step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE) %>%\n", " prep(data = pumpkin_select) %>%\n", " bake(new_data = NULL)\n", "\n", "# Display the first few rows of preprocessed data\n", "baked_pumpkins %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "✅ Ποια είναι τα πλεονεκτήματα της χρήσης ενός ordinal encoder για τη στήλη Item Size;\n", "\n", "### Ανάλυση σχέσεων μεταξύ μεταβλητών\n", "\n", "Τώρα που έχουμε προεπεξεργαστεί τα δεδομένα μας, μπορούμε να αναλύσουμε τις σχέσεις μεταξύ των χαρακτηριστικών και της ετικέτας, ώστε να αποκτήσουμε μια ιδέα για το πόσο καλά θα μπορέσει το μοντέλο να προβλέψει την ετικέτα με βάση τα χαρακτηριστικά. Ο καλύτερος τρόπος για να πραγματοποιήσουμε αυτό το είδος ανάλυσης είναι η απεικόνιση των δεδομένων. \n", "Θα χρησιμοποιήσουμε ξανά τη συνάρτηση ggplot geom_boxplot_ για να οπτικοποιήσουμε τις σχέσεις μεταξύ του Item Size, Variety και Color σε μια κατηγορική απεικόνιση. Για καλύτερη απεικόνιση των δεδομένων, θα χρησιμοποιήσουμε την κωδικοποιημένη στήλη Item Size και την μη κωδικοποιημένη στήλη Variety.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Define the color palette\n", "palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n", "\n", "# We need the encoded Item Size column to use it as the x-axis values in the plot\n", "pumpkins_select_plot<-pumpkins_select\n", "pumpkins_select_plot$item_size <- baked_pumpkins$item_size\n", "\n", "# Create the grouped box plot\n", "ggplot(pumpkins_select_plot, aes(x = `item_size`, y = color, fill = color)) +\n", " geom_boxplot() +\n", " facet_grid(variety ~ ., scales = \"free_x\") +\n", " scale_fill_manual(values = palette) +\n", " labs(x = \"Item Size\", y = \"\") +\n", " theme_minimal() +\n", " theme(strip.text = element_text(size = 12)) +\n", " theme(axis.text.x = element_text(size = 10)) +\n", " theme(axis.title.x = element_text(size = 12)) +\n", " theme(axis.title.y = element_blank()) +\n", " theme(legend.position = \"bottom\") +\n", " guides(fill = guide_legend(title = \"Color\")) +\n", " theme(panel.spacing = unit(0.5, \"lines\"))+\n", " theme(strip.text.y = element_text(size = 4, hjust = 0)) \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Χρησιμοποιήστε ένα swarm plot\n", "\n", "Δεδομένου ότι το Color είναι μια δυαδική κατηγορία (Λευκό ή Όχι), απαιτείται 'μια [εξειδικευμένη προσέγγιση](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf) για την οπτικοποίησή του'.\n", "\n", "Δοκιμάστε ένα `swarm plot` για να δείξετε την κατανομή του χρώματος σε σχέση με το item_size.\n", "\n", "Θα χρησιμοποιήσουμε το [πακέτο ggbeeswarm](https://github.com/eclarke/ggbeeswarm), το οποίο παρέχει μεθόδους για τη δημιουργία διαγραμμάτων τύπου beeswarm χρησιμοποιώντας το ggplot2. Τα διαγράμματα beeswarm είναι ένας τρόπος απεικόνισης σημείων που κανονικά θα επικαλύπτονταν, έτσι ώστε να τοποθετούνται το ένα δίπλα στο άλλο.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Create beeswarm plots of color and item_size\n", "baked_pumpkins %>% \n", " mutate(color = factor(color)) %>% \n", " ggplot(mapping = aes(x = color, y = item_size, color = color)) +\n", " geom_quasirandom() +\n", " scale_color_brewer(palette = \"Dark2\", direction = -1) +\n", " theme(legend.position = \"none\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Τώρα που έχουμε μια ιδέα για τη σχέση μεταξύ των δυαδικών κατηγοριών του χρώματος και της μεγαλύτερης ομάδας των μεγεθών, ας εξερευνήσουμε τη λογιστική παλινδρόμηση για να καθορίσουμε το πιθανό χρώμα μιας δεδομένης κολοκύθας.\n", "\n", "## Δημιουργήστε το μοντέλο σας\n", "\n", "Επιλέξτε τις μεταβλητές που θέλετε να χρησιμοποιήσετε στο μοντέλο ταξινόμησης και χωρίστε τα δεδομένα σε σύνολα εκπαίδευσης και δοκιμής. Το [rsample](https://rsample.tidymodels.org/), ένα πακέτο στο Tidymodels, παρέχει υποδομή για αποτελεσματική διαίρεση και επαναδειγματοληψία δεδομένων:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Split data into 80% for training and 20% for testing\n", "set.seed(2056)\n", "pumpkins_split <- pumpkins_select %>% \n", " initial_split(prop = 0.8)\n", "\n", "# Extract the data in each split\n", "pumpkins_train <- training(pumpkins_split)\n", "pumpkins_test <- testing(pumpkins_split)\n", "\n", "# Print out the first 5 rows of the training set\n", "pumpkins_train %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "🙌 Είμαστε τώρα έτοιμοι να εκπαιδεύσουμε ένα μοντέλο προσαρμόζοντας τα χαρακτηριστικά εκπαίδευσης στην ετικέτα εκπαίδευσης (χρώμα).\n", "\n", "Θα ξεκινήσουμε δημιουργώντας μια συνταγή που καθορίζει τα βήματα προεπεξεργασίας που πρέπει να πραγματοποιηθούν στα δεδομένα μας για να τα προετοιμάσουμε για μοντελοποίηση, δηλαδή: κωδικοποίηση κατηγορικών μεταβλητών σε ένα σύνολο ακέραιων αριθμών. Όπως και με το `baked_pumpkins`, δημιουργούμε μια `pumpkins_recipe` αλλά δεν κάνουμε `prep` και `bake`, καθώς αυτά θα ενσωματωθούν σε μια ροή εργασίας, την οποία θα δείτε σε λίγα βήματα από τώρα.\n", "\n", "Υπάρχουν αρκετοί τρόποι για να καθορίσετε ένα μοντέλο λογιστικής παλινδρόμησης στο Tidymodels. Δείτε `?logistic_reg()`. Προς το παρόν, θα καθορίσουμε ένα μοντέλο λογιστικής παλινδρόμησης μέσω της προεπιλεγμένης μηχανής `stats::glm()`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Create a recipe that specifies preprocessing steps for modelling\n", "pumpkins_recipe <- recipe(color ~ ., data = pumpkins_train) %>% \n", " step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n", " step_integer(item_size, zero_based = F) %>% \n", " step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE)\n", "\n", "# Create a logistic model specification\n", "log_reg <- logistic_reg() %>% \n", " set_engine(\"glm\") %>% \n", " set_mode(\"classification\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Τώρα που έχουμε μια συνταγή και μια προδιαγραφή μοντέλου, πρέπει να βρούμε έναν τρόπο να τα συνδυάσουμε σε ένα αντικείμενο που θα επεξεργάζεται πρώτα τα δεδομένα (prep+bake στο παρασκήνιο), θα προσαρμόζει το μοντέλο στα επεξεργασμένα δεδομένα και θα επιτρέπει επίσης πιθανές δραστηριότητες μετά την επεξεργασία.\n", "\n", "Στο Tidymodels, αυτό το πρακτικό αντικείμενο ονομάζεται [`workflow`](https://workflows.tidymodels.org/) και συγκεντρώνει βολικά τα συστατικά του μοντέλου σας.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Bundle modelling components in a workflow\n", "log_reg_wf <- workflow() %>% \n", " add_recipe(pumpkins_recipe) %>% \n", " add_model(log_reg)\n", "\n", "# Print out the workflow\n", "log_reg_wf\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Αφού έχει *καθοριστεί* μια ροή εργασίας, ένα μοντέλο μπορεί να `εκπαιδευτεί` χρησιμοποιώντας τη συνάρτηση [`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html). Η ροή εργασίας θα εκτιμήσει μια συνταγή και θα προεπεξεργαστεί τα δεδομένα πριν από την εκπαίδευση, οπότε δεν θα χρειαστεί να το κάνουμε αυτό χειροκίνητα χρησιμοποιώντας τις prep και bake.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Train the model\n", "wf_fit <- log_reg_wf %>% \n", " fit(data = pumpkins_train)\n", "\n", "# Print the trained workflow\n", "wf_fit\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Το μοντέλο εκτυπώνει τους συντελεστές που έμαθε κατά τη διάρκεια της εκπαίδευσης.\n", "\n", "Τώρα που έχουμε εκπαιδεύσει το μοντέλο χρησιμοποιώντας τα δεδομένα εκπαίδευσης, μπορούμε να κάνουμε προβλέψεις στα δεδομένα δοκιμής χρησιμοποιώντας [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). Ας ξεκινήσουμε χρησιμοποιώντας το μοντέλο για να προβλέψουμε ετικέτες για το σύνολο δοκιμής μας και τις πιθανότητες για κάθε ετικέτα. Όταν η πιθανότητα είναι μεγαλύτερη από 0.5, η προβλεπόμενη κατηγορία είναι `WHITE`, διαφορετικά είναι `ORANGE`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Make predictions for color and corresponding probabilities\n", "results <- pumpkins_test %>% select(color) %>% \n", " bind_cols(wf_fit %>% \n", " predict(new_data = pumpkins_test)) %>%\n", " bind_cols(wf_fit %>%\n", " predict(new_data = pumpkins_test, type = \"prob\"))\n", "\n", "# Compare predictions\n", "results %>% \n", " slice_head(n = 10)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Πολύ ωραία! Αυτό μας δίνει μια καλύτερη κατανόηση του τρόπου λειτουργίας της λογιστικής παλινδρόμησης.\n", "\n", "### Καλύτερη κατανόηση μέσω ενός πίνακα σύγχυσης\n", "\n", "Η σύγκριση κάθε πρόβλεψης με την αντίστοιχη \"πραγματική\" τιμή αναφοράς δεν είναι ένας πολύ αποδοτικός τρόπος για να καθορίσουμε πόσο καλά προβλέπει το μοντέλο. Ευτυχώς, το Tidymodels έχει μερικά ακόμα κόλπα στο μανίκι του: το [`yardstick`](https://yardstick.tidymodels.org/) - ένα πακέτο που χρησιμοποιείται για τη μέτρηση της αποτελεσματικότητας των μοντέλων μέσω μετρικών απόδοσης.\n", "\n", "Μία μετρική απόδοσης που σχετίζεται με προβλήματα ταξινόμησης είναι ο [`πίνακας σύγχυσης`](https://wikipedia.org/wiki/Confusion_matrix). Ένας πίνακας σύγχυσης περιγράφει πόσο καλά αποδίδει ένα μοντέλο ταξινόμησης. Καταγράφει πόσα παραδείγματα σε κάθε κατηγορία ταξινομήθηκαν σωστά από το μοντέλο. Στην περίπτωσή μας, θα σας δείξει πόσες πορτοκαλί κολοκύθες ταξινομήθηκαν ως πορτοκαλί και πόσες λευκές κολοκύθες ταξινομήθηκαν ως λευκές· ο πίνακας σύγχυσης δείχνει επίσης πόσες ταξινομήθηκαν σε **λάθος** κατηγορίες.\n", "\n", "Η [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) συνάρτηση από το yardstick υπολογίζει αυτή τη διασταυρούμενη ταξινόμηση των παρατηρούμενων και προβλεπόμενων κατηγοριών.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Confusion matrix for prediction results\n", "conf_mat(data = results, truth = color, estimate = .pred_class)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ας ερμηνεύσουμε τον πίνακα σύγχυσης. Το μοντέλο μας καλείται να ταξινομήσει κολοκύθες μεταξύ δύο δυαδικών κατηγοριών, την κατηγορία `λευκή` και την κατηγορία `μη-λευκή`.\n", "\n", "- Εάν το μοντέλο σας προβλέψει μια κολοκύθα ως λευκή και αυτή ανήκει στην κατηγορία 'λευκή' στην πραγματικότητα, το αποκαλούμε `αληθώς θετικό`, που φαίνεται από τον αριθμό επάνω αριστερά.\n", "\n", "- Εάν το μοντέλο σας προβλέψει μια κολοκύθα ως μη λευκή και αυτή ανήκει στην κατηγορία 'λευκή' στην πραγματικότητα, το αποκαλούμε `ψευδώς αρνητικό`, που φαίνεται από τον αριθμό κάτω αριστερά.\n", "\n", "- Εάν το μοντέλο σας προβλέψει μια κολοκύθα ως λευκή και αυτή ανήκει στην κατηγορία 'μη-λευκή' στην πραγματικότητα, το αποκαλούμε `ψευδώς θετικό`, που φαίνεται από τον αριθμό επάνω δεξιά.\n", "\n", "- Εάν το μοντέλο σας προβλέψει μια κολοκύθα ως μη λευκή και αυτή ανήκει στην κατηγορία 'μη-λευκή' στην πραγματικότητα, το αποκαλούμε `αληθώς αρνητικό`, που φαίνεται από τον αριθμό κάτω δεξιά.\n", "\n", "| Αλήθεια |\n", "|:-----:|\n", "\n", "\n", "| | | |\n", "|---------------|--------|-------|\n", "| **Προβλεπόμενο** | ΛΕΥΚΗ | ΠΟΡΤΟΚΑΛΙ |\n", "| ΛΕΥΚΗ | TP | FP |\n", "| ΠΟΡΤΟΚΑΛΙ | FN | TN |\n", "\n", "Όπως ίσως έχετε μαντέψει, είναι προτιμότερο να έχουμε μεγαλύτερο αριθμό αληθώς θετικών και αληθώς αρνητικών και μικρότερο αριθμό ψευδώς θετικών και ψευδώς αρνητικών, κάτι που υποδηλώνει ότι το μοντέλο αποδίδει καλύτερα.\n", "\n", "Ο πίνακας σύγχυσης είναι χρήσιμος καθώς οδηγεί σε άλλες μετρικές που μπορούν να μας βοηθήσουν να αξιολογήσουμε καλύτερα την απόδοση ενός μοντέλου ταξινόμησης. Ας δούμε μερικές από αυτές:\n", "\n", "🎓 Ακρίβεια (Precision): `TP/(TP + FP)` ορίζεται ως το ποσοστό των προβλεπόμενων θετικών που είναι πραγματικά θετικά. Επίσης αποκαλείται [θετική προγνωστική αξία](https://en.wikipedia.org/wiki/Positive_predictive_value \"Positive predictive value\").\n", "\n", "🎓 Ανάκληση (Recall): `TP/(TP + FN)` ορίζεται ως το ποσοστό των θετικών αποτελεσμάτων από τον αριθμό των δειγμάτων που ήταν πραγματικά θετικά. Επίσης γνωστή ως `ευαισθησία`.\n", "\n", "🎓 Ειδικότητα (Specificity): `TN/(TN + FP)` ορίζεται ως το ποσοστό των αρνητικών αποτελεσμάτων από τον αριθμό των δειγμάτων που ήταν πραγματικά αρνητικά.\n", "\n", "🎓 Ακρίβεια (Accuracy): `TP + TN/(TP + TN + FP + FN)` Το ποσοστό των ετικετών που προβλέφθηκαν σωστά για ένα δείγμα.\n", "\n", "🎓 Μέτρο F (F Measure): Ένας σταθμισμένος μέσος όρος της ακρίβειας και της ανάκλησης, με το καλύτερο να είναι 1 και το χειρότερο να είναι 0.\n", "\n", "Ας υπολογίσουμε αυτές τις μετρικές!\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Combine metric functions and calculate them all at once\n", "eval_metrics <- metric_set(ppv, recall, spec, f_meas, accuracy)\n", "eval_metrics(data = results, truth = color, estimate = .pred_class)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Οπτικοποίηση της καμπύλης ROC αυτού του μοντέλου\n", "\n", "Ας κάνουμε μία ακόμη οπτικοποίηση για να δούμε την αποκαλούμενη [`καμπύλη ROC`](https://en.wikipedia.org/wiki/Receiver_operating_characteristic):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Make a roc_curve\n", "results %>% \n", " roc_curve(color, .pred_ORANGE) %>% \n", " autoplot()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Οι καμπύλες ROC χρησιμοποιούνται συχνά για να αποκτήσουμε μια εικόνα της απόδοσης ενός ταξινομητή σε όρους αληθών έναντι ψευδών θετικών. Οι καμπύλες ROC συνήθως απεικονίζουν τον `True Positive Rate`/Ευαισθησία στον άξονα Y και τον `False Positive Rate`/1-Ειδικότητα στον άξονα X. Έτσι, η κλίση της καμπύλης και ο χώρος μεταξύ της γραμμής του μέσου σημείου και της καμπύλης έχουν σημασία: θέλουμε μια καμπύλη που ανεβαίνει γρήγορα και περνάει πάνω από τη γραμμή. Στην περίπτωσή μας, υπάρχουν ψευδώς θετικά στην αρχή, και στη συνέχεια η γραμμή ανεβαίνει και περνάει σωστά πάνω.\n", "\n", "Τέλος, ας χρησιμοποιήσουμε το `yardstick::roc_auc()` για να υπολογίσουμε την πραγματική Επιφάνεια Κάτω από την Καμπύλη (Area Under the Curve). Ένας τρόπος ερμηνείας του AUC είναι ως η πιθανότητα το μοντέλο να κατατάξει ένα τυχαίο θετικό παράδειγμα υψηλότερα από ένα τυχαίο αρνητικό παράδειγμα.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Calculate area under curve\n", "results %>% \n", " roc_auc(color, .pred_ORANGE)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Το αποτέλεσμα είναι περίπου `0.975`. Δεδομένου ότι το AUC κυμαίνεται από 0 έως 1, θέλετε ένα υψηλό σκορ, καθώς ένα μοντέλο που είναι 100% σωστό στις προβλέψεις του θα έχει AUC ίσο με 1. Σε αυτή την περίπτωση, το μοντέλο είναι *αρκετά καλό*.\n", "\n", "Στα επόμενα μαθήματα για ταξινομήσεις, θα μάθετε πώς να βελτιώσετε τα σκορ του μοντέλου σας (όπως η αντιμετώπιση μη ισορροπημένων δεδομένων σε αυτή την περίπτωση).\n", "\n", "## 🚀Πρόκληση\n", "\n", "Υπάρχουν πολλά περισσότερα να εξερευνήσετε σχετικά με την λογιστική παλινδρόμηση! Αλλά ο καλύτερος τρόπος για να μάθετε είναι να πειραματιστείτε. Βρείτε ένα σύνολο δεδομένων που ταιριάζει σε αυτόν τον τύπο ανάλυσης και δημιουργήστε ένα μοντέλο με αυτό. Τι μαθαίνετε; συμβουλή: δοκιμάστε το [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) για ενδιαφέροντα σύνολα δεδομένων.\n", "\n", "## Ανασκόπηση & Αυτομελέτη\n", "\n", "Διαβάστε τις πρώτες σελίδες από [αυτό το άρθρο του Stanford](https://web.stanford.edu/~jurafsky/slp3/5.pdf) σχετικά με κάποιες πρακτικές χρήσεις της λογιστικής παλινδρόμησης. Σκεφτείτε εργασίες που ταιριάζουν καλύτερα σε έναν ή τον άλλο τύπο παλινδρόμησης που έχουμε μελετήσει μέχρι τώρα. Τι θα λειτουργούσε καλύτερα;\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**Αποποίηση ευθύνης**: \nΑυτό το έγγραφο έχει μεταφραστεί χρησιμοποιώντας την υπηρεσία αυτόματης μετάφρασης [Co-op Translator](https://github.com/Azure/co-op-translator). Παρόλο που καταβάλλουμε προσπάθειες για ακρίβεια, παρακαλούμε να έχετε υπόψη ότι οι αυτόματες μεταφράσεις ενδέχεται να περιέχουν σφάλματα ή ανακρίβειες. Το πρωτότυπο έγγραφο στη μητρική του γλώσσα θα πρέπει να θεωρείται η αυθεντική πηγή. Για κρίσιμες πληροφορίες, συνιστάται επαγγελματική ανθρώπινη μετάφραση. Δεν φέρουμε ευθύνη για τυχόν παρεξηγήσεις ή εσφαλμένες ερμηνείες που προκύπτουν από τη χρήση αυτής της μετάφρασης.\n" ] } ], "metadata": { "anaconda-cloud": "", "kernelspec": { "display_name": "R", "langauge": "R", "name": "ir" }, "language_info": { "codemirror_mode": "r", "file_extension": ".r", "mimetype": "text/x-r-source", "name": "R", "pygments_lexer": "r", "version": "3.4.1" }, "coopTranslator": { "original_hash": "feaf125f481a89c468fa115bf2aed580", "translation_date": "2025-09-04T06:51:00+00:00", "source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb", "language_code": "el" } }, "nbformat": 4, "nbformat_minor": 1 }