跳至主要内容

R 中的逻辑回归教程

全面了解逻辑回归:它与线性回归有何不同,如何在 R 中使用 glm() 拟合并评估这些模型等!
· 14分钟 阅读

使用 AI 探索

在线运行和编辑此教程中的代码

运行代码

逻辑回归是一种简单却强大的模型,用于预测二元结果。也就是判断某件事是否会发生。它属于监督式机器学习中的分类模型。

逻辑回归几乎应用于各行各业——营销、医疗健康、社会科学等——是每位数据科学家工具箱中的必备模型。

要充分利用本教程,您需要具备 R 的基础使用能力。了解相关模型类型(如线性回归)也会有所帮助。阅读 R 中的线性回归教程了解更多。

逻辑回归概览

假设您想预测今天是否会是晴天。可能的结果只有两个:“晴”或“非晴”。这个结果变量也称为“目标变量”或“因变量”。

有许多变量可能影响结果,比如“前一天的气温”“气压”等。这些影响变量称为特征、自变量或预测变量——这些术语含义相同。

其他示例包括:客户是否会购买您的产品、电子邮件是否为垃圾邮件、交易是否为欺诈、药物是否能治愈患者等。

逻辑回归如何工作?

逻辑回归在预测变量与目标变量之间找到尽可能好的拟合关系,从而预测目标变量属于某个已标注类别的概率。

线性回归试图找到一条最优直线,用特征来预测结果。它形成如下方程:

y_predictions = intercept + slope * features

并通过优化来寻找截距与斜率的最佳取值。

逻辑回归的思路类似,但它对“结果属于某一类别的概率”进行回归。它使用 S 型函数(逻辑分布的累积分布函数)来变换方程右侧。

y_predictions = logistic_cdf(intercept + slope * features)

同样,模型通过优化寻找截距和斜率的最佳取值。

由于逻辑回归的算法形式与线性回归非常相似,它属于“广义线性模型”家族。这也是逻辑回归名字里带“回归”的原因,尽管它本质上是分类模型。

下图中的 S 型函数呈现出 S 形曲线。它将实数输入映射到 0 到 1 之间(两端收缩:负值趋近 0,非常大的正值趋近 1)。此外,阈值是覆盖在这些概率之上的决策因素,用于将输出划分到不同的类别或类中。

image4.png

复杂概念最适合通过示例来理解,因此我们用一个类比来说明 LR 算法的工作方式。假设 LR 模型的任务是通过多个欺诈指示器(如用户位置、购买金额、IP 地址等)来识别欺诈交易。目标是确定某笔交易是否合法或欺诈——这就是目标变量。

模型会根据各预测变量对目标变量的影响分配权重,并将它们组合以计算标准化得分或欺诈概率。

数据集

我们将使用葡萄牙某银行机构通过电话开展的直销活动数据集。该活动旨在销售银行定期存款订阅,由变量 y(订阅或未订阅)表示。逻辑回归模型的目标是基于预测变量(即客户属性,如人口统计信息)来预测客户是否会购买订阅。

image1.png

该数据集以及许多其他有用数据集的数据字典可在 Datacamp 网站上找到。

变量

描述

详细信息

age

客户年龄

 

job

职业类型

类别型:"admin.","blue-collar","entrepreneur","housemaid","management","retired","self-employed","services","student","technician","unemployed","unknown"

marital

婚姻状况

类别型:"divorced","married","single","unknown";注意:"divorced" 包括离婚或丧偶

education

客户最高学历

类别型:"basic.4y","basic.6y","basic.9y","high.school","illiterate","professional.course","university.degree","unknown"

default

是否有违约贷款?

类别型:"no","yes","unknown"

housing

是否有住房贷款?

类别型:"no","yes","unknown"

loan

是否有个人贷款?

类别型:"no","yes","unknown"

contact

联系通信类型

类别型:"cellular","telephone"

month

最后一次联系的月份

类别型:"jan", "feb", "mar", ..., "nov", "dec"

day_of_week

最后一次联系的星期几

类别型:"mon","tue","wed","thu","fri"

campaign

该活动期间与客户联系的次数

数值型,包含最后一次联系

pdays

距离上一次在先前活动中联系客户的天数

数值型;999 表示此前未联系过客户

previous

在本次活动前对该客户进行过的联系次数

数值型

poutcome

上一次营销活动的结果

类别型:"failure","nonexistent","success"

emp.var.rate

就业变动率——季度指标

数值型

cons.price.idx

消费者物价指数——月度指标

数值型

cons.conf.idx

消费者信心指数——月度指标

数值型

euribor3m

3 个月期欧元同业拆借利率——日度指标

数值型

nr.employed

雇员人数——季度指标

数值型

y

