{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_1-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "c18d3bd0bd8ae3878597e89dcd1fa5c1", "translation_date": "2025-09-03T19:43:03+00:00", "source_file": "2-Regression/1-Tools/solution/R/lesson_1-R.ipynb", "language_code": "zh" } }, "cells": [ { "cell_type": "markdown", "source": [], "metadata": { "id": "YJUHCXqK57yz" } }, { "cell_type": "markdown", "source": [ "## 回归简介 - 第1课\n", "\n", "#### 放到实际情境中\n", "\n", "✅ 回归方法有很多种,选择哪一种取决于你想要得到的答案。如果你想预测某个年龄段的人可能的身高,你会使用 `线性回归`,因为你在寻找一个**数值结果**。如果你想知道某种菜肴是否应该被归类为素食,你是在寻找一个**类别分配**,因此你会使用 `逻辑回归`。稍后你会学习更多关于逻辑回归的内容。试着思考一些你可以从数据中提出的问题,以及哪种方法更适合这些问题。\n", "\n", "在本节中,你将使用一个[关于糖尿病的小型数据集](https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html)。假设你想测试一种针对糖尿病患者的治疗方法。机器学习模型可能会帮助你根据变量的组合确定哪些患者对治疗的反应更好。即使是一个非常基础的回归模型,在可视化时也可能显示出一些关于变量的信息,这些信息可以帮助你组织理论上的临床试验。\n", "\n", "话不多说,让我们开始这项任务吧!\n", "\n", "

\n", " \n", "

由 @allison_horst 创作的艺术作品
\n", "\n", "\n" ], "metadata": { "id": "LWNNzfqd6feZ" } }, { "cell_type": "markdown", "source": [ "## 1. 加载工具集\n", "\n", "在这个任务中,我们需要以下软件包:\n", "\n", "- `tidyverse`: [tidyverse](https://www.tidyverse.org/) 是一个[由 R 软件包组成的集合](https://www.tidyverse.org/packages),旨在让数据科学更快速、更简单、更有趣!\n", "\n", "- `tidymodels`: [tidymodels](https://www.tidymodels.org/) 框架是一个[由软件包组成的集合](https://www.tidymodels.org/packages/),用于建模和机器学习。\n", "\n", "你可以通过以下命令安装它们:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\"))`\n", "\n", "下面的脚本会检查你是否拥有完成本模块所需的软件包,并在缺少某些软件包时为你安装它们。\n" ], "metadata": { "id": "FIo2YhO26wI9" } }, { "cell_type": "code", "execution_count": 2, "source": [ "suppressWarnings(if(!require(\"pacman\")) install.packages(\"pacman\"))\n", "pacman::p_load(tidyverse, tidymodels)" ], "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "Loading required package: pacman\n", "\n" ] } ], "metadata": { "id": "cIA9fz9v7Dss", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "2df7073b-86b2-4b32-cb86-0da605a0dc11" } }, { "cell_type": "markdown", "source": [ "现在,让我们加载这些超棒的包并使它们在我们当前的 R 会话中可用。(这只是为了说明,`pacman::p_load()` 已经为您完成了这一操作)\n" ], "metadata": { "id": "gpO_P_6f9WUG" } }, { "cell_type": "code", "execution_count": null, "source": [ "# load the core Tidyverse packages\r\n", "library(tidyverse)\r\n", "\r\n", "# load the core Tidymodels packages\r\n", "library(tidymodels)\r\n" ], "outputs": [], "metadata": { "id": "NLMycgG-9ezO" } }, { "cell_type": "markdown", "source": [ "## 2. 糖尿病数据集\n", "\n", "在本次练习中,我们将通过对糖尿病数据集进行预测来展示我们的回归技能。[糖尿病数据集](https://www4.stat.ncsu.edu/~boos/var.select/diabetes.rwrite1.txt) 包含 `442 个样本`,数据包括 10 个预测特征变量:`年龄`、`性别`、`身体质量指数`、`平均血压`以及 `六项血清测量值`,还有一个结果变量 `y`:衡量基线后一年疾病进展的定量指标。\n", "\n", "|观察数量|442|\n", "|----------------------|:---|\n", "|预测变量数量|前 10 列为数值型预测变量|\n", "|结果/目标|第 11 列为基线后一年疾病进展的定量指标|\n", "|预测变量信息|- 年龄(以年为单位)\n", "||- 性别\n", "||- bmi 身体质量指数\n", "||- bp 平均血压\n", "||- s1 tc,总血清胆固醇\n", "||- s2 ldl,低密度脂蛋白\n", "||- s3 hdl,高密度脂蛋白\n", "||- s4 tch,总胆固醇 / HDL\n", "||- s5 ltg,可能是血清甘油三酯水平的对数值\n", "||- s6 glu,血糖水平|\n", "\n", "> 🎓 记住,这是监督学习,我们需要一个名为 'y' 的目标变量。\n", "\n", "在使用 R 操作数据之前,您需要将数据导入 R 的内存,或者建立一个 R 可以用来远程访问数据的连接。\n", "\n", "> [readr](https://readr.tidyverse.org/) 包是 Tidyverse 的一部分,它提供了一种快速且友好的方式将矩形数据读入 R。\n", "\n", "现在,让我们加载来源 URL 提供的糖尿病数据集:\n", "\n", "此外,我们将使用 `glimpse()` 对数据进行基本检查,并使用 `slice()` 显示前 5 行。\n", "\n", "在继续之前,让我们介绍一个您在 R 代码中经常会遇到的东西 🥁🥁:管道操作符 `%>%`\n", "\n", "管道操作符 (`%>%`) 按逻辑顺序执行操作,将一个对象传递到函数或表达式中。您可以将管道操作符理解为代码中的“然后”。\n" ], "metadata": { "id": "KM6iXLH996Cl" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Import the data set\r\n", "diabetes <- read_table2(file = \"https://www4.stat.ncsu.edu/~boos/var.select/diabetes.rwrite1.txt\")\r\n", "\r\n", "\r\n", "# Get a glimpse and dimensions of the data\r\n", "glimpse(diabetes)\r\n", "\r\n", "\r\n", "# Select the first 5 rows of the data\r\n", "diabetes %>% \r\n", " slice(1:5)" ], "outputs": [], "metadata": { "id": "Z1geAMhM-bSP" } }, { "cell_type": "markdown", "source": [ "`glimpse()` 命令显示,这个数据集有 442 行和 11 列,所有列的数据类型均为 `double`。\n", "\n", "
\n", "\n", "> `glimpse()` 和 `slice()` 是 [`dplyr`](https://dplyr.tidyverse.org/) 包中的函数。Dplyr 是 Tidyverse 的一部分,它是一种数据操作的语法,提供了一组一致的动词,帮助解决最常见的数据处理问题。\n", "\n", "
\n", "\n", "现在我们已经有了数据,接下来让我们聚焦于一个特征(`bmi`),作为本次练习的目标。为此,我们需要选择所需的列。那么,我们该如何操作呢?\n", "\n", "[`dplyr::select()`](https://dplyr.tidyverse.org/reference/select.html) 函数允许我们在数据框中*选择*(并可选地重命名)列。\n" ], "metadata": { "id": "UwjVT1Hz-c3Z" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Select predictor feature `bmi` and outcome `y`\r\n", "diabetes_select <- diabetes %>% \r\n", " select(c(bmi, y))\r\n", "\r\n", "# Print the first 5 rows\r\n", "diabetes_select %>% \r\n", " slice(1:10)" ], "outputs": [], "metadata": { "id": "RDY1oAKI-m80" } }, { "cell_type": "markdown", "source": [ "## 3. 训练和测试数据\n", "\n", "在监督学习中,通常的做法是将数据*分割*成两个子集:一个(通常较大的)用于训练模型的集合,以及一个较小的“保留”集合,用于查看模型的表现如何。\n", "\n", "现在我们已经准备好了数据,可以看看机器是否能够帮助我们在这个数据集中找到一个合理的分割方式。我们可以使用 [rsample](https://tidymodels.github.io/rsample/) 包,它是 Tidymodels 框架的一部分,用来创建一个包含数据分割信息的对象,然后使用另外两个 rsample 函数提取生成的训练集和测试集:\n" ], "metadata": { "id": "SDk668xK-tc3" } }, { "cell_type": "code", "execution_count": null, "source": [ "set.seed(2056)\r\n", "# Split 67% of the data for training and the rest for tesing\r\n", "diabetes_split <- diabetes_select %>% \r\n", " initial_split(prop = 0.67)\r\n", "\r\n", "# Extract the resulting train and test sets\r\n", "diabetes_train <- training(diabetes_split)\r\n", "diabetes_test <- testing(diabetes_split)\r\n", "\r\n", "# Print the first 3 rows of the training set\r\n", "diabetes_train %>% \r\n", " slice(1:10)" ], "outputs": [], "metadata": { "id": "EqtHx129-1h-" } }, { "cell_type": "markdown", "source": [ "## 4. 使用Tidymodels训练线性回归模型\n", "\n", "现在我们可以开始训练模型了!\n", "\n", "在Tidymodels中,你可以通过`parsnip()`指定模型,主要涉及以下三个概念:\n", "\n", "- 模型**类型**区分了不同的模型,例如线性回归、逻辑回归、决策树模型等。\n", "\n", "- 模型**模式**包括常见选项如回归和分类;某些模型类型支持这两种模式,而有些仅支持其中一种。\n", "\n", "- 模型**引擎**是用于拟合模型的计算工具。通常这些是R包,例如 **`\"lm\"`** 或 **`\"ranger\"`**。\n", "\n", "这些建模信息会被捕获到一个模型规范中,所以让我们来构建一个吧!\n" ], "metadata": { "id": "sBOS-XhB-6v7" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Build a linear model specification\r\n", "lm_spec <- \r\n", " # Type\r\n", " linear_reg() %>% \r\n", " # Engine\r\n", " set_engine(\"lm\") %>% \r\n", " # Mode\r\n", " set_mode(\"regression\")\r\n", "\r\n", "\r\n", "# Print the model specification\r\n", "lm_spec" ], "outputs": [], "metadata": { "id": "20OwEw20--t3" } }, { "cell_type": "markdown", "source": [ "在模型被*指定*之后,可以使用 [`fit()`](https://parsnip.tidymodels.org/reference/fit.html) 函数对模型进行`估计`或`训练`,通常使用公式和一些数据。\n", "\n", "`y ~ .` 表示我们将拟合 `y` 作为预测值/目标,由所有预测变量/特征解释,即 `.`(在这个例子中,我们只有一个预测变量:`bmi`)。\n" ], "metadata": { "id": "_oDHs89k_CJj" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Build a linear model specification\r\n", "lm_spec <- linear_reg() %>% \r\n", " set_engine(\"lm\") %>%\r\n", " set_mode(\"regression\")\r\n", "\r\n", "\r\n", "# Train a linear regression model\r\n", "lm_mod <- lm_spec %>% \r\n", " fit(y ~ ., data = diabetes_train)\r\n", "\r\n", "# Print the model\r\n", "lm_mod" ], "outputs": [], "metadata": { "id": "YlsHqd-q_GJQ" } }, { "cell_type": "markdown", "source": [ "从模型输出中,我们可以看到训练过程中学习到的系数。它们表示最佳拟合线的系数,该线使实际变量与预测变量之间的总体误差最小。\n", "
\n", "\n", "## 5. 在测试集上进行预测\n", "\n", "现在我们已经训练了一个模型,可以使用它通过 [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html) 来预测测试数据集中的疾病进展 y。这将用于绘制数据组之间的分界线。\n" ], "metadata": { "id": "kGZ22RQj_Olu" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make predictions for the test set\r\n", "predictions <- lm_mod %>% \r\n", " predict(new_data = diabetes_test)\r\n", "\r\n", "# Print out some of the predictions\r\n", "predictions %>% \r\n", " slice(1:5)" ], "outputs": [], "metadata": { "id": "nXHbY7M2_aao" } }, { "cell_type": "markdown", "source": [ "哇哦!💃🕺 我们刚刚训练了一个模型,并用它进行了预测!\n", "\n", "在进行预测时,tidymodels 的惯例是始终生成一个带有标准化列名的 tibble/数据框结果。这使得将原始数据和预测结果结合在一个可用的格式中变得非常简单,方便后续操作,例如绘图。\n", "\n", "`dplyr::bind_cols()` 可以高效地将多个数据框按列绑定在一起。\n" ], "metadata": { "id": "R_JstwUY_bIs" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Combine the predictions and the original test set\r\n", "results <- diabetes_test %>% \r\n", " bind_cols(predictions)\r\n", "\r\n", "\r\n", "results %>% \r\n", " slice(1:5)" ], "outputs": [], "metadata": { "id": "RybsMJR7_iI8" } }, { "cell_type": "markdown", "source": [ "## 6. 绘制模型结果\n", "\n", "现在是时候用视觉化方式来看结果了 📈。我们将创建一个散点图,展示测试集中的所有 `y` 和 `bmi` 值,然后使用预测结果绘制一条线,将模型的数据分组之间连接起来,放在最合适的位置。\n", "\n", "R 有多种绘图系统,但 `ggplot2` 是其中最优雅且最灵活的一个。它允许你通过**组合独立组件**来构建图表。\n" ], "metadata": { "id": "XJbYbMZW_n_s" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Set a theme for the plot\r\n", "theme_set(theme_light())\r\n", "# Create a scatter plot\r\n", "results %>% \r\n", " ggplot(aes(x = bmi)) +\r\n", " # Add a scatter plot\r\n", " geom_point(aes(y = y), size = 1.6) +\r\n", " # Add a line plot\r\n", " geom_line(aes(y = .pred), color = \"blue\", size = 1.5)" ], "outputs": [], "metadata": { "id": "R9tYp3VW_sTn" } }, { "cell_type": "markdown", "source": [ "✅ 想一想这里发生了什么。一条直线穿过了许多小数据点,但它究竟在做什么呢?你能看出如何利用这条直线来预测一个新的、未见过的数据点应该如何与图表的 y 轴相关联吗?试着用语言描述这个模型的实际用途。\n", "\n", "恭喜你!你已经构建了第一个线性回归模型,用它进行了预测,并在图表中展示了结果!\n" ], "metadata": { "id": "zrPtHIxx_tNI" } }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**免责声明**: \n本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。\n" ] } ] }