{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_3-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "5015d65d61ba75a223bfc56c273aa174", "translation_date": "2025-09-04T01:13:39+00:00", "source_file": "2-Regression/3-Linear/solution/R/lesson_3-R.ipynb", "language_code": "de" } }, "cells": [ { "cell_type": "markdown", "source": [], "metadata": { "id": "EgQw8osnsUV-" } }, { "cell_type": "markdown", "source": [ "## Lineare und polynomiale Regression für Kürbispreise - Lektion 3\n", "

\n", " \n", "

Infografik von Dasani Madipalli
\n", "\n", "\n", "#### Einführung\n", "\n", "Bisher hast du untersucht, was Regression ist, anhand von Beispieldaten aus dem Kürbispreis-Datensatz, den wir in dieser Lektion verwenden werden. Du hast sie auch mit `ggplot2` visualisiert. 💪\n", "\n", "Jetzt bist du bereit, tiefer in die Regression für maschinelles Lernen einzutauchen. In dieser Lektion wirst du mehr über zwei Arten der Regression lernen: *einfache lineare Regression* und *polynomiale Regression*, zusammen mit einigen mathematischen Grundlagen dieser Techniken.\n", "\n", "> Im gesamten Lehrplan gehen wir von minimalen mathematischen Kenntnissen aus und versuchen, das Thema für Studierende aus anderen Bereichen zugänglich zu machen. Achte daher auf Hinweise, 🧮 Erläuterungen, Diagramme und andere Lernhilfen, die das Verständnis erleichtern.\n", "\n", "#### Vorbereitung\n", "\n", "Zur Erinnerung: Du lädst diese Daten, um Fragen dazu zu stellen.\n", "\n", "- Wann ist der beste Zeitpunkt, Kürbisse zu kaufen?\n", "\n", "- Welchen Preis kann ich für eine Kiste mit Miniaturkürbissen erwarten?\n", "\n", "- Sollte ich sie in halben Scheffelkörben oder in einer 1 1/9 Scheffelbox kaufen? Lass uns weiter in diese Daten eintauchen.\n", "\n", "In der vorherigen Lektion hast du ein `tibble` (eine moderne Neuinterpretation des Dataframes) erstellt und es mit einem Teil des ursprünglichen Datensatzes gefüllt, wobei du die Preise standardisiert nach Scheffel angegeben hast. Dadurch konntest du jedoch nur etwa 400 Datenpunkte sammeln, und das nur für die Herbstmonate. Vielleicht können wir durch eine gründlichere Bereinigung der Daten mehr Details über die Natur der Daten erhalten? Mal sehen... 🕵️‍♀️\n", "\n", "Für diese Aufgabe benötigen wir die folgenden Pakete:\n", "\n", "- `tidyverse`: Das [tidyverse](https://www.tidyverse.org/) ist eine [Sammlung von R-Paketen](https://www.tidyverse.org/packages), die Datenwissenschaft schneller, einfacher und unterhaltsamer macht!\n", "\n", "- `tidymodels`: Das [tidymodels](https://www.tidymodels.org/) Framework ist eine [Sammlung von Paketen](https://www.tidymodels.org/packages/) für Modellierung und maschinelles Lernen.\n", "\n", "- `janitor`: Das [janitor-Paket](https://github.com/sfirke/janitor) bietet einfache kleine Werkzeuge zur Untersuchung und Bereinigung von unordentlichen Daten.\n", "\n", "- `corrplot`: Das [corrplot-Paket](https://cran.r-project.org/web/packages/corrplot/vignettes/corrplot-intro.html) bietet ein visuelles Explorationswerkzeug für Korrelationsmatrizen, das die automatische Neuordnung von Variablen unterstützt, um versteckte Muster zwischen Variablen zu erkennen.\n", "\n", "Du kannst sie wie folgt installieren:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"corrplot\"))`\n", "\n", "Das untenstehende Skript überprüft, ob du die für dieses Modul benötigten Pakete hast, und installiert sie für dich, falls sie fehlen.\n" ], "metadata": { "id": "WqQPS1OAsg3H" } }, { "cell_type": "code", "execution_count": null, "source": [ "suppressWarnings(if (!require(\"pacman\")) install.packages(\"pacman\"))\n", "\n", "pacman::p_load(tidyverse, tidymodels, janitor, corrplot)" ], "outputs": [], "metadata": { "id": "tA4C2WN3skCf", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "c06cd805-5534-4edc-f72b-d0d1dab96ac0" } }, { "cell_type": "markdown", "source": [ "Wir werden später diese großartigen Pakete laden und sie in unserer aktuellen R-Sitzung verfügbar machen. (Das dient nur zur Veranschaulichung, `pacman::p_load()` hat das bereits für Sie erledigt.)\n", "\n", "## 1. Eine lineare Regressionslinie\n", "\n", "Wie Sie in Lektion 1 gelernt haben, besteht das Ziel einer linearen Regression darin, eine *Linie* *der* *besten Anpassung* zu zeichnen, um:\n", "\n", "- **Variable Beziehungen zu zeigen**. Die Beziehung zwischen Variablen darzustellen.\n", "\n", "- **Vorhersagen zu treffen**. Präzise Vorhersagen darüber zu machen, wo ein neuer Datenpunkt im Verhältnis zu dieser Linie liegen würde.\n", "\n", "Um diese Art von Linie zu zeichnen, verwenden wir eine statistische Technik namens **Least-Squares Regression**. Der Begriff `least-squares` bedeutet, dass alle Datenpunkte um die Regressionslinie herum quadriert und dann addiert werden. Idealerweise ist diese endgültige Summe so klein wie möglich, da wir eine geringe Anzahl von Fehlern oder `least-squares` anstreben. Die Linie der besten Anpassung ist daher die Linie, die uns den niedrigsten Wert für die Summe der quadrierten Fehler liefert – daher der Name *Least-Squares Regression*.\n", "\n", "Wir tun dies, weil wir eine Linie modellieren möchten, die die geringste kumulative Entfernung von all unseren Datenpunkten hat. Wir quadrieren die Terme vor dem Addieren, da uns die Größe und nicht die Richtung interessiert.\n", "\n", "> **🧮 Zeig mir die Mathematik**\n", ">\n", "> Diese Linie, genannt *Linie der besten Anpassung*, kann durch [eine Gleichung](https://en.wikipedia.org/wiki/Simple_linear_regression) ausgedrückt werden:\n", ">\n", "> Y = a + bX\n", ">\n", "> `X` ist die '`erklärende Variable` oder `Prädiktor`'. `Y` ist die '`abhängige Variable` oder `Ergebnis`'. Die Steigung der Linie ist `b` und `a` ist der y-Achsenabschnitt, der den Wert von `Y` angibt, wenn `X = 0`.\n", ">\n", "\n", "> ![](../../../../../../2-Regression/3-Linear/solution/images/slope.png \"Steigung = $y/x$\")\n", " Infografik von Jen Looper\n", ">\n", "> Zuerst berechnen wir die Steigung `b`.\n", ">\n", "> Anders ausgedrückt, und bezogen auf die ursprüngliche Frage zu unseren Kürbisdaten: \"den Preis eines Kürbisses pro Scheffel nach Monat vorhersagen\", würde `X` den Preis und `Y` den Verkaufsmonat darstellen.\n", ">\n", "> ![](../../../../../../translated_images/calculation.989aa7822020d9d0ba9fc781f1ab5192f3421be86ebb88026528aef33c37b0d8.de.png)\n", " Infografik von Jen Looper\n", "> \n", "> Berechnen Sie den Wert von Y. Wenn Sie etwa 4 \\$ zahlen, muss es April sein!\n", ">\n", "> Die Mathematik, die die Linie berechnet, muss die Steigung der Linie demonstrieren, die auch vom Achsenabschnitt abhängt, oder wo `Y` liegt, wenn `X = 0`.\n", ">\n", "> Sie können die Methode zur Berechnung dieser Werte auf der Website [Math is Fun](https://www.mathsisfun.com/data/least-squares-regression.html) beobachten. Besuchen Sie auch [diesen Least-Squares-Rechner](https://www.mathsisfun.com/data/least-squares-calculator.html), um zu sehen, wie die Werte der Zahlen die Linie beeinflussen.\n", "\n", "Gar nicht so beängstigend, oder? 🤓\n", "\n", "#### Korrelation\n", "\n", "Ein weiterer Begriff, den Sie verstehen sollten, ist der **Korrelationskoeffizient** zwischen den gegebenen X- und Y-Variablen. Mithilfe eines Streudiagramms können Sie diesen Koeffizienten schnell visualisieren. Ein Diagramm mit Datenpunkten, die in einer ordentlichen Linie angeordnet sind, hat eine hohe Korrelation, während ein Diagramm mit Datenpunkten, die überall zwischen X und Y verstreut sind, eine niedrige Korrelation aufweist.\n", "\n", "Ein gutes lineares Regressionsmodell ist eines, das einen hohen (näher an 1 als an 0) Korrelationskoeffizienten mit der Least-Squares Regression-Methode und einer Regressionslinie aufweist.\n" ], "metadata": { "id": "cdX5FRpvsoP5" } }, { "cell_type": "markdown", "source": [ "## **2. Ein Tanz mit Daten: Erstellen eines Dataframes für das Modellieren**\n", "\n", "

\n", " \n", "

Kunstwerk von @allison_horst
\n", "\n", "\n", "\n" ], "metadata": { "id": "WdUKXk7Bs8-V" } }, { "cell_type": "markdown", "source": [ "Lade die benötigten Bibliotheken und den Datensatz. Konvertiere die Daten in einen Dataframe, der einen Teil der Daten enthält:\n", "\n", "- Nur Kürbisse auswählen, die nach Scheffelpreis bewertet sind\n", "\n", "- Das Datum in einen Monat umwandeln\n", "\n", "- Den Preis als Durchschnitt aus hohen und niedrigen Preisen berechnen\n", "\n", "- Den Preis so umrechnen, dass er die Bewertung nach Scheffelmenge widerspiegelt\n", "\n", "> Diese Schritte haben wir in der [vorherigen Lektion](https://github.com/microsoft/ML-For-Beginners/blob/main/2-Regression/2-Data/solution/lesson_2-R.ipynb) behandelt.\n" ], "metadata": { "id": "fMCtu2G2s-p8" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Load the core Tidyverse packages\n", "library(tidyverse)\n", "library(lubridate)\n", "\n", "# Import the pumpkins data\n", "pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\")\n", "\n", "\n", "# Get a glimpse and dimensions of the data\n", "glimpse(pumpkins)\n", "\n", "\n", "# Print the first 50 rows of the data set\n", "pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "ryMVZEEPtERn" } }, { "cell_type": "markdown", "source": [ "Im Geiste des reinen Abenteuers lassen Sie uns das [`janitor package`](../../../../../../2-Regression/3-Linear/solution/R/github.com/sfirke/janitor) erkunden, das einfache Funktionen zum Untersuchen und Bereinigen von unordentlichen Daten bietet. Zum Beispiel werfen wir einen Blick auf die Spaltennamen unserer Daten:\n" ], "metadata": { "id": "xcNxM70EtJjb" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Return column names\n", "pumpkins %>% \n", " names()" ], "outputs": [], "metadata": { "id": "5XtpaIigtPfW" } }, { "cell_type": "markdown", "source": [ "🤔 Wir können es besser machen. Lassen Sie uns diese Spaltennamen `friendR` machen, indem wir sie mit der [snake_case](https://de.wikipedia.org/wiki/Snake_case)-Konvention mit `janitor::clean_names` umwandeln. Um mehr über diese Funktion zu erfahren: `?clean_names`\n" ], "metadata": { "id": "IbIqrMINtSHe" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Clean names to the snake_case convention\n", "pumpkins <- pumpkins %>% \n", " clean_names(case = \"snake\")\n", "\n", "# Return column names\n", "pumpkins %>% \n", " names()" ], "outputs": [], "metadata": { "id": "a2uYvclYtWvX" } }, { "cell_type": "markdown", "source": [ "Viel tidyR 🧹! Jetzt ein Tanz mit den Daten, wie in der vorherigen Lektion, mit `dplyr`! 💃\n" ], "metadata": { "id": "HfhnuzDDtaDd" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Select desired columns\n", "pumpkins <- pumpkins %>% \n", " select(variety, city_name, package, low_price, high_price, date)\n", "\n", "\n", "\n", "# Extract the month from the dates to a new column\n", "pumpkins <- pumpkins %>%\n", " mutate(date = mdy(date),\n", " month = month(date)) %>% \n", " select(-date)\n", "\n", "\n", "\n", "# Create a new column for average Price\n", "pumpkins <- pumpkins %>% \n", " mutate(price = (low_price + high_price)/2)\n", "\n", "\n", "# Retain only pumpkins with the string \"bushel\"\n", "new_pumpkins <- pumpkins %>% \n", " filter(str_detect(string = package, pattern = \"bushel\"))\n", "\n", "\n", "# Normalize the pricing so that you show the pricing per bushel, not per 1 1/9 or 1/2 bushel\n", "new_pumpkins <- new_pumpkins %>% \n", " mutate(price = case_when(\n", " str_detect(package, \"1 1/9\") ~ price/(1.1),\n", " str_detect(package, \"1/2\") ~ price*2,\n", " TRUE ~ price))\n", "\n", "# Relocate column positions\n", "new_pumpkins <- new_pumpkins %>% \n", " relocate(month, .before = variety)\n", "\n", "\n", "# Display the first 5 rows\n", "new_pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "X0wU3gQvtd9f" } }, { "cell_type": "markdown", "source": [ "Gute Arbeit! 👌 Du hast jetzt einen sauberen, aufgeräumten Datensatz, mit dem du dein neues Regressionsmodell erstellen kannst!\n", "\n", "Wie wäre es mit einem Streudiagramm?\n" ], "metadata": { "id": "UpaIwaxqth82" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Set theme\n", "theme_set(theme_light())\n", "\n", "# Make a scatter plot of month and price\n", "new_pumpkins %>% \n", " ggplot(mapping = aes(x = month, y = price)) +\n", " geom_point(size = 1.6)\n" ], "outputs": [], "metadata": { "id": "DXgU-j37tl5K" } }, { "cell_type": "markdown", "source": [ "Ein Streudiagramm erinnert uns daran, dass wir nur Monatsdaten von August bis Dezember haben. Wir benötigen wahrscheinlich mehr Daten, um Schlussfolgerungen auf eine lineare Weise ziehen zu können.\n", "\n", "Werfen wir erneut einen Blick auf unsere Modellierungsdaten:\n" ], "metadata": { "id": "Ve64wVbwtobI" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Display first 5 rows\n", "new_pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "HFQX2ng1tuSJ" } }, { "cell_type": "markdown", "source": [ "Was wäre, wenn wir den `Preis` eines Kürbisses basierend auf den Spalten `Stadt` oder `Paket`, die vom Typ Zeichenkette sind, vorhersagen wollten? Oder noch einfacher, wie könnten wir die Korrelation (die erfordert, dass beide Eingaben numerisch sind) zwischen beispielsweise `Paket` und `Preis` finden? 🤷🤷\n", "\n", "Maschinelle Lernmodelle funktionieren am besten mit numerischen Merkmalen anstelle von Textwerten, daher müssen kategorische Merkmale in der Regel in numerische Darstellungen umgewandelt werden.\n", "\n", "Das bedeutet, dass wir einen Weg finden müssen, unsere Prädiktoren so umzuformatieren, dass sie für ein Modell effektiver nutzbar sind – ein Prozess, der als `Feature Engineering` bekannt ist.\n" ], "metadata": { "id": "7hsHoxsStyjJ" } }, { "cell_type": "markdown", "source": [ "## 3. Vorverarbeitung von Daten für die Modellierung mit Recipes 👩‍🍳👨‍🍳\n", "\n", "Aktivitäten, die Prädiktorwerte umformatieren, um sie für ein Modell effektiver nutzbar zu machen, werden als `Feature Engineering` bezeichnet.\n", "\n", "Verschiedene Modelle haben unterschiedliche Anforderungen an die Vorverarbeitung. Zum Beispiel erfordert die Methode der kleinsten Quadrate die `Kodierung kategorischer Variablen` wie Monat, Sorte und Stadtname. Dies bedeutet einfach, dass eine Spalte mit `kategorischen Werten` in eine oder mehrere `numerische Spalten` übersetzt wird, die die ursprüngliche Spalte ersetzen.\n", "\n", "Angenommen, Ihre Daten enthalten die folgende kategorische Variable:\n", "\n", "| Stadt |\n", "|:--------:|\n", "| Denver |\n", "| Nairobi |\n", "| Tokio |\n", "\n", "Sie können *ordinale Kodierung* anwenden, um jeder Kategorie einen eindeutigen Ganzzahlwert zuzuweisen, wie folgt:\n", "\n", "| Stadt |\n", "|:-----:|\n", "| 0 |\n", "| 1 |\n", "| 2 |\n", "\n", "Und genau das werden wir mit unseren Daten machen!\n", "\n", "In diesem Abschnitt werden wir ein weiteres großartiges Tidymodels-Paket erkunden: [recipes](https://tidymodels.github.io/recipes/) - das entwickelt wurde, um Ihnen bei der Vorverarbeitung Ihrer Daten **vor** dem Training Ihres Modells zu helfen. Im Kern ist ein Recipe ein Objekt, das definiert, welche Schritte auf einen Datensatz angewendet werden sollen, um ihn für die Modellierung vorzubereiten.\n", "\n", "Nun erstellen wir ein Recipe, das unsere Daten für die Modellierung vorbereitet, indem es für alle Beobachtungen in den Prädiktorspalten einen eindeutigen Ganzzahlwert ersetzt:\n" ], "metadata": { "id": "AD5kQbcvt3Xl" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Specify a recipe\n", "pumpkins_recipe <- recipe(price ~ ., data = new_pumpkins) %>% \n", " step_integer(all_predictors(), zero_based = TRUE)\n", "\n", "\n", "# Print out the recipe\n", "pumpkins_recipe" ], "outputs": [], "metadata": { "id": "BNaFKXfRt9TU" } }, { "cell_type": "markdown", "source": [ "Super! 👏 Wir haben gerade unser erstes Rezept erstellt, das ein Ergebnis (Preis) und die dazugehörigen Prädiktoren spezifiziert und alle Prädiktorspalten in eine Menge von Ganzzahlen kodiert 🙌! Lass uns das schnell aufschlüsseln:\n", "\n", "- Der Aufruf von `recipe()` mit einer Formel teilt dem Rezept die *Rollen* der Variablen mit, wobei die Daten aus `new_pumpkins` als Referenz verwendet werden. Zum Beispiel wurde der `price`-Spalte die Rolle `outcome` zugewiesen, während die restlichen Spalten die Rolle `predictor` erhalten haben.\n", "\n", "- `step_integer(all_predictors(), zero_based = TRUE)` gibt an, dass alle Prädiktoren in eine Menge von Ganzzahlen umgewandelt werden sollen, wobei die Nummerierung bei 0 beginnt.\n", "\n", "Wir sind sicher, dass du dir gerade Gedanken machst wie: \"Das ist so cool!! Aber was, wenn ich überprüfen möchte, ob die Rezepte genau das tun, was ich von ihnen erwarte? 🤔\"\n", "\n", "Das ist ein großartiger Gedanke! Siehst du, sobald dein Rezept definiert ist, kannst du die Parameter schätzen, die erforderlich sind, um die Daten tatsächlich vorzubereiten, und dann die verarbeiteten Daten extrahieren. Normalerweise musst du das nicht tun, wenn du Tidymodels verwendest (wir werden gleich die übliche Vorgehensweise sehen -> `workflows`), aber es kann nützlich sein, wenn du eine Art Plausibilitätsprüfung durchführen möchtest, um sicherzustellen, dass die Rezepte das tun, was du erwartest.\n", "\n", "Dafür brauchst du zwei weitere Verben: `prep()` und `bake()`. Und wie immer helfen dir unsere kleinen R-Freunde von [`Allison Horst`](https://github.com/allisonhorst/stats-illustrations) dabei, das besser zu verstehen!\n", "\n", "

\n", " \n", "

Kunstwerk von @allison_horst
\n" ], "metadata": { "id": "KEiO0v7kuC9O" } }, { "cell_type": "markdown", "source": [ "[`prep()`](https://recipes.tidymodels.org/reference/prep.html): schätzt die erforderlichen Parameter aus einem Trainingssatz, die später auf andere Datensätze angewendet werden können. Zum Beispiel, für eine gegebene Prädiktorspalte, welche Beobachtung wird der Ganzzahl 0, 1, 2 usw. zugewiesen.\n", "\n", "[`bake()`](https://recipes.tidymodels.org/reference/bake.html): nimmt ein vorbereitetes Rezept und wendet die Operationen auf jeden beliebigen Datensatz an.\n", "\n", "Das gesagt, lassen Sie uns unsere Rezepte vorbereiten und anwenden, um wirklich zu bestätigen, dass die Prädiktorspalten im Hintergrund zuerst kodiert werden, bevor ein Modell angepasst wird.\n" ], "metadata": { "id": "Q1xtzebuuTCP" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Prep the recipe\n", "pumpkins_prep <- prep(pumpkins_recipe)\n", "\n", "# Bake the recipe to extract a preprocessed new_pumpkins data\n", "baked_pumpkins <- bake(pumpkins_prep, new_data = NULL)\n", "\n", "# Print out the baked data set\n", "baked_pumpkins %>% \n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "FGBbJbP_uUUn" } }, { "cell_type": "markdown", "source": [ "Woo-hoo!🥳 Die verarbeiteten Daten `baked_pumpkins` haben alle ihre Prädiktoren kodiert, was bestätigt, dass die im Rezept definierten Vorverarbeitungsschritte wie erwartet funktionieren. Das macht es zwar schwieriger für dich zu lesen, aber viel verständlicher für Tidymodels! Nimm dir etwas Zeit, um herauszufinden, welche Beobachtung einer entsprechenden Ganzzahl zugeordnet wurde.\n", "\n", "Es ist auch erwähnenswert, dass `baked_pumpkins` ein Dataframe ist, auf dem wir Berechnungen durchführen können.\n", "\n", "Zum Beispiel können wir versuchen, eine gute Korrelation zwischen zwei Punkten deiner Daten zu finden, um möglicherweise ein gutes Vorhersagemodell zu erstellen. Dafür verwenden wir die Funktion `cor()`. Gib `?cor()` ein, um mehr über die Funktion zu erfahren.\n" ], "metadata": { "id": "1dvP0LBUueAW" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Find the correlation between the city_name and the price\n", "cor(baked_pumpkins$city_name, baked_pumpkins$price)\n", "\n", "# Find the correlation between the package and the price\n", "cor(baked_pumpkins$package, baked_pumpkins$price)\n" ], "outputs": [], "metadata": { "id": "3bQzXCjFuiSV" } }, { "cell_type": "markdown", "source": [ "Wie sich herausstellt, gibt es nur eine schwache Korrelation zwischen der Stadt und dem Preis. Allerdings gibt es eine etwas stärkere Korrelation zwischen dem Paket und seinem Preis. Das ergibt Sinn, oder? Normalerweise gilt: Je größer die Obst- oder Gemüsekiste, desto höher der Preis.\n", "\n", "Während wir schon dabei sind, können wir auch versuchen, eine Korrelationsmatrix aller Spalten mit dem `corrplot`-Paket zu visualisieren.\n" ], "metadata": { "id": "BToPWbgjuoZw" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Load the corrplot package\n", "library(corrplot)\n", "\n", "# Obtain correlation matrix\n", "corr_mat <- cor(baked_pumpkins %>% \n", " # Drop columns that are not really informative\n", " select(-c(low_price, high_price)))\n", "\n", "# Make a correlation plot between the variables\n", "corrplot(corr_mat, method = \"shade\", shade.col = NA, tl.col = \"black\", tl.srt = 45, addCoef.col = \"black\", cl.pos = \"n\", order = \"original\")" ], "outputs": [], "metadata": { "id": "ZwAL3ksmutVR" } }, { "cell_type": "markdown", "source": [ "🤩🤩 Viel besser.\n", "\n", "Eine gute Frage, die man jetzt zu diesen Daten stellen könnte, wäre: '`Welchen Preis kann ich für ein bestimmtes Kürbispaket erwarten?`' Lassen Sie uns direkt loslegen!\n", "\n", "> Hinweis: Wenn Sie das vorbereitete Rezept **`pumpkins_prep`** mit **`new_data = NULL`** **`bake()`**, extrahieren Sie die verarbeiteten (d.h. kodierten) Trainingsdaten. Wenn Sie ein anderes Datenset hätten, beispielsweise ein Testset, und sehen möchten, wie ein Rezept es vorverarbeiten würde, könnten Sie einfach **`pumpkins_prep`** mit **`new_data = test_set`** backen.\n", "\n", "## 4. Erstellen Sie ein lineares Regressionsmodell\n", "\n", "

\n", " \n", "

Infografik von Dasani Madipalli
\n", "\n", "\n", "\n" ], "metadata": { "id": "YqXjLuWavNxW" } }, { "cell_type": "markdown", "source": [ "Jetzt, da wir ein Rezept erstellt und tatsächlich bestätigt haben, dass die Daten angemessen vorverarbeitet werden, bauen wir nun ein Regressionsmodell, um die folgende Frage zu beantworten: `Welchen Preis kann ich für ein bestimmtes Kürbispaket erwarten?`\n", "\n", "#### Trainiere ein lineares Regressionsmodell mit dem Trainingsdatensatz\n", "\n", "Wie Sie wahrscheinlich schon herausgefunden haben, ist die Spalte *price* die `Zielvariable`, während die Spalte *package* die `Prädiktorvariable` ist.\n", "\n", "Um dies zu tun, werden wir die Daten zunächst so aufteilen, dass 80 % in den Trainings- und 20 % in den Testdatensatz gehen. Anschließend definieren wir ein Rezept, das die Prädiktorspalte in eine Reihe von Ganzzahlen kodiert, und erstellen eine Modellspezifikation. Wir werden unser Rezept nicht vorbereiten und backen, da wir bereits wissen, dass es die Daten wie erwartet vorverarbeitet.\n" ], "metadata": { "id": "Pq0bSzCevW-h" } }, { "cell_type": "code", "execution_count": null, "source": [ "set.seed(2056)\n", "# Split the data into training and test sets\n", "pumpkins_split <- new_pumpkins %>% \n", " initial_split(prop = 0.8)\n", "\n", "\n", "# Extract training and test data\n", "pumpkins_train <- training(pumpkins_split)\n", "pumpkins_test <- testing(pumpkins_split)\n", "\n", "\n", "\n", "# Create a recipe for preprocessing the data\n", "lm_pumpkins_recipe <- recipe(price ~ package, data = pumpkins_train) %>% \n", " step_integer(all_predictors(), zero_based = TRUE)\n", "\n", "\n", "\n", "# Create a linear model specification\n", "lm_spec <- linear_reg() %>% \n", " set_engine(\"lm\") %>% \n", " set_mode(\"regression\")" ], "outputs": [], "metadata": { "id": "CyoEh_wuvcLv" } }, { "cell_type": "markdown", "source": [ "Gut gemacht! Jetzt, da wir ein Rezept und eine Modellspezifikation haben, müssen wir eine Möglichkeit finden, diese zusammen in einem Objekt zu bündeln, das zunächst die Daten vorverarbeitet (prep+bake im Hintergrund), das Modell auf den vorverarbeiteten Daten anpasst und auch potenzielle Nachbearbeitungsaktivitäten ermöglicht. Klingt das nicht beruhigend?🤩\n", "\n", "In Tidymodels wird dieses praktische Objekt [`workflow`](https://workflows.tidymodels.org/) genannt und enthält bequem alle Modellierungskomponenten! Das ist das, was wir in *Python* als *Pipelines* bezeichnen würden.\n", "\n", "Also, lass uns alles in einem Workflow bündeln!📦\n" ], "metadata": { "id": "G3zF_3DqviFJ" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Hold modelling components in a workflow\n", "lm_wf <- workflow() %>% \n", " add_recipe(lm_pumpkins_recipe) %>% \n", " add_model(lm_spec)\n", "\n", "# Print out the workflow\n", "lm_wf" ], "outputs": [], "metadata": { "id": "T3olroU3v-WX" } }, { "cell_type": "markdown", "source": [ "Obendrein kann ein Workflow auf ähnliche Weise angepasst/trainiert werden wie ein Modell.\n" ], "metadata": { "id": "zd1A5tgOwEPX" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Train the model\n", "lm_wf_fit <- lm_wf %>% \n", " fit(data = pumpkins_train)\n", "\n", "# Print the model coefficients learned \n", "lm_wf_fit" ], "outputs": [], "metadata": { "id": "NhJagFumwFHf" } }, { "cell_type": "markdown", "source": [ "Aus den Modellergebnissen können wir die während des Trainings gelernten Koeffizienten sehen. Sie repräsentieren die Koeffizienten der Linie der besten Anpassung, die uns den geringsten Gesamtfehler zwischen der tatsächlichen und der vorhergesagten Variablen liefert.\n", "\n", "#### Modellleistung mit dem Testdatensatz bewerten\n", "\n", "Es ist Zeit herauszufinden, wie das Modell abgeschnitten hat 📏! Wie machen wir das?\n", "\n", "Nachdem wir das Modell trainiert haben, können wir es verwenden, um Vorhersagen für den `test_set` mit `parsnip::predict()` zu treffen. Anschließend können wir diese Vorhersagen mit den tatsächlichen Label-Werten vergleichen, um zu bewerten, wie gut (oder nicht!) das Modell funktioniert.\n", "\n", "Beginnen wir damit, Vorhersagen für den Testdatensatz zu machen und die Spalten an den Testdatensatz anzufügen.\n" ], "metadata": { "id": "_4QkGtBTwItF" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make predictions for the test set\n", "predictions <- lm_wf_fit %>% \n", " predict(new_data = pumpkins_test)\n", "\n", "\n", "# Bind predictions to the test set\n", "lm_results <- pumpkins_test %>% \n", " select(c(package, price)) %>% \n", " bind_cols(predictions)\n", "\n", "\n", "# Print the first ten rows of the tibble\n", "lm_results %>% \n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "UFZzTG0gwTs9" } }, { "cell_type": "markdown", "source": [ "Ja, Sie haben gerade ein Modell trainiert und verwendet, um Vorhersagen zu treffen! 🔮 Ist es gut? Lassen Sie uns die Leistung des Modells bewerten!\n", "\n", "In Tidymodels machen wir das mit `yardstick::metrics()`! Für die lineare Regression konzentrieren wir uns auf die folgenden Metriken:\n", "\n", "- `Root Mean Square Error (RMSE)`: Die Quadratwurzel des [MSE](https://en.wikipedia.org/wiki/Mean_squared_error). Dies ergibt eine absolute Metrik in derselben Einheit wie das Label (in diesem Fall der Preis eines Kürbisses). Je kleiner der Wert, desto besser das Modell (vereinfacht gesagt repräsentiert es den durchschnittlichen Betrag, um den die Vorhersagen falsch sind!).\n", "\n", "- `Coefficient of Determination (üblicherweise bekannt als R-squared oder R2)`: Eine relative Metrik, bei der ein höherer Wert eine bessere Anpassung des Modells bedeutet. Im Wesentlichen repräsentiert diese Metrik, wie viel der Varianz zwischen vorhergesagten und tatsächlichen Label-Werten das Modell erklären kann.\n" ], "metadata": { "id": "0A5MjzM7wW9M" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Evaluate performance of linear regression\n", "metrics(data = lm_results,\n", " truth = price,\n", " estimate = .pred)" ], "outputs": [], "metadata": { "id": "reJ0UIhQwcEH" } }, { "cell_type": "markdown", "source": [ "Da geht die Modellleistung. Mal sehen, ob wir eine bessere Einschätzung bekommen, indem wir ein Streudiagramm der Pakete und Preise visualisieren und dann die Vorhersagen verwenden, um eine Linie der besten Anpassung darüber zu legen.\n", "\n", "Das bedeutet, dass wir den Testdatensatz vorbereiten und verarbeiten müssen, um die Paketspalte zu kodieren und diese dann mit den Vorhersagen unseres Modells zu verbinden.\n" ], "metadata": { "id": "fdgjzjkBwfWt" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Encode package column\n", "package_encode <- lm_pumpkins_recipe %>% \n", " prep() %>% \n", " bake(new_data = pumpkins_test) %>% \n", " select(package)\n", "\n", "\n", "# Bind encoded package column to the results\n", "lm_results <- lm_results %>% \n", " bind_cols(package_encode %>% \n", " rename(package_integer = package)) %>% \n", " relocate(package_integer, .after = package)\n", "\n", "\n", "# Print new results data frame\n", "lm_results %>% \n", " slice_head(n = 5)\n", "\n", "\n", "# Make a scatter plot\n", "lm_results %>% \n", " ggplot(mapping = aes(x = package_integer, y = price)) +\n", " geom_point(size = 1.6) +\n", " # Overlay a line of best fit\n", " geom_line(aes(y = .pred), color = \"orange\", size = 1.2) +\n", " xlab(\"package\")\n", " \n" ], "outputs": [], "metadata": { "id": "R0nw719lwkHE" } }, { "cell_type": "markdown", "source": [ "Wie Sie sehen können, generalisiert das lineare Regressionsmodell die Beziehung zwischen einem Paket und seinem entsprechenden Preis nicht besonders gut.\n", "\n", "🎃 Herzlichen Glückwunsch, Sie haben gerade ein Modell erstellt, das helfen kann, den Preis einiger Kürbissorten vorherzusagen. Ihr Kürbisfeld für die Feiertage wird wunderschön sein. Aber Sie können wahrscheinlich ein besseres Modell erstellen!\n", "\n", "## 5. Erstellen Sie ein polynomiales Regressionsmodell\n", "\n", "

\n", " \n", "

Infografik von Dasani Madipalli
\n", "\n", "\n", "\n" ], "metadata": { "id": "HOCqJXLTwtWI" } }, { "cell_type": "markdown", "source": [ "Manchmal haben unsere Daten keine lineare Beziehung, aber wir möchten trotzdem ein Ergebnis vorhersagen. Die polynomiale Regression kann uns helfen, Vorhersagen für komplexere nicht-lineare Beziehungen zu treffen.\n", "\n", "Nehmen wir zum Beispiel die Beziehung zwischen Verpackung und Preis in unserem Kürbis-Datensatz. Während es manchmal eine lineare Beziehung zwischen Variablen gibt – je größer der Kürbis im Volumen, desto höher der Preis – können diese Beziehungen manchmal nicht als Ebene oder gerade Linie dargestellt werden.\n", "\n", "> ✅ Hier sind [einige weitere Beispiele](https://online.stat.psu.edu/stat501/lesson/9/9.8) für Daten, die polynomiale Regression verwenden könnten.\n", ">\n", "> Werfen Sie einen weiteren Blick auf die Beziehung zwischen Sorte und Preis im vorherigen Diagramm. Sieht dieser Streudiagramm so aus, als sollte er unbedingt mit einer geraden Linie analysiert werden? Vielleicht nicht. In diesem Fall können Sie polynomiale Regression ausprobieren.\n", ">\n", "> ✅ Polynome sind mathematische Ausdrücke, die aus einer oder mehreren Variablen und Koeffizienten bestehen können.\n", "\n", "#### Trainieren eines polynomialen Regressionsmodells mit dem Trainingssatz\n", "\n", "Die polynomiale Regression erstellt eine *gekrümmte Linie*, um nichtlineare Daten besser anzupassen.\n", "\n", "Schauen wir, ob ein polynomiales Modell besser darin ist, Vorhersagen zu treffen. Wir folgen einem ähnlichen Verfahren wie zuvor:\n", "\n", "- Erstellen Sie ein Rezept, das die Vorverarbeitungsschritte angibt, die an unseren Daten durchgeführt werden müssen, um sie für die Modellierung vorzubereiten, z. B.: Kodierung von Prädiktoren und Berechnung von Polynomen eines Grades *n*.\n", "\n", "- Erstellen Sie eine Modellspezifikation.\n", "\n", "- Bündeln Sie das Rezept und die Modellspezifikation in einen Workflow.\n", "\n", "- Erstellen Sie ein Modell, indem Sie den Workflow anpassen.\n", "\n", "- Bewerten Sie, wie gut das Modell auf den Testdaten abschneidet.\n", "\n", "Legen wir los!\n" ], "metadata": { "id": "VcEIpRV9wzYr" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Specify a recipe\r\n", "poly_pumpkins_recipe <-\r\n", " recipe(price ~ package, data = pumpkins_train) %>%\r\n", " step_integer(all_predictors(), zero_based = TRUE) %>% \r\n", " step_poly(all_predictors(), degree = 4)\r\n", "\r\n", "\r\n", "# Create a model specification\r\n", "poly_spec <- linear_reg() %>% \r\n", " set_engine(\"lm\") %>% \r\n", " set_mode(\"regression\")\r\n", "\r\n", "\r\n", "# Bundle recipe and model spec into a workflow\r\n", "poly_wf <- workflow() %>% \r\n", " add_recipe(poly_pumpkins_recipe) %>% \r\n", " add_model(poly_spec)\r\n", "\r\n", "\r\n", "# Create a model\r\n", "poly_wf_fit <- poly_wf %>% \r\n", " fit(data = pumpkins_train)\r\n", "\r\n", "\r\n", "# Print learned model coefficients\r\n", "poly_wf_fit\r\n", "\r\n", " " ], "outputs": [], "metadata": { "id": "63n_YyRXw3CC" } }, { "cell_type": "markdown", "source": [ "#### Modellleistung bewerten\n", "\n", "👏👏Du hast ein Polynommodell erstellt – lass uns Vorhersagen für den Testdatensatz machen!\n" ], "metadata": { "id": "-LHZtztSxDP0" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make price predictions on test data\r\n", "poly_results <- poly_wf_fit %>% predict(new_data = pumpkins_test) %>% \r\n", " bind_cols(pumpkins_test %>% select(c(package, price))) %>% \r\n", " relocate(.pred, .after = last_col())\r\n", "\r\n", "\r\n", "# Print the results\r\n", "poly_results %>% \r\n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "YUFpQ_dKxJGx" } }, { "cell_type": "markdown", "source": [ "Woo-hoo, lass uns bewerten, wie das Modell auf dem test_set mit `yardstick::metrics()` abgeschnitten hat.\n" ], "metadata": { "id": "qxdyj86bxNGZ" } }, { "cell_type": "code", "execution_count": null, "source": [ "metrics(data = poly_results, truth = price, estimate = .pred)" ], "outputs": [], "metadata": { "id": "8AW5ltkBxXDm" } }, { "cell_type": "markdown", "source": [ "🤩🤩 Viel bessere Leistung.\n", "\n", "Das `rmse` sank von etwa 7 auf etwa 3, was darauf hinweist, dass der Fehler zwischen dem tatsächlichen Preis und dem vorhergesagten Preis reduziert wurde. Man kann dies *grob* so interpretieren, dass falsche Vorhersagen im Durchschnitt um etwa 3 \\$ danebenliegen. Das `rsq` stieg von etwa 0,4 auf 0,8.\n", "\n", "Alle diese Metriken zeigen, dass das polynomiale Modell deutlich besser abschneidet als das lineare Modell. Gute Arbeit!\n", "\n", "Lass uns sehen, ob wir das visualisieren können!\n" ], "metadata": { "id": "6gLHNZDwxYaS" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Bind encoded package column to the results\r\n", "poly_results <- poly_results %>% \r\n", " bind_cols(package_encode %>% \r\n", " rename(package_integer = package)) %>% \r\n", " relocate(package_integer, .after = package)\r\n", "\r\n", "\r\n", "# Print new results data frame\r\n", "poly_results %>% \r\n", " slice_head(n = 5)\r\n", "\r\n", "\r\n", "# Make a scatter plot\r\n", "poly_results %>% \r\n", " ggplot(mapping = aes(x = package_integer, y = price)) +\r\n", " geom_point(size = 1.6) +\r\n", " # Overlay a line of best fit\r\n", " geom_line(aes(y = .pred), color = \"midnightblue\", size = 1.2) +\r\n", " xlab(\"package\")\r\n" ], "outputs": [], "metadata": { "id": "A83U16frxdF1" } }, { "cell_type": "markdown", "source": [ "Du kannst eine geschwungene Linie sehen, die besser zu deinen Daten passt! 🤩\n", "\n", "Du kannst dies noch glatter machen, indem du eine polynomiale Formel an `geom_smooth` übergibst, wie hier:\n" ], "metadata": { "id": "4U-7aHOVxlGU" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make a scatter plot\r\n", "poly_results %>% \r\n", " ggplot(mapping = aes(x = package_integer, y = price)) +\r\n", " geom_point(size = 1.6) +\r\n", " # Overlay a line of best fit\r\n", " geom_smooth(method = lm, formula = y ~ poly(x, degree = 4), color = \"midnightblue\", size = 1.2, se = FALSE) +\r\n", " xlab(\"package\")" ], "outputs": [], "metadata": { "id": "5vzNT0Uexm-w" } }, { "cell_type": "markdown", "source": [ "Ganz wie eine geschmeidige Kurve!🤩\n", "\n", "So erstellen Sie eine neue Vorhersage:\n" ], "metadata": { "id": "v9u-wwyLxq4G" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make a hypothetical data frame\r\n", "hypo_tibble <- tibble(package = \"bushel baskets\")\r\n", "\r\n", "# Make predictions using linear model\r\n", "lm_pred <- lm_wf_fit %>% predict(new_data = hypo_tibble)\r\n", "\r\n", "# Make predictions using polynomial model\r\n", "poly_pred <- poly_wf_fit %>% predict(new_data = hypo_tibble)\r\n", "\r\n", "# Return predictions in a list\r\n", "list(\"linear model prediction\" = lm_pred, \r\n", " \"polynomial model prediction\" = poly_pred)\r\n" ], "outputs": [], "metadata": { "id": "jRPSyfQGxuQv" } }, { "cell_type": "markdown", "source": [ "Die Vorhersage des `polynomial model` ergibt Sinn, wenn man die Streudiagramme von `price` und `package` betrachtet! Und falls dies ein besseres Modell als das vorherige ist, basierend auf denselben Daten, solltest du für diese teureren Kürbisse ein höheres Budget einplanen!\n", "\n", "🏆 Gut gemacht! Du hast in einer Lektion zwei Regressionsmodelle erstellt. Im letzten Abschnitt über Regression wirst du etwas über logistische Regression lernen, um Kategorien zu bestimmen.\n", "\n", "## **🚀Challenge**\n", "\n", "Teste mehrere verschiedene Variablen in diesem Notebook, um zu sehen, wie die Korrelation mit der Modellgenauigkeit zusammenhängt.\n", "\n", "## [**Post-lecture quiz**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/14/)\n", "\n", "## **Review & Selbststudium**\n", "\n", "In dieser Lektion haben wir über Lineare Regression gelernt. Es gibt andere wichtige Arten der Regression. Lies über Stepwise-, Ridge-, Lasso- und Elasticnet-Techniken. Ein guter Kurs, um mehr darüber zu lernen, ist der [Stanford Statistical Learning course](https://online.stanford.edu/courses/sohs-ystatslearning-statistical-learning).\n", "\n", "Wenn du mehr darüber erfahren möchtest, wie du das großartige Tidymodels-Framework nutzen kannst, sieh dir bitte die folgenden Ressourcen an:\n", "\n", "- Tidymodels-Website: [Get started with Tidymodels](https://www.tidymodels.org/start/)\n", "\n", "- Max Kuhn und Julia Silge, [*Tidy Modeling with R*](https://www.tmwr.org/)*.*\n", "\n", "###### **DANK AN:**\n", "\n", "[Allison Horst](https://twitter.com/allison_horst?lang=en) für die Erstellung der großartigen Illustrationen, die R einladender und ansprechender machen. Weitere Illustrationen findest du in ihrer [Galerie](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n" ], "metadata": { "id": "8zOLOWqMxzk5" } }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**Haftungsausschluss**: \nDieses Dokument wurde mithilfe des KI-Übersetzungsdienstes [Co-op Translator](https://github.com/Azure/co-op-translator) übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Nutzung dieser Übersetzung entstehen.\n" ] } ] }