客户是否订阅了定期存款?

二元:"yes","no"

逻辑回归工作流程

完整的机器学习流程见信息图 机器学习工作流程新手指南。这里我们聚焦数据准备和建模步骤,主要包括:

  • 将数据拆分为训练集与测试集
  • 拟合(训练)模型
  • 进行预测
  • 评估模型性能
  • 超参数调优

逻辑回归相关包

在 R 中,建模逻辑回归有两种常见工作流:base-R 与 tidymodels。

base-R 工作流更为简单,包含 glm() 和 summary() 等函数用于拟合模型并生成模型摘要。

tidymodels 工作流便于管理多个模型,并为不同模型类型提供一致接口。

本教程将采用 tidymodels 工作流。

可视化数据

通过调用 library() 函数导入 tidymodels 包。

数据集是带有欧洲风格格式的 CSV 文件(逗号作小数点,分号作分隔符)。我们将使用 readr 包的 read_csv2() 来读取。

将目标变量 y 转换为因子变量以便建模。

使用 ggplot() 函数绘制按 y 分组的各职业类型计数图。

library(readr)
library(tidymodels)

# Read the dataset and convert the target variable to a factor
bank_df <- read_csv2("bank-full.csv")
bank_df$y = as.factor(bank_df$y)

# Plot job occupation against the target variable
ggplot(bank_df, aes(job, fill = y)) +
    geom_bar() +
    coord_flip()

image5.png

划分数据

将数据集拆分为训练集(用于拟合模型)和测试集(用于评估模型),以确保训练出的模型能在未见过的数据上发挥作用。

可以使用 initial_split() 函数并通过 prop 参数指定训练集比例来完成数据集拆分。

# Split data into train and test
set.seed(421)
split <- initial_split(bank_df, prop = 0.8, strata = y)
train <- split %>% 
         training()
test <- split %>% 
        testing()

拟合与评估模型

要创建模型,先声明一个 logistic_reg() 模型。它需要 mixture 和 penalty 参数来控制正则化的程度。mixture 为 1 表示 lasso 模型,为 0 表示 ridge 回归,中间值也可取。penalty 参数表示正则化强度。

请注意,您需要向 mixture 和 penalty 传入 "double" 浮点数。

使用 set_engine() 设置“引擎”(用于执行计算的后端)。有多种选择:默认引擎为 "glm",执行经典的逻辑回归。统计学家常偏好此法,因为它会给出每个系数的 p 值,便于理解各系数的重要性。

这里我们将使用 "glmnet" 引擎。它因支持正则化而受到机器学习研究者的青睐,尤其在特征很多时能提升预测效果。(在 Python 中,scikit-learn 包默认在逻辑回归中包含一定的正则化。)

调用 fit() 方法在上一节创建的训练数据上训练模型。其第一个参数是公式。公式左侧使用目标变量(此处为 y),右侧可包含任意您想使用的特征。一个点表示“使用所有未写在公式左侧的变量”。关于公式语法的更多信息,请阅读 R 公式教程。

# Train a logistic regression model
model <- logistic_reg(mixture = double(1), penalty = double(1)) %>%
  set_engine("glmnet") %>%
  set_mode("classification") %>%
  fit(y ~ ., data = train)

# Model summary
tidy(model)

输出如下所示,其中 estimate 列表示各预测变量的系数。

# A tibble: 43 × 3
   term              estimate penalty
   <chr>                <dbl>   <dbl>
 1 (Intercept)      -2.59           0
 2 age              -0.000477       0
 3 jobblue-collar   -0.183          0
 4 jobentrepreneur  -0.206          0
 5 jobhousemaid     -0.270          0
 6 jobmanagement    -0.0190         0
 7 jobretired        0.360          0
 8 jobself-employed -0.101          0
 9 jobservices      -0.105          0
10 jobstudent        0.415          0
# ... with 33 more rows
# ℹ Use `print(n = ...)` to see more rows

进行预测

使用 predict() 函数在测试数据上进行预测。您可以选择预测类型。

  • type = "class" 返回每个观测最可能的目标值。此处将返回 "yes" 或 "no",取决于模型是否认为该客户可能订阅定期存款。
  • type = "prob" 返回每个观测的各目标值概率。此处会返回 "yes" 的概率和 "no" 的概率(对每个观测相加为 1)。
# Class Predictions
pred_class <- predict(model,
                      new_data = test,
                      type = "class")

# Class Probabilities
pred_proba <- predict(model,
                      new_data = test,
                      type = "prob")

使用 accuracy() 函数评估模型,其中 truth 参数为 y,estimate 参数为上一步的预测值。

results <- test %>%
           select(y) %>%
           bind_cols(pred_class, pred_proba)

