{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Xây dựng mô hình hồi quy logistic - Bài học 4\n", "\n", "![Đồ họa thông tin hồi quy logistic vs. hồi quy tuyến tính](../../../../../../2-Regression/4-Logistic/images/linear-vs-logistic.png)\n", "\n", "#### **[Câu hỏi trước bài học](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n", "\n", "#### Giới thiệu\n", "\n", "Trong bài học cuối cùng về Hồi quy, một trong những kỹ thuật *cổ điển* cơ bản của ML, chúng ta sẽ tìm hiểu về Hồi quy Logistic. Bạn sẽ sử dụng kỹ thuật này để khám phá các mẫu nhằm dự đoán các danh mục nhị phân. Đây có phải là kẹo sô-cô-la hay không? Bệnh này có lây hay không? Khách hàng này có chọn sản phẩm này hay không?\n", "\n", "Trong bài học này, bạn sẽ học:\n", "\n", "- Các kỹ thuật cho hồi quy logistic\n", "\n", "✅ Nâng cao hiểu biết của bạn về cách làm việc với loại hồi quy này trong [module học này](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)\n", "\n", "## Điều kiện tiên quyết\n", "\n", "Sau khi làm việc với dữ liệu bí ngô, chúng ta đã đủ quen thuộc để nhận ra rằng có một danh mục nhị phân mà chúng ta có thể làm việc: `Color`.\n", "\n", "Hãy xây dựng một mô hình hồi quy logistic để dự đoán, dựa trên một số biến, *màu sắc của một quả bí ngô có khả năng là gì* (cam 🎃 hoặc trắng 👻).\n", "\n", "> Tại sao chúng ta lại nói về phân loại nhị phân trong một bài học nhóm về hồi quy? Chỉ vì sự tiện lợi về ngôn ngữ, vì hồi quy logistic thực chất là [một phương pháp phân loại](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), mặc dù dựa trên tuyến tính. Tìm hiểu về các cách khác để phân loại dữ liệu trong nhóm bài học tiếp theo.\n", "\n", "Để thực hiện bài học này, chúng ta sẽ cần các gói sau:\n", "\n", "- `tidyverse`: [tidyverse](https://www.tidyverse.org/) là một [bộ sưu tập các gói R](https://www.tidyverse.org/packages) được thiết kế để làm cho khoa học dữ liệu nhanh hơn, dễ dàng hơn và thú vị hơn!\n", "\n", "- `tidymodels`: [tidymodels](https://www.tidymodels.org/) là một [bộ khung các gói](https://www.tidymodels.org/packages/) dành cho mô hình hóa và học máy.\n", "\n", "- `janitor`: [Gói janitor](https://github.com/sfirke/janitor) cung cấp các công cụ đơn giản để kiểm tra và làm sạch dữ liệu bẩn.\n", "\n", "- `ggbeeswarm`: [Gói ggbeeswarm](https://github.com/eclarke/ggbeeswarm) cung cấp các phương pháp để tạo biểu đồ kiểu beeswarm sử dụng ggplot2.\n", "\n", "Bạn có thể cài đặt chúng bằng lệnh:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n", "\n", "Ngoài ra, đoạn mã dưới đây sẽ kiểm tra xem bạn đã có các gói cần thiết để hoàn thành module này chưa và cài đặt chúng nếu chúng bị thiếu.\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": [ "## **Xác định câu hỏi**\n", "\n", "Đối với mục đích của chúng ta, chúng ta sẽ biểu diễn điều này dưới dạng nhị phân: 'Trắng' hoặc 'Không Trắng'. Trong tập dữ liệu của chúng ta cũng có một danh mục 'sọc', nhưng số lượng trường hợp rất ít, vì vậy chúng ta sẽ không sử dụng nó. Dù sao thì danh mục này cũng biến mất khi chúng ta loại bỏ các giá trị null khỏi tập dữ liệu.\n", "\n", "> 🎃 Một sự thật thú vị, đôi khi chúng ta gọi bí ngô trắng là bí ngô 'ma'. Chúng không dễ khắc lắm, vì vậy chúng không phổ biến như bí ngô màu cam, nhưng trông chúng rất ngầu! Vì vậy, chúng ta cũng có thể diễn đạt lại câu hỏi của mình thành: 'Ma' hoặc 'Không Ma'. 👻\n", "\n", "## **Về hồi quy logistic**\n", "\n", "Hồi quy logistic khác với hồi quy tuyến tính, mà bạn đã học trước đây, ở một vài điểm quan trọng.\n", "\n", "#### **Phân loại nhị phân**\n", "\n", "Hồi quy logistic không cung cấp các tính năng giống như hồi quy tuyến tính. Hồi quy logistic đưa ra dự đoán về một `danh mục nhị phân` (\"màu cam hoặc không màu cam\"), trong khi hồi quy tuyến tính có khả năng dự đoán `giá trị liên tục`, ví dụ như dựa trên nguồn gốc của một quả bí ngô và thời gian thu hoạch, *giá của nó sẽ tăng bao nhiêu*.\n", "\n", "![Đồ họa thông tin của Dasani Madipalli](../../../../../../2-Regression/4-Logistic/images/pumpkin-classifier.png)\n", "\n", "### Các loại phân loại khác\n", "\n", "Có các loại hồi quy logistic khác, bao gồm hồi quy đa thức và hồi quy thứ bậc:\n", "\n", "- **Đa thức**, liên quan đến việc có nhiều hơn một danh mục - \"Màu cam, Trắng và Sọc\".\n", "\n", "- **Thứ bậc**, liên quan đến các danh mục có thứ tự, hữu ích nếu chúng ta muốn sắp xếp các kết quả theo logic, như các quả bí ngô được sắp xếp theo một số kích thước hữu hạn (mini, nhỏ, vừa, lớn, rất lớn, cực lớn).\n", "\n", "![Hồi quy đa thức vs hồi quy thứ bậc](../../../../../../2-Regression/4-Logistic/images/multinomial-vs-ordinal.png)\n", "\n", "#### **Các biến KHÔNG CẦN phải tương quan**\n", "\n", "Bạn còn nhớ hồi quy tuyến tính hoạt động tốt hơn với các biến có tương quan cao không? Hồi quy logistic thì ngược lại - các biến không cần phải tương quan. Điều này phù hợp với tập dữ liệu của chúng ta, vốn có các mối tương quan khá yếu.\n", "\n", "#### **Bạn cần nhiều dữ liệu sạch**\n", "\n", "Hồi quy logistic sẽ cho kết quả chính xác hơn nếu bạn sử dụng nhiều dữ liệu hơn; tập dữ liệu nhỏ của chúng ta không phải là tối ưu cho nhiệm vụ này, vì vậy hãy ghi nhớ điều đó.\n", "\n", "✅ Hãy suy nghĩ về các loại dữ liệu phù hợp với hồi quy logistic\n", "\n", "## Bài tập - làm sạch dữ liệu\n", "\n", "Đầu tiên, làm sạch dữ liệu một chút, loại bỏ các giá trị null và chỉ chọn một số cột:\n", "\n", "1. Thêm đoạn mã sau:\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": [ "Bạn luôn có thể xem nhanh dataframe mới của mình bằng cách sử dụng hàm [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html) như dưới đây:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "pumpkins_select %>% \n", " glimpse()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Hãy xác nhận rằng chúng ta thực sự sẽ thực hiện một bài toán phân loại nhị phân:\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": [ "### Trực quan hóa - biểu đồ phân loại\n", "Đến thời điểm này, bạn đã tải lại dữ liệu về bí ngô và làm sạch nó để giữ lại một tập dữ liệu chứa một vài biến, bao gồm Màu sắc. Hãy trực quan hóa dataframe trong notebook bằng thư viện ggplot.\n", "\n", "Thư viện ggplot cung cấp một số cách thú vị để trực quan hóa dữ liệu của bạn. Ví dụ, bạn có thể so sánh phân bố dữ liệu cho từng Loại và Màu sắc trong một biểu đồ phân loại.\n", "\n", "1. Tạo biểu đồ như vậy bằng cách sử dụng hàm geombar, sử dụng dữ liệu bí ngô của chúng ta, và chỉ định ánh xạ màu cho từng loại bí ngô (màu cam hoặc màu trắng):\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": [ "Bằng cách quan sát dữ liệu, bạn có thể thấy cách dữ liệu Màu sắc liên quan đến Loại.\n", "\n", "✅ Dựa trên biểu đồ phân loại này, bạn có thể hình dung ra những khám phá thú vị nào?\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Xử lý dữ liệu: mã hóa đặc trưng\n", "\n", "Bộ dữ liệu pumpkins của chúng ta chứa các giá trị dạng chuỗi cho tất cả các cột. Làm việc với dữ liệu phân loại rất trực quan đối với con người nhưng không phải đối với máy móc. Các thuật toán học máy hoạt động tốt với dữ liệu dạng số. Đó là lý do tại sao mã hóa là một bước rất quan trọng trong giai đoạn xử lý dữ liệu, vì nó cho phép chúng ta chuyển đổi dữ liệu phân loại thành dữ liệu dạng số mà không làm mất thông tin. Mã hóa tốt sẽ giúp xây dựng một mô hình tốt.\n", "\n", "Đối với mã hóa đặc trưng, có hai loại mã hóa chính:\n", "\n", "1. Bộ mã hóa thứ tự (Ordinal encoder): phù hợp với các biến thứ tự, là các biến phân loại mà dữ liệu của chúng tuân theo một thứ tự logic, như cột `item_size` trong bộ dữ liệu của chúng ta. Nó tạo ra một ánh xạ sao cho mỗi danh mục được biểu diễn bằng một con số, con số này là thứ tự của danh mục trong cột.\n", "\n", "2. Bộ mã hóa phân loại (Categorical encoder): phù hợp với các biến danh nghĩa, là các biến phân loại mà dữ liệu của chúng không tuân theo một thứ tự logic, như tất cả các đặc trưng khác ngoài `item_size` trong bộ dữ liệu của chúng ta. Đây là một dạng mã hóa one-hot, nghĩa là mỗi danh mục được biểu diễn bằng một cột nhị phân: biến được mã hóa sẽ bằng 1 nếu quả bí thuộc về loại đó và bằng 0 nếu không.\n", "\n", "Tidymodels cung cấp một gói rất tiện lợi khác: [recipes](https://recipes.tidymodels.org/) - một gói dùng để xử lý dữ liệu. Chúng ta sẽ định nghĩa một `recipe` để chỉ định rằng tất cả các cột dự đoán nên được mã hóa thành một tập hợp các số nguyên, `prep` để ước tính các số lượng và thống kê cần thiết cho bất kỳ thao tác nào, và cuối cùng `bake` để áp dụng các tính toán cho dữ liệu mới.\n", "\n", "> Thông thường, recipes thường được sử dụng như một bộ tiền xử lý cho việc mô hình hóa, nơi nó định nghĩa các bước cần được áp dụng cho một tập dữ liệu để chuẩn bị cho việc mô hình hóa. Trong trường hợp đó, **rất khuyến khích** bạn sử dụng `workflow()` thay vì tự ước tính một recipe bằng prep và bake. Chúng ta sẽ thấy tất cả điều này ngay sau đây.\n", ">\n", "> Tuy nhiên, hiện tại chúng ta đang sử dụng recipes + prep + bake để chỉ định các bước cần được áp dụng cho một tập dữ liệu nhằm chuẩn bị cho việc phân tích dữ liệu và sau đó trích xuất dữ liệu đã được xử lý với các bước đã áp dụng.\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": [ "✅ Những lợi ích của việc sử dụng bộ mã hóa thứ tự (ordinal encoder) cho cột Item Size là gì?\n", "\n", "### Phân tích mối quan hệ giữa các biến\n", "\n", "Bây giờ, sau khi đã tiền xử lý dữ liệu, chúng ta có thể phân tích mối quan hệ giữa các đặc trưng và nhãn để hiểu rõ hơn về khả năng dự đoán nhãn của mô hình dựa trên các đặc trưng. Cách tốt nhất để thực hiện loại phân tích này là vẽ biểu đồ dữ liệu. \n", "Chúng ta sẽ tiếp tục sử dụng hàm ggplot geom_boxplot_ để trực quan hóa mối quan hệ giữa Item Size, Variety và Color trong một biểu đồ phân loại. Để biểu diễn dữ liệu tốt hơn, chúng ta sẽ sử dụng cột Item Size đã được mã hóa và cột Variety chưa được mã hóa.\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": [ "#### Sử dụng biểu đồ swarm\n", "\n", "Vì Color là một danh mục nhị phân (Trắng hoặc Không), nó cần 'một [phương pháp chuyên biệt](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf) để trực quan hóa'.\n", "\n", "Hãy thử sử dụng `biểu đồ swarm` để hiển thị sự phân bố của màu sắc liên quan đến kích thước vật phẩm.\n", "\n", "Chúng ta sẽ sử dụng [gói ggbeeswarm](https://github.com/eclarke/ggbeeswarm), cung cấp các phương pháp để tạo biểu đồ kiểu beeswarm bằng ggplot2. Biểu đồ beeswarm là một cách để vẽ các điểm mà thông thường sẽ chồng lên nhau, sao cho chúng nằm cạnh nhau thay vì chồng lấp.\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": [ "Bây giờ chúng ta đã hiểu mối quan hệ giữa các danh mục nhị phân của màu sắc và nhóm lớn hơn của kích thước, hãy cùng khám phá hồi quy logistic để xác định màu sắc có khả năng của một quả bí ngô.\n", "\n", "## Xây dựng mô hình của bạn\n", "\n", "Chọn các biến bạn muốn sử dụng trong mô hình phân loại và chia dữ liệu thành tập huấn luyện và tập kiểm tra. [rsample](https://rsample.tidymodels.org/), một gói trong Tidymodels, cung cấp cơ sở hạ tầng để chia dữ liệu và lấy mẫu lại một cách hiệu quả:\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": [ "🙌 Chúng ta đã sẵn sàng huấn luyện một mô hình bằng cách khớp các đặc trưng huấn luyện với nhãn huấn luyện (màu sắc).\n", "\n", "Chúng ta sẽ bắt đầu bằng việc tạo một công thức (recipe) để chỉ định các bước tiền xử lý cần thực hiện trên dữ liệu nhằm chuẩn bị cho việc mô hình hóa, ví dụ: mã hóa các biến phân loại thành một tập hợp các số nguyên. Tương tự như `baked_pumpkins`, chúng ta tạo một `pumpkins_recipe` nhưng không `prep` và `bake` vì nó sẽ được tích hợp vào một quy trình làm việc (workflow), điều này sẽ được giải thích trong vài bước tiếp theo.\n", "\n", "Có khá nhiều cách để chỉ định một mô hình hồi quy logistic trong Tidymodels. Xem `?logistic_reg()`. Hiện tại, chúng ta sẽ chỉ định một mô hình hồi quy logistic thông qua engine mặc định `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": [ "Bây giờ chúng ta đã có một công thức và một mô tả mô hình, chúng ta cần tìm cách kết hợp chúng lại thành một đối tượng có thể thực hiện các nhiệm vụ sau: tiền xử lý dữ liệu (chuẩn bị + xử lý ngầm), huấn luyện mô hình trên dữ liệu đã được tiền xử lý, và cũng hỗ trợ các hoạt động hậu xử lý tiềm năng.\n", "\n", "Trong Tidymodels, đối tượng tiện lợi này được gọi là một [`workflow`](https://workflows.tidymodels.org/) và nó giúp bạn lưu trữ các thành phần mô hình một cách thuận tiện.\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": [ "Sau khi một quy trình làm việc được *xác định*, một mô hình có thể được `huấn luyện` bằng cách sử dụng hàm [`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html). Quy trình làm việc sẽ ước tính một công thức và tiền xử lý dữ liệu trước khi huấn luyện, vì vậy chúng ta sẽ không cần phải thực hiện thủ công bằng cách sử dụng prep và 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": [ "Mô hình hiển thị các hệ số đã học được trong quá trình huấn luyện.\n", "\n", "Bây giờ chúng ta đã huấn luyện mô hình bằng dữ liệu huấn luyện, chúng ta có thể thực hiện dự đoán trên dữ liệu kiểm tra bằng [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). Hãy bắt đầu bằng cách sử dụng mô hình để dự đoán nhãn cho tập kiểm tra và xác suất cho từng nhãn. Khi xác suất lớn hơn 0.5, lớp dự đoán là `WHITE`, ngược lại là `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": [ "Rất tuyệt! Điều này cung cấp thêm một số hiểu biết về cách hồi quy logistic hoạt động.\n", "\n", "### Hiểu rõ hơn thông qua ma trận nhầm lẫn\n", "\n", "So sánh từng dự đoán với giá trị thực tế \"ground truth\" tương ứng không phải là cách hiệu quả nhất để xác định mức độ chính xác của mô hình. May mắn thay, Tidymodels có một vài thủ thuật khác: [`yardstick`](https://yardstick.tidymodels.org/) - một gói dùng để đo lường hiệu quả của mô hình thông qua các chỉ số hiệu suất.\n", "\n", "Một chỉ số hiệu suất liên quan đến các vấn đề phân loại là [`ma trận nhầm lẫn`](https://wikipedia.org/wiki/Confusion_matrix). Ma trận nhầm lẫn mô tả mức độ hiệu quả của một mô hình phân loại. Ma trận nhầm lẫn liệt kê số lượng ví dụ trong mỗi lớp được mô hình phân loại chính xác. Trong trường hợp của chúng ta, nó sẽ cho bạn biết có bao nhiêu quả bí ngô màu cam được phân loại là màu cam và bao nhiêu quả bí ngô màu trắng được phân loại là màu trắng; ma trận nhầm lẫn cũng cho thấy có bao nhiêu quả bị phân loại vào các danh mục **sai**.\n", "\n", "Hàm [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) từ yardstick tính toán sự đối chiếu giữa các lớp quan sát và dự đoán.\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": [ "Hãy cùng phân tích ma trận nhầm lẫn. Mô hình của chúng ta được yêu cầu phân loại bí ngô thành hai danh mục nhị phân, danh mục `trắng` và danh mục `không trắng`.\n", "\n", "- Nếu mô hình của bạn dự đoán một quả bí ngô là trắng và thực tế nó thuộc danh mục 'trắng', chúng ta gọi đó là `đúng dương`, được biểu thị bằng số ở góc trên bên trái.\n", "\n", "- Nếu mô hình của bạn dự đoán một quả bí ngô là không trắng và thực tế nó thuộc danh mục 'trắng', chúng ta gọi đó là `sai âm`, được biểu thị bằng số ở góc dưới bên trái.\n", "\n", "- Nếu mô hình của bạn dự đoán một quả bí ngô là trắng và thực tế nó thuộc danh mục 'không trắng', chúng ta gọi đó là `sai dương`, được biểu thị bằng số ở góc trên bên phải.\n", "\n", "- Nếu mô hình của bạn dự đoán một quả bí ngô là không trắng và thực tế nó thuộc danh mục 'không trắng', chúng ta gọi đó là `đúng âm`, được biểu thị bằng số ở góc dưới bên phải.\n", "\n", "| Thực tế |\n", "|:-----:|\n", "\n", "\n", "| | | |\n", "|---------------|--------|-------|\n", "| **Dự đoán** | TRẮNG | CAM |\n", "| TRẮNG | TP | FP |\n", "| CAM | FN | TN |\n", "\n", "Như bạn có thể đoán, sẽ tốt hơn nếu có số lượng lớn các giá trị đúng dương và đúng âm, đồng thời giảm số lượng sai dương và sai âm, điều này cho thấy mô hình hoạt động tốt hơn.\n", "\n", "Ma trận nhầm lẫn rất hữu ích vì nó dẫn đến các chỉ số khác giúp chúng ta đánh giá hiệu quả của một mô hình phân loại tốt hơn. Hãy cùng tìm hiểu một số chỉ số này:\n", "\n", "🎓 Độ chính xác: `TP/(TP + FP)` được định nghĩa là tỷ lệ các dự đoán dương thực sự là dương. Còn được gọi là [giá trị dự đoán dương](https://en.wikipedia.org/wiki/Positive_predictive_value \"Positive predictive value\").\n", "\n", "🎓 Độ nhạy: `TP/(TP + FN)` được định nghĩa là tỷ lệ kết quả dương trên tổng số mẫu thực sự là dương. Còn được gọi là `độ nhạy cảm`.\n", "\n", "🎓 Độ đặc hiệu: `TN/(TN + FP)` được định nghĩa là tỷ lệ kết quả âm trên tổng số mẫu thực sự là âm.\n", "\n", "🎓 Độ chính xác tổng thể: `TP + TN/(TP + TN + FP + FN)` Tỷ lệ nhãn được dự đoán chính xác trên tổng số mẫu.\n", "\n", "🎓 F Measure: Trung bình trọng số của độ chính xác và độ nhạy, với giá trị tốt nhất là 1 và kém nhất là 0.\n", "\n", "Hãy cùng tính các chỉ số này!\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": [ "## Hiển thị đường cong ROC của mô hình này\n", "\n", "Hãy thực hiện một hình ảnh hóa nữa để xem cái gọi là [`đường cong 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": [ "Đường cong ROC thường được sử dụng để đánh giá đầu ra của một bộ phân loại dựa trên tỷ lệ dương tính thật so với dương tính giả. Đường cong ROC thường hiển thị `True Positive Rate`/Độ nhạy trên trục Y, và `False Positive Rate`/1-Đặc hiệu trên trục X. Do đó, độ dốc của đường cong và khoảng cách giữa đường trung điểm và đường cong rất quan trọng: bạn muốn một đường cong nhanh chóng đi lên và vượt qua đường trung điểm. Trong trường hợp của chúng ta, ban đầu có một số dương tính giả, sau đó đường cong đi lên và vượt qua đúng cách.\n", "\n", "Cuối cùng, hãy sử dụng `yardstick::roc_auc()` để tính toán Diện Tích Dưới Đường Cong thực tế. Một cách để diễn giải AUC là xác suất mà mô hình xếp hạng một ví dụ dương tính ngẫu nhiên cao hơn một ví dụ âm tính ngẫu nhiên.\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": [ "Kết quả là khoảng `0.975`. Vì AUC dao động từ 0 đến 1, bạn muốn có một điểm số cao, bởi vì một mô hình dự đoán chính xác 100% sẽ có AUC bằng 1; trong trường hợp này, mô hình *khá tốt*.\n", "\n", "Trong các bài học tương lai về phân loại, bạn sẽ học cách cải thiện điểm số của mô hình (chẳng hạn như xử lý dữ liệu không cân bằng trong trường hợp này).\n", "\n", "## 🚀Thử thách\n", "\n", "Có rất nhiều điều để khám phá về hồi quy logistic! Nhưng cách tốt nhất để học là thử nghiệm. Tìm một tập dữ liệu phù hợp với loại phân tích này và xây dựng một mô hình với nó. Bạn học được gì? mẹo: thử [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) để tìm các tập dữ liệu thú vị.\n", "\n", "## Ôn tập & Tự học\n", "\n", "Đọc vài trang đầu của [bài báo này từ Stanford](https://web.stanford.edu/~jurafsky/slp3/5.pdf) về một số ứng dụng thực tiễn của hồi quy logistic. Hãy suy nghĩ về các nhiệm vụ phù hợp hơn với từng loại hồi quy mà chúng ta đã học cho đến thời điểm này. Loại nào sẽ hoạt động tốt nhất?\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**Tuyên bố miễn trừ trách nhiệm**: \nTài liệu này đã được dịch bằng dịch vụ dịch thuật AI [Co-op Translator](https://github.com/Azure/co-op-translator). Mặc dù chúng tôi cố gắng đảm bảo độ chính xác, xin lưu ý rằng các bản dịch tự động có thể chứa lỗi hoặc sự không chính xác. Tài liệu gốc bằng ngôn ngữ bản địa nên được coi là nguồn tham khảo chính thức. Đối với các thông tin quan trọng, nên sử dụng dịch vụ dịch thuật chuyên nghiệp từ con người. Chúng tôi không chịu trách nhiệm cho bất kỳ sự hiểu lầm hoặc diễn giải sai nào phát sinh từ việc sử dụng bản dịch này.\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-06T13:38:14+00:00", "source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb", "language_code": "vi" } }, "nbformat": 4, "nbformat_minor": 1 }