2. 建立逻辑回归模型
在此,我们建立一个二项逻辑回归模型来预测一名乘客是否能在泰坦尼克号灾难中幸存下来。加载包:
library(mlr) library(tidyverse)
注:R
中警告信息:自 2019 年 7 月以来,mlr
处于“仅维护”模式。未来的开发将只在 mlr3
中进行(https://mlr3.mlr-org.com)。由于对 mlr3
的关注,在 mlr
中可能会有未捕获的 bug,请考虑切换。
2.1 加载泰坦尼克号数据集
该数据集在 titanic
包中,有 891 个实例和 12 个变量。
install.packages("titanic")#安装包 data(titanic_train, package = "titanic")#加载数据 titanicTib <- as_tibble(titanic_train)#转换为 tibble 格式 titanicTib #查看数据 # A tibble: 891 x 12 # PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin # <int> <int> <int> <chr> <chr> <dbl> <int> <int> <chr> <dbl> <chr> # 1 1 0 3 Braund, Mr.~ male 22 1 0 A/5 21~ 7.25 "" # 2 2 1 1 Cumings, Mr~ fema~ 38 1 0 PC 175~ 71.3 "C85" # 3 3 1 3 Heikkinen, ~ fema~ 26 0 0 STON/O~ 7.92 "" # 4 4 1 1 Futrelle, M~ fema~ 35 1 0 113803 53.1 "C12~ # 5 5 0 3 Allen, Mr. ~ male 35 0 0 373450 8.05 "" # 6 6 0 3 Moran, Mr. ~ male NA 0 0 330877 8.46 "" # 7 7 0 1 McCarthy, M~ male 54 0 0 17463 51.9 "E46" # 8 8 0 3 Palsson, Ma~ male 2 3 1 349909 21.1 "" # 9 9 1 3 Johnson, Mr~ fema~ 27 0 2 347742 11.1 "" #10 10 1 2 Nasser, Mrs~ fema~ 14 1 0 237736 30.1 "" # ... with 881 more rows, and 1 more variable: Embarked <chr>
此 tibble
包含以下变量:
- PassengerId: 每个乘客都有一个独特的任意数字。
- Survived: 表示是否存活的整数(1=存活,0=死亡)。
- Pclass: 乘客是住在一等舱,二等舱还是三等舱。
- Name: 乘客姓名的字符向量。
- Sex: 包含“男性”和“女性”的字符向量。
- Age: 乘客的年龄。
- SibSp: 乘客船上兄弟姐妹和配偶的总数。
- Parch: 乘客船上父母和孩子的总数。
- Ticket: 乘客票号的字符向量。
- Fare: 乘客买票的金额。
- Cabin: 乘客座舱号的字符向量。
- Embarked: 乘客出发港口的字符向量。
2.2 充分利用数据:特征工程和特征选择
通常我们不会使用整个数据集来进行建模。在正式建模之前,首先要对数据进行清理,包括将数据转换为正确类型、纠正错误和删除不相关数据等步骤。对于泰坦尼克号数据集,主要有以下三个处理步骤:
- 将
Survived, Sex, Pclass
三个变量转换为因子(factor)。(converting to factors) - 添加新的变量
FamSize
为SibSp
和Parch
两个变量之和。(feature engineering) - 选择认为对模型有预测价值的变量。(feature selection)
2.2.1 转换为因子 (converting to factors)
每个变量都应该被视为一个因子,因为它们代表了在整个数据集中重复出现的不同情况之间的离散差异。
2.2.2 特征工程(feature engineering)
这是一项极其重要的机器学习任务,它是对数据集中的变量进行修改,以提高它们的预测值。特征工程有两种方式:
- Feature extraction.
- Feature creation.
Feature extraction
是将预测信息保存在变量中,但以一种无用的格式保存。例如,假设有一个变量,它包含事件发生的年、月、日和时间。一天中的时间有重要的预测价值,而年、月、日则没有。为了让这个变量在模型中有用,只需要提取一天中的时间信息作为一个新变量。
Feature creation
是将现有的变量组合起来创建新变量。例如,添加新的变量 FamSize
为 SibSp
和 Parch
两个变量之和。
2.2.3 特征选择(feature selection)
这是另一个非常重要的机器学习任务:保留增加预测价值的变量,删除没有增加预测价值的变量。
泰坦尼克号数据清理代码如下:
fctrs <- c("Survived", "Sex", "Pclass")#定义将要转换为因子的变量的向量 titanicClean <- titanicTib %>% mutate_at(.vars = fctrs, .funs = factor) %>% #将变量转换为因子 mutate(FamSize = SibSp + Parch) %>% #定义新的变量 select(Survived, Pclass, Sex, Age, Fare, FamSize)#选择可以增加预测价值的变量 titanicClean#查看处理后的数据集 # A tibble: 891 x 6 # Survived Pclass Sex Age Fare FamSize # <fct> <fct> <fct> <dbl> <dbl> <int> # 1 0 3 male 22 7.25 1 # 2 1 1 female 38 71.3 1 # 3 1 3 female 26 7.92 0 # 4 1 1 female 35 53.1 1 # 5 0 3 male 35 8.05 0 # 6 0 3 male NA 8.46 0 # 7 0 1 male 54 51.9 0 # 8 0 3 male 2 21.1 4 # 9 1 3 female 27 11.1 2 #10 1 2 female 14 30.1 1 # ... with 881 more rows
2.3 绘制数据
首先,使用 gather()
函数将数据转化为 untidy
形式:每个预测变量名保存在一列中,它们的值保存在另一列中。这样就可以使用 ggplot2
作分面图把不同的变量画在一起。
titanicUntidy <- gather(titanicClean, key = "Variable", value = "Value", -Survived) titanicUntidy # A tibble: 4,455 x 3 # Survived Variable Value # <fct> <chr> <chr> # 1 0 Pclass 3 # 2 1 Pclass 1 # 3 1 Pclass 3 # 4 1 Pclass 1 # 5 0 Pclass 3 # 6 0 Pclass 3 # 7 0 Pclass 1 # 8 0 Pclass 3 # 9 1 Pclass 3 #10 1 Pclass 2 # ... with 4,445 more rows
titanicUntidy %>% filter(Variable != "Pclass" & Variable != "Sex") %>% #过滤掉Pclass和Sex两个变量 ggplot(aes(Survived, as.numeric(Value))) + facet_wrap(~ Variable, scales = "free_y") + #绘制不同变量分面图 geom_violin(draw_quantiles = c(0.25, 0.5, 0.75)) + #小提琴形状并画出分位数线 theme_bw()
Fig 9. 三个变量分面图
小提琴图显示沿 y 轴的数据密度。每把小提琴上的线代表第 1 个四分位数、中位数和第 3 个四分位数(从最低到最高)。
接下来绘制关于 Pclass
和 Sex
两个变量的图,分别查看不同舱位和性别所占幸存人数的比例。
Fig 10. 两个变量比例图
2.4 训练模型
现在我们已经清理了数据,接下来用 mlr
包创建任务、learner 和模型(使用 "classif.logreg" 来作为逻辑回归的 learner)。
titanicTask <- makeClassifTask(data = titanicClean, target = "Survived")#创建任务 logReg <- makeLearner("classif.logreg")#指定learner logRegModel <- train(logReg, titanicTask)#训练模型 #Error in checkLearnerBeforeTrain(task, learner, weights) : # Task 'titanicClean' has missing values in 'Age', but learner 'classif.logreg' does not support that!
此时报错,查看年龄数据可知存在缺失值,而逻辑回归无法处理这样的数据。
2.5 处理缺失值
处理缺失数据有两种方法:
- 简单地从分析中排除缺少数据的情况。
- 应用一种机制来填补空白。
当缺失值的情况与完整情况的比例非常小时,第一种选择可能是有效的。在这种情况下,省略带有缺失值的实例不太可能对模型的性能产生很大的影响。
第二种选择是使用一些算法来估计那些缺失值,用这些估计值替换 NA,并使用这个新数据集来训练模型。估计缺失值的方法有很多种,例如均值插补,也就是取缺失数据变量的均值,用它来替换缺失值。
在本例中,由于年龄缺失值较多,故使用第二种处理缺失值的方法。
imp <- impute(titanicClean, cols = list(Age = imputeMean()))#均值插补 sum(is.na(titanicClean$Age))#原数据集年龄变量缺失值个数 #[1] 177 sum(is.na(imp$data$Age))#新数据集年龄变量缺失值个数 #[1] 0
2.6 重新训练模型
titanicTask <- makeClassifTask(data = imp$data, target = "Survived")#定义任务 logRegModel <- train(logReg, titanicTask)#训练模型
使用经过处理缺失值的新数据来训练模型。