accuracy(results, truth = y, estimate = .pred_class)

超参数调优

相比直接为 mixture 和 penalty(“超参数”)传入具体数值,您也可以通过调优来优化模型的预测能力。

思路是使用不同的超参数取值多次运行模型,观察哪一组能带来最佳预测表现。

  • 在 logistic_reg() 函数中,将 mixture 和 penalty 参数设为对 tune() 的调用。
  • 使用 grid_regular() 函数为 mixture 和 penalty 定义一个候选值网格。
  • workflow() 函数创建一个对象用于存储模型细节,便于多次运行。
  • 使用 select_best() 函数选择最佳模型。您可以从多种度量中选择“最佳”标准。此处我们使用“受试者工作特征曲线下面积”(ROC AUC)指标。
# Define the logistic regression model with penalty and mixture hyperparameters
log_reg <- logistic_reg(mixture = tune(), penalty = tune(), engine = "glmnet")

# Define the grid search for the hyperparameters
grid <- grid_regular(mixture(), penalty(), levels = c(mixture = 4, penalty = 3))

# Define the workflow for the model
log_reg_wf <- workflow() %>%
  add_model(log_reg) %>%
  add_formula(y ~ .)

# Define the resampling method for the grid search
folds <- vfold_cv(train, v = 5)

# Tune the hyperparameters using the grid search
log_reg_tuned <- tune_grid(
  log_reg_wf,
  resamples = folds,
  grid = grid,
  control = control_grid(save_pred = TRUE)
)

select_best(log_reg_tuned, metric = "roc_auc")
# A tibble: 1 × 3
       penalty mixture .config              
         <dbl>   <dbl> <chr>                
1 0.0000000001       0 Preprocessor1_Model01

更多评估指标

基于最佳超参数:

  1. 训练一个逻辑回归模型
  2. 用它在测试集上生成预测
  3. 使用真实值与预测结果创建混淆矩阵
# Fit the model using the optimal hyperparameters
log_reg_final <- logistic_reg(penalty = 0.0000000001, mixture = 0) %>%
                 set_engine("glmnet") %>%
                 set_mode("classification") %>%
                 fit(y~., data = train)

# Evaluate the model performance on the testing set
pred_class <- predict(log_reg_final,
                      new_data = test,
                      type = "class")
results <- test %>%
  select(y) %>%
  bind_cols(pred_class, pred_proba)

# Create confusion matrix
conf_mat(results, truth = y,
         estimate = .pred_class)
Truth
Prediction   no  yes
       no  7838  738
       yes  147  320

您可以使用 precision() 函数计算精确率(阳性预测值,即真阳性数占预测为阳性的比例)。

precision(results, truth = y,
          estimate = .pred_class)
# A tibble: 1 × 3
  .metric   .estimator .estimate
  <chr>     <chr>          <dbl>
1 precision binary         0.914

类似地,您可以使用 recall() 函数计算召回率(敏感度,即真阳性数占实际阳性的比例)。

recall(results, truth = y,
          estimate = .pred_class)
# A tibble: 1 × 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 recall  binary         0.982

让我们了解影响订阅购买决策的变量。在逻辑回归中,系数反映目标变量对各个预测变量的敏感程度。系数值越大,重要性越高。按系数绝对值从大到小排序,并仅展示绝对值大于 0.5 的系数。

coeff <- tidy(log_reg_final) %>% 
  arrange(desc(abs(estimate))) %>% 
  filter(abs(estimate) > 0.5)
# A tibble: 10 × 3
   term            estimate      penalty
   <chr>              <dbl>        <dbl>
 1 (Intercept)       -2.59  0.0000000001
 2 poutcomesuccess    2.08  0.0000000001
 3 monthmar           1.62  0.0000000001
 4 monthoct           1.08  0.0000000001
 5 monthsep           1.03  0.0000000001
 6 contactunknown    -1.01  0.0000000001
 7 monthdec           0.861 0.0000000001
 8 monthjan          -0.820 0.0000000001
 9 housingyes        -0.550 0.0000000001
10 monthnov          -0.517 0.0000000001

使用 ggplot() 函数绘制特征重要性图。

ggplot(coeff, aes(x = term, y = estimate, fill = term)) + geom_col() + coord_flip()

image2.png

更进一步

至此,我们已完成本教程的主要内容,演示了如何使用 tidymodels 包训练并评估逻辑回归模型,也介绍了如何解读模型结果并绘制如特征重要性之类的图表。

如果您想进一步学习如何使用 tidymodels 构建 AI 模型,请查看课程 Modeling with tidymodels in R。若想了解基于 base-R 的建模,请查看课程 Introduction to Regression in R、Intermediate Regression in R 和 Generalized Linear Models in R。

主题