You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
686 lines
29 KiB
686 lines
29 KiB
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Build logistic regression model - Lesson 4\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"#### **[Pre-lecture quiz](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n",
|
|
"\n",
|
|
"#### Introduction\n",
|
|
"\n",
|
|
"Dis na di last lesson for Regression, one of di basic *classic* ML techniques. We go look Logistic Regression. You fit use dis technique to find patterns wey go help predict two categories. Dis candy na chocolate or e no be? Dis sickness dey spread or e no dey spread? Dis customer go choose dis product or e no go choose am?\n",
|
|
"\n",
|
|
"For dis lesson, you go learn:\n",
|
|
"\n",
|
|
"- Techniques for logistic regression\n",
|
|
"\n",
|
|
"✅ Make your understanding strong for how dis regression dey work for dis [Learn module](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)\n",
|
|
"\n",
|
|
"## Prerequisite\n",
|
|
"\n",
|
|
"Since we don work with di pumpkin data, we don sabi am well well to know say e get one binary category wey we fit work with: `Color`.\n",
|
|
"\n",
|
|
"Make we build logistic regression model to predict, based on some variables, *wetin be di color wey pumpkin go likely be* (orange 🎃 or white 👻).\n",
|
|
"\n",
|
|
"> Why we dey talk about binary classification for lesson wey dey group under regression? Na just because e dey easy to talk am like dat, as logistic regression na [classification method](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), even though e dey based on linear regression. You go learn other ways to classify data for di next lesson group.\n",
|
|
"\n",
|
|
"For dis lesson, we go need di following packages:\n",
|
|
"\n",
|
|
"- `tidyverse`: Di [tidyverse](https://www.tidyverse.org/) na [collection of R packages](https://www.tidyverse.org/packages) wey dey make data science fast, easy and fun!\n",
|
|
"\n",
|
|
"- `tidymodels`: Di [tidymodels](https://www.tidymodels.org/) framework na [collection of packages](https://www.tidymodels.org/packages/) for modeling and machine learning.\n",
|
|
"\n",
|
|
"- `janitor`: Di [janitor package](https://github.com/sfirke/janitor) dey provide simple tools to check and clean dirty data.\n",
|
|
"\n",
|
|
"- `ggbeeswarm`: Di [ggbeeswarm package](https://github.com/eclarke/ggbeeswarm) dey provide methods to create beeswarm-style plots using ggplot2.\n",
|
|
"\n",
|
|
"You fit install dem like dis:\n",
|
|
"\n",
|
|
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n",
|
|
"\n",
|
|
"Or, di script wey dey below go check whether you get di packages wey you need for dis module and go install dem for you if dem no dey.\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": [
|
|
"## **Define di question**\n",
|
|
"\n",
|
|
"For wetin we wan do, we go tok am as binary: 'White' or 'Not White'. Di dataset get one 'striped' category but e no too plenty, so we no go use am. E go comot sef once we remove di null values from di dataset.\n",
|
|
"\n",
|
|
"> 🎃 Fun fact, sometimes we dey call white pumpkins 'ghost' pumpkins. Dem no too easy to carve, so dem no popular like di orange ones but dem dey look cool! So we fit also change di question to: 'Ghost' or 'Not Ghost'. 👻\n",
|
|
"\n",
|
|
"## **About logistic regression**\n",
|
|
"\n",
|
|
"Logistic regression no be di same as linear regression wey you don learn before. E get some important difference.\n",
|
|
"\n",
|
|
"#### **Binary classification**\n",
|
|
"\n",
|
|
"Logistic regression no dey do di same tin as linear regression. Logistic regression dey predict `binary category` (\"orange or not orange\") but linear regression fit predict `continual values`, like if you know where pumpkin come from and di time dem harvest am, *how much di price go increase*.\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"### Other classifications\n",
|
|
"\n",
|
|
"Logistic regression get other types, like multinomial and ordinal:\n",
|
|
"\n",
|
|
"- **Multinomial**, wey mean say e get more than one category - \"Orange, White, and Striped\".\n",
|
|
"\n",
|
|
"- **Ordinal**, wey mean say e get ordered categories, useful if we wan arrange di outcomes logically, like di pumpkins wey we fit arrange by size (mini, sm, med, lg, xl, xxl).\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"#### **Variables NO need to correlate**\n",
|
|
"\n",
|
|
"You remember how linear regression dey work better when variables dey correlate? Logistic regression no need dat one - di variables no need align. Dis one dey work well for dis data wey no get strong correlations.\n",
|
|
"\n",
|
|
"#### **You need plenty clean data**\n",
|
|
"\n",
|
|
"Logistic regression go give better result if you use plenty data; our small dataset no too good for dis task, so make you remember dat one.\n",
|
|
"\n",
|
|
"✅ Think about di kind data wey go work well for logistic regression\n",
|
|
"\n",
|
|
"## Exercise - tidy di data\n",
|
|
"\n",
|
|
"First, clean di data small, remove null values and choose only some columns:\n",
|
|
"\n",
|
|
"1. Add di following code:\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": [
|
|
"You fit always look ya new dataframe small, if you use [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html) function like dis:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"vscode": {
|
|
"languageId": "r"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"pumpkins_select %>% \n",
|
|
" glimpse()\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Make we confirm say na true true binary classification problem we go dey do:\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": [
|
|
"### Visualization - categorical plot\n",
|
|
"By now you don load di pumpkin data again and clean am so e go fit keep dataset wey get some variables, including Color. Make we use ggplot library take visualize di dataframe for di notebook.\n",
|
|
"\n",
|
|
"Di ggplot library get some beta ways to show your data. For example, you fit compare how di data dey spread for each Variety and Color inside one categorical plot.\n",
|
|
"\n",
|
|
"1. Create dis kain plot by using di geombar function, use our pumpkin data, and specify color mapping for each pumpkin category (orange or white):\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": [
|
|
"As you dey look di data, you fit see how di Color data take connect wit Variety.\n",
|
|
"\n",
|
|
"✅ Wit dis kind categorical plot, wetin be some kind interesting tori wey you fit imagine?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Data pre-processing: feature encoding\n",
|
|
"\n",
|
|
"Our pumpkin dataset get string values for all di columns. To work wit categorical data dey easy for humans, but e no dey easy for machines. Machine learning algorithms dey work well wit numbers. Na why encoding na very important step for di data pre-processing phase, because e go help us turn categorical data to numerical data, without losing any information. Better encoding fit help us build better model.\n",
|
|
"\n",
|
|
"For feature encoding, we get two main types of encoders:\n",
|
|
"\n",
|
|
"1. **Ordinal encoder**: E dey work well for ordinal variables, wey be categorical variables wey their data get logical order, like di `item_size` column for our dataset. E go create mapping wey go make each category get number, wey be di order of di category for di column.\n",
|
|
"\n",
|
|
"2. **Categorical encoder**: E dey work well for nominal variables, wey be categorical variables wey their data no get logical order, like all di features wey no be `item_size` for our dataset. E dey use one-hot encoding, wey mean say each category go get binary column: di encoded variable go equal 1 if di pumpkin belong to dat Variety, and 0 if e no belong.\n",
|
|
"\n",
|
|
"Tidymodels get one correct package: [recipes](https://recipes.tidymodels.org/) - na package for preprocessing data. We go define one `recipe` wey go specify say all predictor columns go dey encoded into set of integers, `prep` am to calculate di quantities and statistics wey di operations need, and finally `bake` am to apply di calculations to new data.\n",
|
|
"\n",
|
|
"> Normally, recipes dey usually dey used as preprocessor for modelling, where e dey define wetin steps dem go apply to one dataset to make am ready for modelling. For dat case, **e dey highly recommend** say make you use `workflow()` instead of to dey manually estimate recipe using prep and bake. We go see all dis one soon.\n",
|
|
">\n",
|
|
"> But for now, we dey use recipes + prep + bake to specify wetin steps dem go apply to one dataset to make am ready for data analysis, and then extract di preprocessed data wit di steps wey dem don apply.\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": [
|
|
"✅ Wetin be di advantage of using ordinal encoder for di Item Size column?\n",
|
|
"\n",
|
|
"### Check how di variables take relate\n",
|
|
"\n",
|
|
"Now we don process our data finish, we fit check how di features and di label take relate so we go fit sabi how di model go take predict di label based on di features. Di best way to do dis kain analysis na to plot di data. \n",
|
|
"We go use di ggplot geom_boxplot_ function again, to show how Item Size, Variety and Color take relate for one categorical plot. To make di plot better, we go use di encoded Item Size column and di unencoded Variety column.\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": [
|
|
"#### Use swarm plot\n",
|
|
"\n",
|
|
"Because say Color na binary category (White or Not), e need 'one [special way](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf) to take show am for visualization'.\n",
|
|
"\n",
|
|
"Make we try `swarm plot` to take show how color dey spread with respect to item_size.\n",
|
|
"\n",
|
|
"We go use [ggbeeswarm package](https://github.com/eclarke/ggbeeswarm) wey dey give methods to create beeswarm-style plots with ggplot2. Beeswarm plots na one way to plot points wey for normal suppose overlap, but e go arrange dem make dem dey side by side.\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": [
|
|
"Now wey we don sabi how di binary categories of color and di bigger group of sizes dey relate, make we check logistic regression to fit know di likely color of one pumpkin.\n",
|
|
"\n",
|
|
"## Build your model\n",
|
|
"\n",
|
|
"Choose di variables wey you wan use for di classification model and divide di data into training and test sets. [rsample](https://rsample.tidymodels.org/), one package for Tidymodels, dey provide infrastructure wey go make data splitting and resampling easy:\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": [
|
|
"🙌 We don ready to train model by fit di training features to di training label (color).\n",
|
|
"\n",
|
|
"We go start by create one recipe wey go show di preprocessing steps wey we go do for our data to make am ready for modelling, like: encode categorical variables into set of integers. Just like `baked_pumpkins`, we go create `pumpkins_recipe` but we no go `prep` and `bake` am because e go dey inside workflow, wey you go see for di next few steps.\n",
|
|
"\n",
|
|
"Plenty ways dey to specify logistic regression model for Tidymodels. Check `?logistic_reg()` For now, we go specify logistic regression model through di default `stats::glm()` engine.\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": [
|
|
"Now wey we don get recipe and model specification, we need find way to join dem together inside one object wey go first preprocess di data (prep+bake for back), fit di model on top di preprocessed data, and still allow for post-processing if e dey necessary.\n",
|
|
"\n",
|
|
"For Tidymodels, dis easy-to-use object na [`workflow`](https://workflows.tidymodels.org/) and e dey carry all your modeling components well well.\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": [
|
|
"Afta dem don *specify* workflow, dem fit use [`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html) function take `train` model. Di workflow go estimate recipe and go preprocess di data before e train, so we no go need do am manually wit prep and 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": [
|
|
"The model print out dey show the coefficients wey e learn during training.\n",
|
|
"\n",
|
|
"Now we don train the model with the training data, we fit use am predict for the test data using [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). Make we start by using the model to predict labels for our test set and the probabilities for each label. If the probability pass 0.5, the predict class na `WHITE`, but if e no reach, na `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": [
|
|
"Very nice! Dis one dey give more insight on how logistic regression dey work.\n",
|
|
"\n",
|
|
"### Beta understanding wit confusion matrix\n",
|
|
"\n",
|
|
"To dey compare each prediction wit di \"ground truth\" actual value no too make sense if you wan sabi how well di model dey predict. Luckily, Tidymodels get some beta tools for hand: [`yardstick`](https://yardstick.tidymodels.org/) - na package wey dem dey use measure how well models dey perform wit performance metrics.\n",
|
|
"\n",
|
|
"One performance metric wey dem dey use for classification problems na [`confusion matrix`](https://wikipedia.org/wiki/Confusion_matrix). Confusion matrix dey show how well classification model dey perform. E dey show how many examples for each class di model classify correct. For our case, e go show you how many orange pumpkins dem classify as orange and how many white pumpkins dem classify as white; di confusion matrix go also show you how many dem classify for di **wrong** categories.\n",
|
|
"\n",
|
|
"Di [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) function from yardstick dey calculate dis cross-tabulation of observed and predicted classes.\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": [
|
|
"Make we interpret di confusion matrix. Our model dey try classify pumpkins between two binary categories, category `white` and category `not-white`.\n",
|
|
"\n",
|
|
"- If di model talk say pumpkin na white and e really belong to category 'white', we go call am `true positive`, e dey show for di top left number.\n",
|
|
"\n",
|
|
"- If di model talk say pumpkin no be white and e really belong to category 'white', we go call am `false negative`, e dey show for di bottom left number.\n",
|
|
"\n",
|
|
"- If di model talk say pumpkin na white and e really belong to category 'not-white', we go call am `false positive`, e dey show for di top right number.\n",
|
|
"\n",
|
|
"- If di model talk say pumpkin no be white and e really belong to category 'not-white', we go call am `true negative`, e dey show for di bottom right number.\n",
|
|
"\n",
|
|
"| Truth |\n",
|
|
"|:-----:|\n",
|
|
"\n",
|
|
"\n",
|
|
"| | | |\n",
|
|
"|---------------|--------|-------|\n",
|
|
"| **Predicted** | WHITE | ORANGE |\n",
|
|
"| WHITE | TP | FP |\n",
|
|
"| ORANGE | FN | TN |\n",
|
|
"\n",
|
|
"As you fit guess, e better make we get plenty true positives and true negatives, and make di false positives and false negatives small, because e mean say di model dey perform well.\n",
|
|
"\n",
|
|
"Di confusion matrix dey useful because e dey help us calculate other metrics wey fit help us check how well di classification model dey perform. Make we look some of dem:\n",
|
|
"\n",
|
|
"🎓 Precision: `TP/(TP + FP)` e mean di proportion of di things wey di model predict as positive wey really be positive. Dem dey also call am [positive predictive value](https://en.wikipedia.org/wiki/Positive_predictive_value \"Positive predictive value\").\n",
|
|
"\n",
|
|
"🎓 Recall: `TP/(TP + FN)` e mean di proportion of di positive results out of di number of samples wey really be positive. Dem dey also call am `sensitivity`.\n",
|
|
"\n",
|
|
"🎓 Specificity: `TN/(TN + FP)` e mean di proportion of di negative results out of di number of samples wey really be negative.\n",
|
|
"\n",
|
|
"🎓 Accuracy: `TP + TN/(TP + TN + FP + FN)` Na di percentage of di labels wey di model predict correct for di samples.\n",
|
|
"\n",
|
|
"🎓 F Measure: Na di weighted average of di precision and recall, di best na 1 and di worst na 0.\n",
|
|
"\n",
|
|
"Make we calculate all dis metrics!\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": [
|
|
"## Show di ROC curve for dis model\n",
|
|
"\n",
|
|
"Make we do one more visualization to see wetin dem dey call [`ROC curve`](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 curves dey often dey use to take see how classifier dey perform in terms of true positives versus false positives. ROC curves dey usually show `True Positive Rate`/Sensitivity for Y axis, and `False Positive Rate`/1-Specificity for X axis. So, how steep di curve be and di space wey dey between di middle line and di curve dey important: you go wan make di curve quick quick go up and pass di line. For our case, false positives dey first, but di line later go up and pass di line well.\n",
|
|
"\n",
|
|
"Last last, make we use `yardstick::roc_auc()` to calculate di real Area Under di Curve. One way wey you fit take understand AUC na as di chance say di model go rank one random positive example higher pass one random negative example.\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": [
|
|
"Di result na around `0.975`. Since AUC dey range from 0 to 1, you go wan make di score big, because model wey dey 100% correct for im predictions go get AUC of 1; for dis case, di model *dey very good*.\n",
|
|
"\n",
|
|
"For future lessons on classifications, you go learn how you fit take improve your model scores (like how to handle imbalanced data for dis kind case).\n",
|
|
"\n",
|
|
"## 🚀Challenge\n",
|
|
"\n",
|
|
"Plenty tins dey to learn about logistic regression! But di best way to sabi am na to try am. Find one dataset wey fit work for dis kind analysis and build one model with am. Wetin you learn? Tip: try [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) to find interesting datasets.\n",
|
|
"\n",
|
|
"## Review & Self Study\n",
|
|
"\n",
|
|
"Read di first few pages of [dis paper from Stanford](https://web.stanford.edu/~jurafsky/slp3/5.pdf) wey talk about some practical ways to use logistic regression. Think about di tasks wey go fit one type of regression pass di other one wey we don study so far. Which one go work best?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**Disclaimer**: \nDis dokyument don use AI translation service [Co-op Translator](https://github.com/Azure/co-op-translator) do di translation. Even as we dey try make am accurate, abeg make you sabi say machine translation fit get mistake or no dey correct well. Di original dokyument wey dey for im native language na di main source wey you go trust. For important information, e better make professional human translation dey use. We no go fit take blame for any misunderstanding or wrong interpretation wey fit happen because you use dis translation.\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\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-11-18T19:15:11+00:00",
|
|
"source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb",
|
|
"language_code": "pcm"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 1
|
|
} |